turtletooth 04d8fd
#include "tiio_ffmpeg.h"
turtletooth 04d8fd
#include "../toonz/tapp.h"
turtletooth 04d8fd
#include "tsystem.h"
turtletooth 04d8fd
#include "tsound.h"
turtletooth 04d8fd
turtletooth 04d8fd
#include <qprocess></qprocess>
justburner 69bbaf
#include <qeventloop></qeventloop>
justburner 69bbaf
#include <qtimer></qtimer>
turtletooth 04d8fd
#include <qdir></qdir>
turtletooth 04d8fd
#include <qtgui qimage=""></qtgui>
Jeremy Bullock 3b0af2
#include <qregexp></qregexp>
turtletooth 04d8fd
#include "toonz/preferences.h"
turtletooth 04d8fd
#include "toonz/toonzfolders.h"
Jeremy Bullock 55b5db
#include "tmsgcore.h"
turtletooth 04d8fd
turtletooth 04d8fd
Ffmpeg::Ffmpeg() {
turtletooth 04d8fd
  m_ffmpegPath         = Preferences::instance()->getFfmpegPath();
shun-iwasawa 27b0cf
  m_ffmpegTimeout      = Preferences::instance()->getFfmpegTimeout() * 1000;
turtletooth 04d8fd
  std::string strPath  = m_ffmpegPath.toStdString();
turtletooth 04d8fd
  m_intermediateFormat = "png";
turtletooth 04d8fd
}
turtletooth 04d8fd
Ffmpeg::~Ffmpeg() {}
turtletooth 04d8fd
turtletooth 04d8fd
bool Ffmpeg::checkFfmpeg() {
turtletooth 04d8fd
  // check the user defined path in preferences first
turtletooth 04d8fd
  QString path = Preferences::instance()->getFfmpegPath() + "/ffmpeg";
turtletooth 04d8fd
#if defined(_WIN32)
turtletooth 04d8fd
  path = path + ".exe";
turtletooth 04d8fd
#endif
turtletooth 04d8fd
  if (TSystem::doesExistFileOrLevel(TFilePath(path))) return true;
turtletooth 04d8fd
turtletooth 04d8fd
  // check the OpenToonz root directory next
turtletooth 04d8fd
  path = QDir::currentPath() + "/ffmpeg";
turtletooth 04d8fd
#if defined(_WIN32)
turtletooth 04d8fd
  path = path + ".exe";
turtletooth 04d8fd
#endif
turtletooth 04d8fd
  if (TSystem::doesExistFileOrLevel(TFilePath(path))) {
shun-iwasawa 8fb291
    Preferences::instance()->setValue(ffmpegPath, QDir::currentPath());
turtletooth 04d8fd
    return true;
turtletooth 04d8fd
  }
turtletooth 04d8fd
turtletooth 04d8fd
  // give up
turtletooth 04d8fd
  return false;
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
bool Ffmpeg::checkFfprobe() {
turtletooth 04d8fd
  // check the user defined path in preferences first
turtletooth 04d8fd
  QString path = Preferences::instance()->getFfmpegPath() + "/ffprobe";
turtletooth 04d8fd
#if defined(_WIN32)
turtletooth 04d8fd
  path = path + ".exe";
turtletooth 04d8fd
#endif
turtletooth 04d8fd
  if (TSystem::doesExistFileOrLevel(TFilePath(path))) return true;
turtletooth 04d8fd
turtletooth 04d8fd
  // check the OpenToonz root directory next
turtletooth 04d8fd
  path = QDir::currentPath() + "/ffprobe";
turtletooth 04d8fd
#if defined(_WIN32)
turtletooth 04d8fd
  path = path + ".exe";
turtletooth 04d8fd
#endif
turtletooth 04d8fd
  if (TSystem::doesExistFileOrLevel(TFilePath(path))) {
shun-iwasawa 8fb291
    Preferences::instance()->setValue(ffmpegPath, QDir::currentPath());
turtletooth 04d8fd
    return true;
turtletooth 04d8fd
  }
turtletooth 04d8fd
turtletooth 04d8fd
  // give up
turtletooth 04d8fd
  return false;
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
bool Ffmpeg::checkFormat(std::string format) {
shun-iwasawa 27b0cf
  QString path = Preferences::instance()->getFfmpegPath() + "/ffmpeg";
turtletooth 04d8fd
#if defined(_WIN32)
shun-iwasawa 27b0cf
  path = path + ".exe";
turtletooth 04d8fd
#endif
shun-iwasawa 27b0cf
  QStringList args;
shun-iwasawa 27b0cf
  args << "-formats";
shun-iwasawa 27b0cf
  QProcess ffmpeg;
shun-iwasawa 27b0cf
  ffmpeg.start(path, args);
shun-iwasawa 27b0cf
  ffmpeg.waitForFinished();
shun-iwasawa 27b0cf
  QString results = ffmpeg.readAllStandardError();
shun-iwasawa 27b0cf
  results += ffmpeg.readAllStandardOutput();
shun-iwasawa 27b0cf
  ffmpeg.close();
shun-iwasawa 27b0cf
  std::string strResults = results.toStdString();
shun-iwasawa 27b0cf
  std::string::size_type n;
shun-iwasawa 27b0cf
  n = strResults.find(format);
shun-iwasawa 27b0cf
  if (n != std::string::npos)
shun-iwasawa 27b0cf
    return true;
shun-iwasawa 27b0cf
  else
shun-iwasawa 27b0cf
    return false;
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
TFilePath Ffmpeg::getFfmpegCache() {
turtletooth 04d8fd
  QString cacheRoot = ToonzFolder::getCacheRootFolder().getQString();
turtletooth 04d8fd
  if (!TSystem::doesExistFileOrLevel(TFilePath(cacheRoot + "/ffmpeg"))) {
turtletooth 04d8fd
    TSystem::mkDir(TFilePath(cacheRoot + "/ffmpeg"));
turtletooth 04d8fd
  }
turtletooth 04d8fd
  std::string ffmpegPath =
turtletooth 04d8fd
      TFilePath(cacheRoot + "/ffmpeg").getQString().toStdString();
turtletooth 04d8fd
  return TFilePath(cacheRoot + "/ffmpeg");
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
void Ffmpeg::setFrameRate(double fps) { m_frameRate = fps; }
turtletooth 04d8fd
turtletooth 04d8fd
void Ffmpeg::setPath(TFilePath path) { m_path = path; }
turtletooth 04d8fd
turtletooth 04d8fd
void Ffmpeg::createIntermediateImage(const TImageP &img, int frameIndex) {
Jeremy Bullock 3837a1
  m_frameCount++;
Jeremy Bullock 63a3d7
  if (m_frameNumberOffset == -1) m_frameNumberOffset = frameIndex - 1;
Jeremy Bullock edaab7
  QString tempPath = getFfmpegCache().getQString() + "//" +
Jeremy Bullock edaab7
                     QString::fromStdString(m_path.getName()) + "tempOut" +
Jeremy Bullock 63a3d7
                     QString::number(frameIndex - m_frameNumberOffset) + "." +
Jeremy Bullock 63a3d7
                     m_intermediateFormat;
turtletooth 04d8fd
  std::string saveStatus = "";
turtletooth 04d8fd
  TRasterImageP tempImage(img);
turtletooth 04d8fd
  TRasterImage *image = (TRasterImage *)tempImage->cloneImage();
turtletooth 04d8fd
turtletooth 04d8fd
  m_lx           = image->getRaster()->getLx();
turtletooth 04d8fd
  m_ly           = image->getRaster()->getLy();
turtletooth 04d8fd
  m_bpp          = image->getRaster()->getPixelSize();
turtletooth 04d8fd
  int totalBytes = m_lx * m_ly * m_bpp;
turtletooth 04d8fd
  image->getRaster()->yMirror();
turtletooth 04d8fd
turtletooth 04d8fd
  // lock raster to get data
turtletooth 04d8fd
  image->getRaster()->lock();
turtletooth 04d8fd
  void *buffin = image->getRaster()->getRawData();
turtletooth 04d8fd
  assert(buffin);
turtletooth 04d8fd
  void *buffer = malloc(totalBytes);
turtletooth 04d8fd
  memcpy(buffer, buffin, totalBytes);
turtletooth 04d8fd
turtletooth 04d8fd
  image->getRaster()->unlock();
turtletooth 04d8fd
turtletooth 04d8fd
  // create QImage save format
turtletooth 04d8fd
  QByteArray ba      = m_intermediateFormat.toUpper().toLatin1();
turtletooth 04d8fd
  const char *format = ba.data();
turtletooth 04d8fd
turtletooth 04d8fd
  QImage *qi = new QImage((uint8_t *)buffer, m_lx, m_ly, QImage::Format_ARGB32);
turtletooth 04d8fd
  qi->save(tempPath, format, -1);
turtletooth 04d8fd
  free(buffer);
turtletooth 04d8fd
  m_cleanUpList.push_back(tempPath);
Jeremy Bullock 3837a1
turtletooth 04d8fd
  delete qi;
turtletooth 04d8fd
  delete image;
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
void Ffmpeg::runFfmpeg(QStringList preIArgs, QStringList postIArgs,
turtletooth 04d8fd
                       bool includesInPath, bool includesOutPath,
turtletooth 04d8fd
                       bool overWriteFiles) {
Jeremy Bullock edaab7
  QString tempName = "//" + QString::fromStdString(m_path.getName()) +
Jeremy Bullock edaab7
                     "tempOut%d." + m_intermediateFormat;
Jeremy Bullock edaab7
  tempName = getFfmpegCache().getQString() + tempName;
turtletooth 04d8fd
turtletooth 04d8fd
  QStringList args;
turtletooth 04d8fd
  args = args + preIArgs;
turtletooth 04d8fd
  if (!includesInPath) {  // NOTE:  if including the in path, it needs to be in
turtletooth 04d8fd
                          // the preIArgs argument.
turtletooth 04d8fd
    args << "-i";
turtletooth 04d8fd
    args << tempName;
turtletooth 04d8fd
  }
turtletooth 04d8fd
  if (m_hasSoundTrack) args = args + m_audioArgs;
shun-iwasawa 8fb291
  args = args + postIArgs;
turtletooth 04d8fd
  if (overWriteFiles && !includesOutPath) {  // if includesOutPath is true, you
turtletooth 04d8fd
                                             // need to include the overwrite in
turtletooth 04d8fd
                                             // your postIArgs.
turtletooth 04d8fd
    args << "-y";
turtletooth 04d8fd
  }
turtletooth 04d8fd
  if (!includesOutPath) {
turtletooth 04d8fd
    args << m_path.getQString();
turtletooth 04d8fd
  }
turtletooth 04d8fd
turtletooth 04d8fd
  // write the file
turtletooth 04d8fd
  QProcess ffmpeg;
turtletooth 04d8fd
  ffmpeg.start(m_ffmpegPath + "/ffmpeg", args);
justburner 69bbaf
  if (waitFfmpeg(ffmpeg)) {
Jeremy Bullock 55b5db
    QString results = ffmpeg.readAllStandardError();
Jeremy Bullock 55b5db
    results += ffmpeg.readAllStandardOutput();
Jeremy Bullock 55b5db
    int exitCode = ffmpeg.exitCode();
Jeremy Bullock 55b5db
    std::string strResults = results.toStdString();
Jeremy Bullock 55b5db
  }
justburner 69bbaf
  ffmpeg.close();
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
QString Ffmpeg::runFfprobe(QStringList args) {
turtletooth 04d8fd
  QProcess ffmpeg;
turtletooth 04d8fd
  ffmpeg.start(m_ffmpegPath + "/ffprobe", args);
justburner 69bbaf
  if (!waitFfmpeg(ffmpeg)) {
justburner 69bbaf
    throw TImageException(m_path, "error accessing ffprobe.");
justburner 69bbaf
  }
turtletooth 04d8fd
  QString results = ffmpeg.readAllStandardError();
turtletooth 04d8fd
  results += ffmpeg.readAllStandardOutput();
turtletooth 04d8fd
  int exitCode = ffmpeg.exitCode();
turtletooth 04d8fd
  ffmpeg.close();
shun-iwasawa a1dbd7
  // If the url cannot be opened or recognized as a multimedia file, ffprobe
shun-iwasawa a1dbd7
  // returns a positive exit code.
shun-iwasawa a1dbd7
  if (exitCode > 0) throw TImageException(m_path, "error reading info.");
turtletooth 04d8fd
  std::string strResults = results.toStdString();
turtletooth 04d8fd
  return results;
turtletooth 04d8fd
}
turtletooth 04d8fd
justburner 69bbaf
bool Ffmpeg::waitFfmpeg(const QProcess &ffmpeg) {
justburner 69bbaf
  QEventLoop eloop;
justburner 69bbaf
  QTimer timer;
justburner 69bbaf
  timer.connect(&timer, &QTimer::timeout, &eloop, [&eloop] { eloop.exit(-2); });
justburner 69bbaf
  ffmpeg.connect(&ffmpeg, &QProcess::errorOccurred, &eloop,
justburner 69bbaf
                 [&eloop] { eloop.exit(-1); });
justburner 69bbaf
  ffmpeg.connect(&ffmpeg,
justburner 69bbaf
                 static_cast<void (qprocess::*)(int,="" qprocess::exitstatus)="">(</void>
justburner 69bbaf
                     &QProcess::finished),
justburner 69bbaf
                 &eloop, &QEventLoop::quit);
justburner 69bbaf
  timer.start(m_ffmpegTimeout);
justburner 69bbaf
justburner 69bbaf
  int exitCode = eloop.exec();
justburner 69bbaf
  if (exitCode == 0) return true;
justburner 69bbaf
  if (exitCode == -1) {
justburner 69bbaf
    DVGui::warning(
justburner 69bbaf
        QObject::tr("FFmpeg returned error-code: %1").arg(ffmpeg.exitCode()));
justburner 69bbaf
  }
justburner 69bbaf
  if (exitCode == -2) {
justburner 69bbaf
    DVGui::warning(
justburner 69bbaf
        QObject::tr("FFmpeg timed out.\n"
justburner 69bbaf
                    "Please check the file for errors.\n"
justburner 69bbaf
                    "If the file doesn't play or is incomplete, \n"
justburner 69bbaf
                    "Please try raising the FFmpeg timeout in Preferences."));
justburner 69bbaf
  }
justburner 69bbaf
  return false;
justburner 69bbaf
}
justburner 69bbaf
turtletooth 04d8fd
void Ffmpeg::saveSoundTrack(TSoundTrack *st) {
turtletooth 04d8fd
  m_sampleRate    = st->getSampleRate();
turtletooth 04d8fd
  m_channelCount  = st->getChannelCount();
turtletooth 04d8fd
  m_bitsPerSample = st->getBitPerSample();
turtletooth 04d8fd
  // LONG count = st->getSampleCount();
turtletooth 04d8fd
  int bufSize         = st->getSampleCount() * st->getSampleSize();
turtletooth 04d8fd
  const UCHAR *buffer = st->getRawData();
turtletooth 04d8fd
Jeremy Bullock edaab7
  m_audioPath = getFfmpegCache().getQString() + "//" +
Jeremy Bullock edaab7
                QString::fromStdString(m_path.getName()) + "tempOut.raw";
turtletooth 04d8fd
  m_audioFormat = "s" + QString::number(m_bitsPerSample);
turtletooth 04d8fd
  if (m_bitsPerSample > 8) m_audioFormat = m_audioFormat + "le";
shun-iwasawa 8fb291
  std::string strPath = m_audioPath.toStdString();
turtletooth 04d8fd
turtletooth 04d8fd
  QByteArray data;
turtletooth 04d8fd
  data.insert(0, (char *)buffer, bufSize);
turtletooth 04d8fd
turtletooth 04d8fd
  QFile file(m_audioPath);
turtletooth 04d8fd
  file.open(QIODevice::WriteOnly);
turtletooth 04d8fd
  file.write(data);
turtletooth 04d8fd
  file.close();
turtletooth 04d8fd
  m_hasSoundTrack = true;
turtletooth 04d8fd
turtletooth 04d8fd
  m_audioArgs << "-f";
turtletooth 04d8fd
  m_audioArgs << m_audioFormat;
turtletooth 04d8fd
  m_audioArgs << "-ar";
turtletooth 04d8fd
  m_audioArgs << QString::number(m_sampleRate);
turtletooth 04d8fd
  m_audioArgs << "-ac";
turtletooth 04d8fd
  m_audioArgs << QString::number(m_channelCount);
turtletooth 04d8fd
  m_audioArgs << "-i";
turtletooth 04d8fd
  m_audioArgs << m_audioPath;
turtletooth 04d8fd
turtletooth 04d8fd
  // add file to framesWritten for cleanup
turtletooth 04d8fd
  m_cleanUpList.push_back(m_audioPath);
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
bool Ffmpeg::checkFilesExist() {
turtletooth 04d8fd
  QString ffmpegCachePath = getFfmpegCache().getQString();
Jeremy Bullock 686e82
  QString tempPath = ffmpegCachePath + "//" + cleanPathSymbols() + "In0001." +
Jeremy Bullock 686e82
                     m_intermediateFormat;
turtletooth 04d8fd
  if (TSystem::doesExistFileOrLevel(TFilePath(tempPath))) {
turtletooth 04d8fd
    return true;
turtletooth 04d8fd
  } else
turtletooth 04d8fd
    return false;
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
ffmpegFileInfo Ffmpeg::getInfo() {
turtletooth 04d8fd
  QString ffmpegCachePath = getFfmpegCache().getQString();
Jeremy Bullock 686e82
  QString tempPath = ffmpegCachePath + "//" + cleanPathSymbols() + ".txt";
turtletooth 04d8fd
  if (QFile::exists(tempPath)) {
turtletooth 04d8fd
    QFile infoText(tempPath);
turtletooth 04d8fd
    infoText.open(QIODevice::ReadOnly);
turtletooth 04d8fd
    QByteArray ba = infoText.readAll();
turtletooth 04d8fd
    infoText.close();
turtletooth 04d8fd
    QString text = QString::fromStdString(ba.toStdString());
turtletooth 04d8fd
    m_lx         = text.split(" ")[0].toInt();
turtletooth 04d8fd
    m_ly         = text.split(" ")[1].toInt();
turtletooth 04d8fd
    m_frameRate  = text.split(" ")[2].toDouble();
turtletooth 04d8fd
    m_frameCount = text.split(" ")[3].toInt();
turtletooth 04d8fd
  } else {
turtletooth 04d8fd
    QFile infoText(tempPath);
turtletooth 04d8fd
    getSize();
turtletooth 04d8fd
    getFrameCount();
manongjohn f2da01
    getFrameRate();
turtletooth 04d8fd
    infoText.open(QIODevice::WriteOnly);
turtletooth 04d8fd
    std::string infoToWrite =
turtletooth 04d8fd
        std::to_string(m_lx) + " " + std::to_string(m_ly) + " " +
turtletooth 04d8fd
        std::to_string(m_frameRate) + " " + std::to_string(m_frameCount);
turtletooth 04d8fd
    int infoLength = infoToWrite.length();
turtletooth 04d8fd
    infoText.write(infoToWrite.c_str(), infoLength);
turtletooth 04d8fd
    infoText.close();
turtletooth 04d8fd
  }
turtletooth 04d8fd
  ffmpegFileInfo info;
turtletooth 04d8fd
  info.m_lx         = m_lx;
turtletooth 04d8fd
  info.m_ly         = m_ly;
turtletooth 04d8fd
  info.m_frameRate  = m_frameRate;
turtletooth 04d8fd
  info.m_frameCount = m_frameCount;
turtletooth 04d8fd
  return info;
turtletooth 04d8fd
}
turtletooth 04d8fd
TRasterImageP Ffmpeg::getImage(int frameIndex) {
turtletooth 04d8fd
  QString ffmpegCachePath = getFfmpegCache().getQString();
Jeremy Bullock 686e82
  QString tempPath        = ffmpegCachePath + "//" + cleanPathSymbols();
Jeremy Bullock 686e82
  std::string tmpPath     = tempPath.toStdString();
turtletooth 04d8fd
  // QString tempPath= m_path.getQString();
turtletooth 04d8fd
  QString number   = QString("%1").arg(frameIndex, 4, 10, QChar('0'));
turtletooth 04d8fd
  QString tempName = "In" + number + ".png";
turtletooth 04d8fd
  tempName         = tempPath + tempName;
turtletooth 04d8fd
turtletooth 04d8fd
  // for debugging
turtletooth 04d8fd
  std::string strPath = tempName.toStdString();
turtletooth 04d8fd
  if (TSystem::doesExistFileOrLevel(TFilePath(tempName))) {
turtletooth 04d8fd
    QImage *temp = new QImage(tempName, "PNG");
turtletooth 04d8fd
    if (temp) {
turtletooth 04d8fd
      QImage tempToo = temp->convertToFormat(QImage::Format_ARGB32);
turtletooth 04d8fd
      delete temp;
turtletooth 04d8fd
      const UCHAR *bits = tempToo.bits();
turtletooth 04d8fd
turtletooth 04d8fd
      TRasterPT<tpixelrgbm32> ret;</tpixelrgbm32>
turtletooth 04d8fd
      ret.create(m_lx, m_ly);
turtletooth 04d8fd
      ret->lock();
turtletooth 04d8fd
      memcpy(ret->getRawData(), bits, m_lx * m_ly * 4);
turtletooth 04d8fd
      ret->unlock();
turtletooth 04d8fd
      ret->yMirror();
turtletooth 04d8fd
      return TRasterImageP(ret);
turtletooth 04d8fd
    }
Rozhuk Ivan 823a31
  }
Rozhuk Ivan 823a31
  return TRasterImageP();
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
double Ffmpeg::getFrameRate() {
manongjohn f2da01
  QStringList fpsArgs;
manongjohn d182c8
  int fpsNum = 0, fpsDen = 0;
manongjohn f2da01
  fpsArgs << "-v";
manongjohn f2da01
  fpsArgs << "error";
manongjohn f2da01
  fpsArgs << "-select_streams";
manongjohn f2da01
  fpsArgs << "v:0";
manongjohn f2da01
  fpsArgs << "-show_entries";
manongjohn f2da01
  fpsArgs << "stream=r_frame_rate";
manongjohn f2da01
  fpsArgs << "-of";
manongjohn f2da01
  fpsArgs << "default=noprint_wrappers=1:nokey=1";
manongjohn f2da01
  fpsArgs << m_path.getQString();
manongjohn f2da01
  QString fpsResults = runFfprobe(fpsArgs);
manongjohn f2da01
manongjohn d182c8
  QStringList fpsResultsList = fpsResults.split("/");
manongjohn d182c8
  if (fpsResultsList.size() > 1) {
manongjohn d182c8
    fpsNum = fpsResultsList[0].toInt();
manongjohn d182c8
    fpsDen = fpsResultsList[1].toInt();
manongjohn d182c8
  }
manongjohn d182c8
manongjohn d182c8
  // if for some reason we don't have enough info to calculate it. Use the
manongjohn d182c8
  // avg_frame_rate
manongjohn d182c8
  if (!fpsDen) {
manongjohn d182c8
    fpsArgs.clear();
manongjohn d182c8
    fpsArgs << "-v";
manongjohn d182c8
    fpsArgs << "error";
manongjohn d182c8
    fpsArgs << "-select_streams";
manongjohn d182c8
    fpsArgs << "v:0";
manongjohn d182c8
    fpsArgs << "-show_entries";
manongjohn d182c8
    fpsArgs << "stream=avg_frame_rate";
manongjohn d182c8
    fpsArgs << "-of";
manongjohn d182c8
    fpsArgs << "default=noprint_wrappers=1:nokey=1";
manongjohn d182c8
    fpsArgs << m_path.getQString();
manongjohn d182c8
    QString fpsResults = runFfprobe(fpsArgs);
manongjohn d182c8
manongjohn d182c8
    fpsResultsList = fpsResults.split("/");
manongjohn d182c8
    if (fpsResultsList.size() > 1) {
manongjohn d182c8
      fpsNum = fpsResultsList[0].toInt();
manongjohn d182c8
      fpsDen = fpsResultsList[1].toInt();
manongjohn d182c8
    }
manongjohn d182c8
  }
manongjohn d182c8
manongjohn f2da01
  if (fpsDen > 0) {
manongjohn f2da01
    m_frameRate = (double)fpsNum / (double)fpsDen;
turtletooth 04d8fd
  }
turtletooth 04d8fd
  return m_frameRate;
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
TDimension Ffmpeg::getSize() {
turtletooth 04d8fd
  QStringList sizeArgs;
turtletooth 04d8fd
  sizeArgs << "-v";
turtletooth 04d8fd
  sizeArgs << "error";
turtletooth 04d8fd
  sizeArgs << "-of";
turtletooth 04d8fd
  sizeArgs << "flat=s=_";
turtletooth 04d8fd
  sizeArgs << "-select_streams";
turtletooth 04d8fd
  sizeArgs << "v:0";
turtletooth 04d8fd
  sizeArgs << "-show_entries";
turtletooth 04d8fd
  sizeArgs << "stream=height,width";
turtletooth 04d8fd
  sizeArgs << m_path.getQString();
turtletooth 04d8fd
turtletooth 04d8fd
  QString sizeResults = runFfprobe(sizeArgs);
turtletooth 04d8fd
  QStringList split   = sizeResults.split("\n");
turtletooth 04d8fd
  m_lx                = split[0].split("=")[1].toInt();
turtletooth 04d8fd
  m_ly                = split[1].split("=")[1].toInt();
turtletooth 04d8fd
  return TDimension(m_lx, m_ly);
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
int Ffmpeg::getFrameCount() {
manongjohn d182c8
  // nb_read_frames from files may not be accurate. Let's calculate it based on
manongjohn d182c8
  // r_frame_rate * duration
turtletooth 04d8fd
  QStringList frameCountArgs;
turtletooth 04d8fd
  frameCountArgs << "-v";
turtletooth 04d8fd
  frameCountArgs << "error";
turtletooth 04d8fd
  frameCountArgs << "-count_frames";
turtletooth 04d8fd
  frameCountArgs << "-select_streams";
turtletooth 04d8fd
  frameCountArgs << "v:0";
turtletooth 04d8fd
  frameCountArgs << "-show_entries";
manongjohn f2da01
  frameCountArgs << "stream=duration";
turtletooth 04d8fd
  frameCountArgs << "-of";
turtletooth 04d8fd
  frameCountArgs << "default=nokey=1:noprint_wrappers=1";
turtletooth 04d8fd
  frameCountArgs << m_path.getQString();
turtletooth 04d8fd
turtletooth 04d8fd
  QString frameResults = runFfprobe(frameCountArgs);
manongjohn f2da01
  m_frameCount         = frameResults.toDouble() * getFrameRate();
manongjohn d182c8
manongjohn d182c8
  // if for some reason we don't have enough info to calculate it. Use the
manongjohn d182c8
  // nb_read_frames
manongjohn d182c8
  if (!m_frameCount) {
manongjohn d182c8
    frameCountArgs.clear();
manongjohn d182c8
    frameCountArgs << "-v";
manongjohn d182c8
    frameCountArgs << "error";
manongjohn d182c8
    frameCountArgs << "-count_frames";
manongjohn d182c8
    frameCountArgs << "-select_streams";
manongjohn d182c8
    frameCountArgs << "v:0";
manongjohn d182c8
    frameCountArgs << "-show_entries";
manongjohn d182c8
    frameCountArgs << "stream=nb_read_frames";
manongjohn d182c8
    frameCountArgs << "-of";
manongjohn d182c8
    frameCountArgs << "default=nokey=1:noprint_wrappers=1";
manongjohn d182c8
    frameCountArgs << m_path.getQString();
manongjohn d182c8
manongjohn d182c8
    frameResults = runFfprobe(frameCountArgs);
manongjohn d182c8
    m_frameCount = frameResults.toInt();
manongjohn d182c8
  }
manongjohn d182c8
turtletooth 04d8fd
  return m_frameCount;
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
void Ffmpeg::getFramesFromMovie(int frame) {
turtletooth 04d8fd
  QString ffmpegCachePath = getFfmpegCache().getQString();
Jeremy Bullock 686e82
  QString tempPath        = ffmpegCachePath + "//" + cleanPathSymbols();
Jeremy Bullock 686e82
  std::string tmpPath     = tempPath.toStdString();
Jeremy Bullock 686e82
  QString tempName        = "In%04d." + m_intermediateFormat;
Jeremy Bullock 686e82
  tempName                = tempPath + tempName;
turtletooth 04d8fd
  QString tempStart;
turtletooth 04d8fd
  if (frame == -1) {
turtletooth 04d8fd
    tempStart = "In0001." + m_intermediateFormat;
turtletooth 04d8fd
    tempStart = tempPath + tempStart;
turtletooth 04d8fd
  } else {
turtletooth 04d8fd
    QString number = QString("%1").arg(frame, 4, 10, QChar('0'));
turtletooth 04d8fd
    tempStart      = tempPath + "In" + number + "." + m_intermediateFormat;
turtletooth 04d8fd
  }
turtletooth 04d8fd
  QString tempBase = tempPath + "In";
turtletooth 04d8fd
  QString addToDelete;
turtletooth 04d8fd
  if (!TSystem::doesExistFileOrLevel(TFilePath(tempStart))) {
turtletooth 04d8fd
    // for debugging
turtletooth 04d8fd
    std::string strPath = tempName.toStdString();
turtletooth 04d8fd
turtletooth 04d8fd
    QStringList preIFrameArgs;
turtletooth 04d8fd
    QStringList postIFrameArgs;
turtletooth 04d8fd
    // frameArgs << "-accurate_seek";
turtletooth 04d8fd
    // frameArgs << "-ss";
turtletooth 04d8fd
    // frameArgs << "0" + QString::number(frameIndex / m_info->m_frameRate);
turtletooth 04d8fd
    preIFrameArgs << "-i";
turtletooth 04d8fd
    preIFrameArgs << m_path.getQString();
turtletooth 04d8fd
    postIFrameArgs << "-y";
turtletooth 04d8fd
    postIFrameArgs << "-f";
turtletooth 04d8fd
    postIFrameArgs << "image2";
turtletooth 04d8fd
turtletooth 04d8fd
    postIFrameArgs << tempName;
turtletooth 04d8fd
turtletooth 04d8fd
    runFfmpeg(preIFrameArgs, postIFrameArgs, true, true, true);
turtletooth 04d8fd
turtletooth 04d8fd
    for (int i = 1; i <= m_frameCount; i++) {
turtletooth 04d8fd
      QString number      = QString("%1").arg(i, 4, 10, QChar('0'));
turtletooth 04d8fd
      addToDelete         = tempBase + number + "." + m_intermediateFormat;
turtletooth 04d8fd
      std::string delPath = addToDelete.toStdString();
turtletooth 04d8fd
      // addToCleanUp(addToDelete);
turtletooth 04d8fd
    }
turtletooth 04d8fd
  }
turtletooth 04d8fd
}
turtletooth 04d8fd
Jeremy Bullock 686e82
QString Ffmpeg::cleanPathSymbols() {
Jeremy Bullock 686e82
  return m_path.getQString().remove(QRegExp(
shun-iwasawa a1dbd7
      QString::fromUtf8("[-`~!@#$%^&*()_—+=|:;<>«»,.?/{}\'\"\\[\\]\\\\]")));
Jeremy Bullock 686e82
}
Jeremy Bullock 686e82
Jeremy Bullock 779cdf
int Ffmpeg::getGifFrameCount() {
Jeremy Bullock 779cdf
  int frame               = 1;
Jeremy Bullock 779cdf
  QString ffmpegCachePath = getFfmpegCache().getQString();
Jeremy Bullock 686e82
  QString tempPath        = ffmpegCachePath + "//" + cleanPathSymbols();
Jeremy Bullock 686e82
  std::string tmpPath     = tempPath.toStdString();
Jeremy Bullock 686e82
  QString tempName        = "In%04d." + m_intermediateFormat;
Jeremy Bullock 686e82
  tempName                = tempPath + tempName;
Jeremy Bullock 779cdf
  QString tempStart;
Jeremy Bullock 779cdf
  tempStart = "In0001." + m_intermediateFormat;
Jeremy Bullock 779cdf
  tempStart = tempPath + tempStart;
Jeremy Bullock 779cdf
  while (TSystem::doesExistFileOrLevel(TFilePath(tempStart))) {
Jeremy Bullock 779cdf
    frame++;
Jeremy Bullock 779cdf
    QString number = QString("%1").arg(frame, 4, 10, QChar('0'));
Jeremy Bullock 779cdf
    tempStart      = tempPath + "In" + number + "." + m_intermediateFormat;
Jeremy Bullock 779cdf
  }
Jeremy Bullock 779cdf
  return frame - 1;
Jeremy Bullock 779cdf
}
Jeremy Bullock 779cdf
turtletooth 04d8fd
void Ffmpeg::addToCleanUp(QString path) {
turtletooth 04d8fd
  if (TSystem::doesExistFileOrLevel(TFilePath(path))) {
turtletooth 04d8fd
    m_cleanUpList.push_back(path);
turtletooth 04d8fd
  }
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
void Ffmpeg::cleanUpFiles() {
turtletooth 04d8fd
  for (QString path : m_cleanUpList) {
turtletooth 04d8fd
    if (TSystem::doesExistFileOrLevel(TFilePath(path))) {
turtletooth 04d8fd
      TSystem::deleteFile(TFilePath(path));
turtletooth 04d8fd
    }
turtletooth 04d8fd
  }
turtletooth 04d8fd
}
turtletooth 04d8fd
turtletooth 04d8fd
void Ffmpeg::disablePrecompute() {
turtletooth 04d8fd
  Preferences::instance()->setPrecompute(false);
turtletooth 04d8fd
}