|
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 |
}
|