Refactored source types (Avisynth, VapourSynth, etc) into separate classes + loads of fixes.
This commit is contained in:
parent
6164e48604
commit
38e7dbae56
@ -26,6 +26,7 @@
|
||||
#include "model_preferences.h"
|
||||
#include "model_sysinfo.h"
|
||||
#include "model_status.h"
|
||||
#include "source_abstract.h"
|
||||
#include "binaries.h"
|
||||
|
||||
#include <QProcess>
|
||||
@ -62,140 +63,17 @@ AbstractEncoder::~AbstractEncoder(void)
|
||||
/*Nothing to do here*/
|
||||
}
|
||||
|
||||
unsigned int AbstractEncoder::checkVersion(bool &modified)
|
||||
{
|
||||
if(m_preferences->getSkipVersionTest())
|
||||
{
|
||||
log("Warning: Skipping encoder version check this time!");
|
||||
return (999 * REV_MULT) + (REV_MULT-1);
|
||||
}
|
||||
|
||||
QProcess process;
|
||||
QList<QRegExp*> patterns;
|
||||
QStringList cmdLine;
|
||||
|
||||
//Init encoder-specific values
|
||||
checkVersion_init(patterns, cmdLine);
|
||||
|
||||
log("Creating process:");
|
||||
if(!startProcess(process, ENC_BINARY(m_sysinfo, m_options), cmdLine))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bTimeout = false;
|
||||
bool bAborted = false;
|
||||
|
||||
unsigned int revision = UINT_MAX;
|
||||
unsigned int coreVers = UINT_MAX;
|
||||
modified = false;
|
||||
|
||||
while(process.state() != QProcess::NotRunning)
|
||||
{
|
||||
if(m_abort)
|
||||
{
|
||||
process.kill();
|
||||
bAborted = true;
|
||||
break;
|
||||
}
|
||||
if(!process.waitForReadyRead())
|
||||
{
|
||||
if(process.state() == QProcess::Running)
|
||||
{
|
||||
process.kill();
|
||||
qWarning("encoder process timed out <-- killing!");
|
||||
log("\nPROCESS TIMEOUT !!!");
|
||||
bTimeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(process.bytesAvailable() > 0)
|
||||
{
|
||||
QList<QByteArray> lines = process.readLine().split('\r');
|
||||
while(!lines.isEmpty())
|
||||
{
|
||||
const QString text = QString::fromUtf8(lines.takeFirst().constData()).simplified();
|
||||
checkVersion_parseLine(text, patterns, coreVers, revision, modified);
|
||||
if(!text.isEmpty())
|
||||
{
|
||||
log(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process.waitForFinished();
|
||||
if(process.state() != QProcess::NotRunning)
|
||||
{
|
||||
process.kill();
|
||||
process.waitForFinished(-1);
|
||||
}
|
||||
|
||||
while(!patterns.isEmpty())
|
||||
{
|
||||
QRegExp *pattern = patterns.takeFirst();
|
||||
X264_DELETE(pattern);
|
||||
}
|
||||
|
||||
if(bTimeout || bAborted || process.exitCode() != EXIT_SUCCESS)
|
||||
{
|
||||
if(!(bTimeout || bAborted))
|
||||
{
|
||||
log(tr("\nPROCESS EXITED WITH ERROR CODE: %1").arg(QString::number(process.exitCode())));
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
if((revision == UINT_MAX) || (coreVers == UINT_MAX))
|
||||
{
|
||||
log(tr("\nFAILED TO DETERMINE ENCODER VERSION !!!"));
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
return (coreVers * REV_MULT) + (revision % REV_MULT);
|
||||
}
|
||||
|
||||
bool AbstractEncoder::runEncodingPass(AbstractSource* source, const QString outputFile, const unsigned int &frames, const int &pass, const QString &passLogFile)
|
||||
bool AbstractEncoder::runEncodingPass(AbstractSource* pipedSource, const QString outputFile, const unsigned int &frames, const int &pass, const QString &passLogFile)
|
||||
{
|
||||
QProcess processEncode, processInput;
|
||||
|
||||
/*
|
||||
if(inputType != INPUT_NATIVE)
|
||||
if(pipedSource)
|
||||
{
|
||||
QStringList cmdLine_Input;
|
||||
processInput.setStandardOutputProcess(&processEncode);
|
||||
switch(inputType)
|
||||
{
|
||||
case INPUT_AVISYN:
|
||||
if(!m_options->customAvs2YUV().isEmpty())
|
||||
{
|
||||
cmdLine_Input.append(splitParams(m_options->customAvs2YUV()));
|
||||
pipedSource->createProcess(processEncode, processInput);
|
||||
}
|
||||
cmdLine_Input << QDir::toNativeSeparators(x264_path2ansi(m_sourceFileName, true));
|
||||
cmdLine_Input << "-";
|
||||
log("Creating Avisynth process:");
|
||||
if(!startProcess(processInput, AVS_BINARY(m_sysinfo, m_preferences), cmdLine_Input, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case INPUT_VAPOUR:
|
||||
cmdLine_Input << QDir::toNativeSeparators(x264_path2ansi(m_sourceFileName, true));
|
||||
cmdLine_Input << "-" << "-y4m";
|
||||
log("Creating Vapoursynth process:");
|
||||
if(!startProcess(processInput, VPS_BINARY(m_sysinfo, m_preferences), cmdLine_Input, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw "Bad input type encontered!";
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
QStringList cmdLine_Encode;
|
||||
buildCommandLine(cmdLine_Encode, (source != NULL), frames, m_indexFile, pass, passLogFile);
|
||||
buildCommandLine(cmdLine_Encode, (pipedSource != NULL), frames, m_indexFile, pass, passLogFile);
|
||||
|
||||
log("Creating encoder process:");
|
||||
if(!startProcess(processEncode, ENC_BINARY(m_sysinfo, m_options), cmdLine_Encode))
|
||||
@ -304,6 +182,8 @@ bool AbstractEncoder::runEncodingPass(AbstractSource* source, const QString outp
|
||||
processEncode.waitForFinished(-1);
|
||||
}
|
||||
|
||||
if(pipedSource)
|
||||
{
|
||||
processInput.waitForFinished(5000);
|
||||
if(processInput.state() != QProcess::NotRunning)
|
||||
{
|
||||
@ -311,6 +191,11 @@ bool AbstractEncoder::runEncodingPass(AbstractSource* source, const QString outp
|
||||
processInput.kill();
|
||||
processInput.waitForFinished(-1);
|
||||
}
|
||||
if(!(bTimeout || bAborted))
|
||||
{
|
||||
pipedSource->flushProcess(processInput);
|
||||
}
|
||||
}
|
||||
|
||||
while(!patterns.isEmpty())
|
||||
{
|
||||
@ -318,44 +203,6 @@ bool AbstractEncoder::runEncodingPass(AbstractSource* source, const QString outp
|
||||
X264_DELETE(pattern);
|
||||
}
|
||||
|
||||
if(!(bTimeout || bAborted))
|
||||
{
|
||||
while(processInput.bytesAvailable() > 0)
|
||||
{
|
||||
/*
|
||||
switch(inputType)
|
||||
{
|
||||
case INPUT_AVISYN:
|
||||
log(tr("av2y [info]: %1").arg(QString::fromUtf8(processInput.readLine()).simplified()));
|
||||
break;
|
||||
case INPUT_VAPOUR:
|
||||
log(tr("vpyp [info]: %1").arg(QString::fromUtf8(processInput.readLine()).simplified()));
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if((inputType != INPUT_NATIVE) && (processInput.exitCode() != EXIT_SUCCESS))
|
||||
{
|
||||
if(!(bTimeout || bAborted))
|
||||
{
|
||||
const int exitCode = processInput.exitCode();
|
||||
log(tr("\nWARNING: Input process exited with error (code: %1), your encode might be *incomplete* !!!").arg(QString::number(exitCode)));
|
||||
if((inputType == INPUT_AVISYN) && ((exitCode < 0) || (exitCode >= 32)))
|
||||
{
|
||||
log(tr("\nIMPORTANT: The Avs2YUV process terminated abnormally. This means Avisynth or one of your Avisynth-Plugin's just crashed."));
|
||||
log(tr("IMPORTANT: Please fix your Avisynth script and try again! If you use Avisynth-MT, try using a *stable* Avisynth instead!"));
|
||||
}
|
||||
if((inputType == INPUT_VAPOUR) && ((exitCode < 0) || (exitCode >= 32)))
|
||||
{
|
||||
log(tr("\nIMPORTANT: The Vapoursynth process terminated abnormally. This means Vapoursynth or one of your Vapoursynth-Plugin's just crashed."));
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if(bTimeout || bAborted || processEncode.exitCode() != EXIT_SUCCESS)
|
||||
{
|
||||
if(!(bTimeout || bAborted))
|
||||
|
@ -30,21 +30,12 @@ class AbstractSource;
|
||||
class AbstractEncoder : public AbstractTool
|
||||
{
|
||||
public:
|
||||
static const unsigned int REV_MULT = 10000;
|
||||
|
||||
AbstractEncoder(JobObject *jobObject, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences, JobStatus &jobStatus, volatile bool *abort, volatile bool *pause, QSemaphore *semaphorePause, const QString &sourceFile, const QString &outputFile);
|
||||
virtual ~AbstractEncoder(void);
|
||||
|
||||
virtual unsigned int checkVersion(bool &modified);
|
||||
virtual bool isVersionSupported(const unsigned int &revision, const bool &modified) = 0;
|
||||
virtual void printVersion(const unsigned int &revision, const bool &modified) = 0;
|
||||
|
||||
bool runEncodingPass(AbstractSource* source, const QString outputFile, const unsigned int &frames, const int &pass, const QString &passLogFile);
|
||||
bool runEncodingPass(AbstractSource* pipedSource, const QString outputFile, const unsigned int &frames, const int &pass = 0, const QString &passLogFile = QString());
|
||||
|
||||
protected:
|
||||
virtual void checkVersion_init(QList<QRegExp*> &patterns, QStringList &cmdLine) = 0;
|
||||
virtual void checkVersion_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &coreVers, unsigned int &revision, bool &modified) = 0;
|
||||
|
||||
virtual void buildCommandLine(QStringList &cmdLine, const bool &usePipe, const unsigned int &frames, const QString &indexFile, const int &pass, const QString &passLogFile) = 0;
|
||||
|
||||
virtual void runEncodingPass_init(QList<QRegExp*> &patterns) = 0;
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "model_options.h"
|
||||
#include "model_status.h"
|
||||
#include "binaries.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
@ -66,13 +67,13 @@ while(0)
|
||||
|
||||
X264Encoder::X264Encoder(JobObject *jobObject, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences, JobStatus &jobStatus, volatile bool *abort, volatile bool *pause, QSemaphore *semaphorePause, const QString &sourceFile, const QString &outputFile)
|
||||
:
|
||||
AbstractEncoder(jobObject, options, sysinfo, preferences, jobStatus, abort, pause, semaphorePause, sourceFile, outputFile)
|
||||
AbstractEncoder(jobObject, options, sysinfo, preferences, jobStatus, abort, pause, semaphorePause, sourceFile, outputFile),
|
||||
m_binaryFile(ENC_BINARY(sysinfo, options))
|
||||
{
|
||||
if(options->encType() != OptionsModel::EncType_X264)
|
||||
{
|
||||
throw "Invalid encoder type!";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
X264Encoder::~X264Encoder(void)
|
||||
|
@ -31,12 +31,16 @@ public:
|
||||
|
||||
virtual void printVersion(const unsigned int &revision, const bool &modified);
|
||||
virtual bool isVersionSupported(const unsigned int &revision, const bool &modified);
|
||||
virtual void buildCommandLine(QStringList &cmdLine, const bool &usePipe, const unsigned int &frames, const QString &indexFile, const int &pass, const QString &passLogFile);
|
||||
|
||||
protected:
|
||||
virtual const QString &getBinaryPath() { return m_binaryFile; }
|
||||
virtual void buildCommandLine(QStringList &cmdLine, const bool &usePipe, const unsigned int &frames, const QString &indexFile, const int &pass, const QString &passLogFile);
|
||||
|
||||
virtual void checkVersion_init(QList<QRegExp*> &patterns, QStringList &cmdLine);
|
||||
virtual void checkVersion_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &coreVers, unsigned int &revision, bool &modified);
|
||||
|
||||
virtual void runEncodingPass_init(QList<QRegExp*> &patterns);
|
||||
virtual void runEncodingPass_parseLine(const QString &line, QList<QRegExp*> &patterns, const int &pass);
|
||||
|
||||
const QString m_binaryFile;
|
||||
};
|
||||
|
@ -22,17 +22,54 @@
|
||||
#include "encoder_x265.h"
|
||||
|
||||
#include "model_options.h"
|
||||
#include "model_status.h"
|
||||
#include "binaries.h"
|
||||
#include "binaries.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
#include <QRegExp>
|
||||
|
||||
//x265 version info
|
||||
static const unsigned int X265_VERSION_X264_MINIMUM_VER = 7;
|
||||
static const unsigned int X265_VERSION_X264_MINIMUM_REV = 167;
|
||||
|
||||
#define X264_UPDATE_PROGRESS(X) do \
|
||||
{ \
|
||||
bool ok = false; qint64 size_estimate = 0; \
|
||||
unsigned int progress = (X)->cap(1).toUInt(&ok); \
|
||||
setStatus((pass == 2) ? JobStatus_Running_Pass2 : ((pass == 1) ? JobStatus_Running_Pass1 : JobStatus_Running)); \
|
||||
if(ok) \
|
||||
{ \
|
||||
setProgress(progress); \
|
||||
size_estimate = estimateSize(m_outputFile, progress); \
|
||||
} \
|
||||
setDetails(tr("%1, est. file size %2").arg(line.mid(offset).trimmed(), sizeToString(size_estimate))); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
#define REMOVE_CUSTOM_ARG(LIST, ITER, FLAG, PARAM) do \
|
||||
{ \
|
||||
if(ITER != LIST.end()) \
|
||||
{ \
|
||||
if((*ITER).compare(PARAM, Qt::CaseInsensitive) == 0) \
|
||||
{ \
|
||||
log(tr("WARNING: Custom parameter \"" PARAM "\" will be ignored in Pipe'd mode!\n")); \
|
||||
ITER = LIST.erase(ITER); \
|
||||
if(ITER != LIST.end()) \
|
||||
{ \
|
||||
if(!((*ITER).startsWith("--", Qt::CaseInsensitive))) ITER = LIST.erase(ITER); \
|
||||
} \
|
||||
FLAG = true; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
X265Encoder::X265Encoder(JobObject *jobObject, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences, JobStatus &jobStatus, volatile bool *abort, volatile bool *pause, QSemaphore *semaphorePause, const QString &sourceFile, const QString &outputFile)
|
||||
:
|
||||
AbstractEncoder(jobObject, options, sysinfo, preferences, jobStatus, abort, pause, semaphorePause, sourceFile, outputFile)
|
||||
AbstractEncoder(jobObject, options, sysinfo, preferences, jobStatus, abort, pause, semaphorePause, sourceFile, outputFile),
|
||||
m_binaryFile(ENC_BINARY(sysinfo, options))
|
||||
{
|
||||
if(options->encType() != OptionsModel::EncType_X265)
|
||||
{
|
||||
@ -82,3 +119,120 @@ bool X265Encoder::isVersionSupported(const unsigned int &revision, const bool &m
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void X265Encoder::buildCommandLine(QStringList &cmdLine, const bool &usePipe, const unsigned int &frames, const QString &indexFile, const int &pass, const QString &passLogFile)
|
||||
{
|
||||
double crf_int = 0.0, crf_frc = 0.0;
|
||||
|
||||
switch(m_options->rcMode())
|
||||
{
|
||||
case OptionsModel::RCMode_CQ:
|
||||
cmdLine << "--qp" << QString::number(qRound(m_options->quantizer()));
|
||||
break;
|
||||
case OptionsModel::RCMode_CRF:
|
||||
crf_frc = modf(m_options->quantizer(), &crf_int);
|
||||
cmdLine << "--crf" << QString("%1.%2").arg(QString::number(qRound(crf_int)), QString::number(qRound(crf_frc * 10.0)));
|
||||
break;
|
||||
case OptionsModel::RCMode_2Pass:
|
||||
case OptionsModel::RCMode_ABR:
|
||||
cmdLine << "--bitrate" << QString::number(m_options->bitrate());
|
||||
break;
|
||||
default:
|
||||
throw "Bad rate-control mode !!!";
|
||||
break;
|
||||
}
|
||||
|
||||
if((pass == 1) || (pass == 2))
|
||||
{
|
||||
cmdLine << "--pass" << QString::number(pass);
|
||||
cmdLine << "--stats" << QDir::toNativeSeparators(passLogFile);
|
||||
}
|
||||
|
||||
cmdLine << "--preset" << m_options->preset().toLower();
|
||||
|
||||
if(m_options->tune().compare("none", Qt::CaseInsensitive))
|
||||
{
|
||||
cmdLine << "--tune" << m_options->tune().toLower();
|
||||
}
|
||||
|
||||
if(m_options->profile().compare("auto", Qt::CaseInsensitive) != 0)
|
||||
{
|
||||
if((m_options->encType() == OptionsModel::EncType_X264) && (m_options->encVariant() == OptionsModel::EncVariant_LoBit))
|
||||
{
|
||||
cmdLine << "--profile" << m_options->profile().toLower();
|
||||
}
|
||||
}
|
||||
|
||||
if(!m_options->customEncParams().isEmpty())
|
||||
{
|
||||
QStringList customArgs = splitParams(m_options->customEncParams(), m_sourceFile, m_outputFile);
|
||||
if(usePipe)
|
||||
{
|
||||
QStringList::iterator i = customArgs.begin();
|
||||
while(i != customArgs.end())
|
||||
{
|
||||
bool bModified = false;
|
||||
REMOVE_CUSTOM_ARG(customArgs, i, bModified, "--fps");
|
||||
REMOVE_CUSTOM_ARG(customArgs, i, bModified, "--frames");
|
||||
if(!bModified) i++;
|
||||
}
|
||||
}
|
||||
cmdLine.append(customArgs);
|
||||
}
|
||||
|
||||
cmdLine << "--output" << QDir::toNativeSeparators(m_outputFile);
|
||||
|
||||
if(usePipe)
|
||||
{
|
||||
if(frames < 1) throw "Frames not set!";
|
||||
cmdLine << "--frames" << QString::number(frames);
|
||||
cmdLine << "--demuxer" << "y4m";
|
||||
cmdLine << "--stdin" << "y4m" << "-";
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdLine << "--index" << QDir::toNativeSeparators(indexFile);
|
||||
cmdLine << QDir::toNativeSeparators(m_sourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
void X265Encoder::runEncodingPass_init(QList<QRegExp*> &patterns)
|
||||
{
|
||||
patterns << new QRegExp("\\[(\\d+)\\.(\\d+)%\\].+frames"); //regExpProgress
|
||||
patterns << new QRegExp("indexing.+\\[(\\d+)\\.(\\d+)%\\]"); //regExpIndexing
|
||||
patterns << new QRegExp("^(\\d+) frames:"); //regExpFrameCnt
|
||||
patterns << new QRegExp("\\[\\s*(\\d+)\\.(\\d+)%\\]\\s+(\\d+)/(\\d+)\\s(\\d+).(\\d+)\\s(\\d+).(\\d+)\\s+(\\d+):(\\d+):(\\d+)\\s+(\\d+):(\\d+):(\\d+)"); //regExpModified
|
||||
}
|
||||
|
||||
void X265Encoder::runEncodingPass_parseLine(const QString &line, QList<QRegExp*> &patterns, const int &pass)
|
||||
{
|
||||
int offset = -1;
|
||||
if((offset = patterns[0]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
X264_UPDATE_PROGRESS(patterns[0]);
|
||||
}
|
||||
else if((offset = patterns[1]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
bool ok = false;
|
||||
unsigned int progress = patterns[1]->cap(1).toUInt(&ok);
|
||||
setStatus(JobStatus_Indexing);
|
||||
if(ok)
|
||||
{
|
||||
setProgress(progress);
|
||||
}
|
||||
setDetails(line.mid(offset).trimmed());
|
||||
}
|
||||
else if((offset = patterns[2]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
setStatus((pass == 2) ? JobStatus_Running_Pass2 : ((pass == 1) ? JobStatus_Running_Pass1 : JobStatus_Running));
|
||||
setDetails(line.mid(offset).trimmed());
|
||||
}
|
||||
else if((offset = patterns[3]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
X264_UPDATE_PROGRESS(patterns[3]);
|
||||
}
|
||||
else if(!line.isEmpty())
|
||||
{
|
||||
log(line);
|
||||
}
|
||||
}
|
||||
|
@ -31,12 +31,16 @@ public:
|
||||
|
||||
virtual void printVersion(const unsigned int &revision, const bool &modified);
|
||||
virtual bool isVersionSupported(const unsigned int &revision, const bool &modified);
|
||||
virtual void buildCommandLine(QStringList &cmdLine, const bool &usePipe, const unsigned int &frames, const QString &indexFile, const int &pass, const QString &passLogFile);
|
||||
|
||||
protected:
|
||||
virtual const QString &getBinaryPath() { return m_binaryFile; }
|
||||
virtual void buildCommandLine(QStringList &cmdLine, const bool &usePipe, const unsigned int &frames, const QString &indexFile, const int &pass, const QString &passLogFile);
|
||||
|
||||
virtual void checkVersion_init(QList<QRegExp*> &patterns, QStringList &cmdLine);
|
||||
virtual void checkVersion_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &coreVers, unsigned int &revision, bool &modified);
|
||||
|
||||
virtual void runEncodingPass_init(QList<QRegExp*> &patterns);
|
||||
virtual void runEncodingPass_parseLine(const QString &line, QList<QRegExp*> &patterns, const int &pass);
|
||||
|
||||
const QString m_binaryFile;
|
||||
};
|
||||
|
@ -112,7 +112,6 @@ static const struct
|
||||
unsigned int ver_build;
|
||||
const char* ver_date;
|
||||
const char* ver_time;
|
||||
unsigned int ver_x264_avs2yuv_ver;
|
||||
}
|
||||
g_x264_version =
|
||||
{
|
||||
@ -122,7 +121,6 @@ g_x264_version =
|
||||
(VER_X264_BUILD),
|
||||
__DATE__,
|
||||
__TIME__,
|
||||
(VER_X264_AVS2YUV_VER)
|
||||
};
|
||||
|
||||
//CLI Arguments
|
||||
@ -759,12 +757,6 @@ const char *x264_version_arch(void)
|
||||
return g_x264_version_arch;
|
||||
}
|
||||
|
||||
//FIXME: Remove x264_version_x264_avs2yuv_ver!
|
||||
unsigned int x264_version_x264_avs2yuv_ver(void)
|
||||
{
|
||||
return g_x264_version.ver_x264_avs2yuv_ver;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get CLI arguments
|
||||
*/
|
||||
|
@ -162,9 +162,6 @@ const QDate &x264_version_date(void);
|
||||
unsigned int x264_version_major(void);
|
||||
unsigned int x264_version_minor(void);
|
||||
const char *x264_version_time(void);
|
||||
unsigned int x264_version_x264_minimum_rev(void);
|
||||
unsigned int x264_version_x264_current_api(void);
|
||||
unsigned int x264_version_x264_avs2yuv_ver(void);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// HELPER MACROS
|
||||
|
183
src/source_abstract.cpp
Normal file
183
src/source_abstract.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Simple x264 Launcher
|
||||
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// http://www.gnu.org/licenses/gpl-2.0.txt
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "source_abstract.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "model_sysinfo.h"
|
||||
#include "model_options.h"
|
||||
#include "model_preferences.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QTextCodec>
|
||||
#include <QDir>
|
||||
|
||||
AbstractSource::AbstractSource(JobObject *jobObject, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences, JobStatus &jobStatus, volatile bool *abort, volatile bool *pause, QSemaphore *semaphorePause, const QString &sourceFile)
|
||||
:
|
||||
AbstractTool(jobObject, options, sysinfo, preferences, jobStatus, abort, pause, semaphorePause),
|
||||
m_sourceFile(sourceFile)
|
||||
{
|
||||
/*Nothing to do here*/
|
||||
}
|
||||
|
||||
AbstractSource::~AbstractSource(void)
|
||||
{
|
||||
/*Nothing to do here*/
|
||||
}
|
||||
|
||||
bool AbstractSource::checkSourceProperties(unsigned int &frames)
|
||||
{
|
||||
QStringList cmdLine;
|
||||
QList<QRegExp*> patterns;
|
||||
QProcess process;
|
||||
|
||||
checkSourceProperties_init(patterns, cmdLine);
|
||||
|
||||
log("Creating process:");
|
||||
if(!startProcess(process, getBinaryPath(), cmdLine))
|
||||
{
|
||||
return false;;
|
||||
}
|
||||
|
||||
QTextCodec *localCodec = QTextCodec::codecForName("System");
|
||||
|
||||
bool bTimeout = false;
|
||||
bool bAborted = false;
|
||||
|
||||
frames = 0;
|
||||
|
||||
unsigned int fpsNom = 0;
|
||||
unsigned int fpsDen = 0;
|
||||
unsigned int fSizeW = 0;
|
||||
unsigned int fSizeH = 0;
|
||||
|
||||
unsigned int waitCounter = 0;
|
||||
|
||||
while(process.state() != QProcess::NotRunning)
|
||||
{
|
||||
if(m_abort)
|
||||
{
|
||||
process.kill();
|
||||
bAborted = true;
|
||||
break;
|
||||
}
|
||||
if(!process.waitForReadyRead(m_processTimeoutInterval))
|
||||
{
|
||||
if(process.state() == QProcess::Running)
|
||||
{
|
||||
if(++waitCounter > m_processTimeoutMaxCounter)
|
||||
{
|
||||
if(m_preferences->getAbortOnTimeout())
|
||||
{
|
||||
process.kill();
|
||||
qWarning("Source process timed out <-- killing!");
|
||||
log("\nPROCESS TIMEOUT !!!");
|
||||
log("\nInput process has encountered a deadlock or your script takes EXTREMELY long to initialize!");
|
||||
bTimeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(waitCounter == m_processTimeoutWarning)
|
||||
{
|
||||
unsigned int timeOut = (waitCounter * m_processTimeoutInterval) / 1000U;
|
||||
log(tr("Warning: Input process did not respond for %1 seconds, potential deadlock...").arg(QString::number(timeOut)));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
waitCounter = 0;
|
||||
|
||||
while(process.bytesAvailable() > 0)
|
||||
{
|
||||
QList<QByteArray> lines = process.readLine().split('\r');
|
||||
while(!lines.isEmpty())
|
||||
{
|
||||
QString text = localCodec->toUnicode(lines.takeFirst().constData()).simplified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process.waitForFinished();
|
||||
if(process.state() != QProcess::NotRunning)
|
||||
{
|
||||
process.kill();
|
||||
process.waitForFinished(-1);
|
||||
}
|
||||
|
||||
if(bTimeout || bAborted || process.exitCode() != EXIT_SUCCESS)
|
||||
{
|
||||
if(!(bTimeout || bAborted))
|
||||
{
|
||||
const int exitCode = process.exitCode();
|
||||
log(tr("\nPROCESS EXITED WITH ERROR CODE: %1").arg(QString::number(exitCode)));
|
||||
if((exitCode < 0) || (exitCode >= 32))
|
||||
{
|
||||
log(tr("\nIMPORTANT: The Avs2YUV process terminated abnormally. This means Avisynth or one of your Avisynth-Plugin's just crashed."));
|
||||
log(tr("IMPORTANT: Please fix your Avisynth script and try again! If you use Avisynth-MT, try using a *stable* Avisynth instead!"));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if(frames == 0)
|
||||
{
|
||||
log(tr("\nFAILED TO DETERMINE AVS PROPERTIES !!!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
log("");
|
||||
|
||||
if((fSizeW > 0) && (fSizeH > 0))
|
||||
{
|
||||
log(tr("Resolution: %1x%2").arg(QString::number(fSizeW), QString::number(fSizeH)));
|
||||
}
|
||||
if((fpsNom > 0) && (fpsDen > 0))
|
||||
{
|
||||
log(tr("Frame Rate: %1/%2").arg(QString::number(fpsNom), QString::number(fpsDen)));
|
||||
}
|
||||
if((fpsNom > 0) && (fpsDen == 0))
|
||||
{
|
||||
log(tr("Frame Rate: %1").arg(QString::number(fpsNom)));
|
||||
}
|
||||
if(frames > 0)
|
||||
{
|
||||
log(tr("No. Frames: %1").arg(QString::number(frames)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbstractSource::createProcess(QProcess &processEncode, QProcess&processInput)
|
||||
{
|
||||
processInput.setStandardOutputProcess(&processEncode);
|
||||
|
||||
QStringList cmdLine_Input;
|
||||
buildCommandLine(cmdLine_Input);
|
||||
|
||||
log("Creating input process:");
|
||||
if(!startProcess(processInput, getBinaryPath(), cmdLine_Input, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
47
src/source_abstract.h
Normal file
47
src/source_abstract.h
Normal file
@ -0,0 +1,47 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Simple x264 Launcher
|
||||
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// http://www.gnu.org/licenses/gpl-2.0.txt
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "tool_abstract.h"
|
||||
|
||||
class QRegExp;
|
||||
template<class T> class QList;
|
||||
class QProcess;
|
||||
|
||||
class AbstractSource : public AbstractTool
|
||||
{
|
||||
public:
|
||||
AbstractSource(JobObject *jobObject, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences, JobStatus &jobStatus, volatile bool *abort, volatile bool *pause, QSemaphore *semaphorePause, const QString &sourceFile);
|
||||
virtual ~AbstractSource(void);
|
||||
|
||||
virtual bool checkSourceProperties(unsigned int &frames);
|
||||
virtual bool createProcess(QProcess &processEncode, QProcess&processInput);
|
||||
virtual void flushProcess(QProcess &processInput) = 0;
|
||||
|
||||
protected:
|
||||
virtual void checkSourceProperties_init(QList<QRegExp*> &patterns, QStringList &cmdLine) = 0;
|
||||
virtual void checkSourceProperties_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &frames, unsigned int &fSizeW, unsigned int &fSizeH, unsigned int &fpsNom, unsigned int &fpsDen) = 0;
|
||||
|
||||
virtual void buildCommandLine(QStringList &cmdLine) = 0;
|
||||
|
||||
const QString &m_sourceFile;
|
||||
};
|
170
src/source_avisynth.cpp
Normal file
170
src/source_avisynth.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Simple x264 Launcher
|
||||
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// http://www.gnu.org/licenses/gpl-2.0.txt
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "source_avisynth.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "model_preferences.h"
|
||||
#include "binaries.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QProcess>
|
||||
|
||||
static const unsigned int VER_X264_AVS2YUV_VER = 242;
|
||||
|
||||
AvisynthSource::AvisynthSource(JobObject *jobObject, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences, JobStatus &jobStatus, volatile bool *abort, volatile bool *pause, QSemaphore *semaphorePause, const QString &sourceFile)
|
||||
:
|
||||
AbstractSource(jobObject, options, sysinfo, preferences, jobStatus, abort, pause, semaphorePause, sourceFile),
|
||||
m_binaryFile(AVS_BINARY(m_sysinfo, m_preferences))
|
||||
{
|
||||
/*Nothing to do here*/
|
||||
}
|
||||
|
||||
AvisynthSource::~AvisynthSource(void)
|
||||
{
|
||||
/*Nothing to do here*/
|
||||
}
|
||||
|
||||
void AvisynthSource::checkVersion_init(QList<QRegExp*> &patterns, QStringList &cmdLine)
|
||||
{
|
||||
cmdLine << "--version";
|
||||
patterns << new QRegExp("\\bAvs2YUV (\\d+).(\\d+)bm(\\d)\\b", Qt::CaseInsensitive);
|
||||
patterns << new QRegExp("\\bAvs2YUV (\\d+).(\\d+)\\b", Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
void AvisynthSource::checkVersion_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &coreVers, unsigned int &revision, bool &modified)
|
||||
{
|
||||
int offset = -1;
|
||||
if((offset = patterns[0]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
bool ok1 = false, ok2 = false;
|
||||
unsigned int temp1 = patterns[0]->cap(2).toUInt(&ok1);
|
||||
unsigned int temp2 = patterns[0]->cap(3).toUInt(&ok2);
|
||||
if(ok1) coreVers = temp1;
|
||||
if(ok2) revision = temp2;
|
||||
}
|
||||
else if((offset = patterns[1]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
bool ok1 = false, ok2 = false;
|
||||
unsigned int temp1 = patterns[1]->cap(2).toUInt(&ok1);
|
||||
unsigned int temp2 = patterns[1]->cap(3).toUInt(&ok2);
|
||||
if(ok1) coreVers = temp1;
|
||||
if(ok2) revision = temp2;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AvisynthSource::printVersion(const unsigned int &revision, const bool &modified)
|
||||
{
|
||||
log(tr("Avs2YUV version: %1.%2.%3").arg(QString::number(revision / REV_MULT), QString::number((revision % REV_MULT) / 10),QString::number((revision % REV_MULT) % 10)));
|
||||
}
|
||||
|
||||
bool AvisynthSource::isVersionSupported(const unsigned int &revision, const bool &modified)
|
||||
{
|
||||
if((revision != UINT_MAX) && ((revision % REV_MULT) != VER_X264_AVS2YUV_VER))
|
||||
{
|
||||
log(tr("\nERROR: Your version of avs2yuv is unsupported (Required version: v0.24 BugMaster's mod 2)"));
|
||||
log(tr("You can find the required version at: http://komisar.gin.by/tools/avs2yuv/"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AvisynthSource::checkSourceProperties_init(QList<QRegExp*> &patterns, QStringList &cmdLine)
|
||||
{
|
||||
cmdLine << "-frames" << "1";
|
||||
cmdLine << QDir::toNativeSeparators(x264_path2ansi(m_sourceFile, true)) << "NUL";
|
||||
|
||||
patterns << new QRegExp(": (\\d+)x(\\d+), (\\d+) fps, (\\d+) frames");
|
||||
patterns << new QRegExp(": (\\d+)x(\\d+), (\\d+)/(\\d+) fps, (\\d+) frames");
|
||||
}
|
||||
|
||||
void AvisynthSource::checkSourceProperties_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &frames, unsigned int &fSizeW, unsigned int &fSizeH, unsigned int &fpsNom, unsigned int &fpsDen)
|
||||
{
|
||||
int offset = -1;
|
||||
if((offset = patterns[0]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
bool ok1 = false, ok2 = false;
|
||||
bool ok3 = false, ok4 = false;
|
||||
unsigned int temp1 = patterns[0]->cap(1).toUInt(&ok1);
|
||||
unsigned int temp2 = patterns[0]->cap(2).toUInt(&ok2);
|
||||
unsigned int temp3 = patterns[0]->cap(3).toUInt(&ok3);
|
||||
unsigned int temp4 = patterns[0]->cap(4).toUInt(&ok4);
|
||||
if(ok1) fSizeW = temp1;
|
||||
if(ok2) fSizeH = temp2;
|
||||
if(ok3) fpsNom = temp3;
|
||||
if(ok4) frames = temp4;
|
||||
}
|
||||
else if((offset = patterns[1]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
bool ok1 = false, ok2 = false;
|
||||
bool ok3 = false, ok4 = false, ok5 = false;
|
||||
unsigned int temp1 = patterns[1]->cap(1).toUInt(&ok1);
|
||||
unsigned int temp2 = patterns[1]->cap(2).toUInt(&ok2);
|
||||
unsigned int temp3 = patterns[1]->cap(3).toUInt(&ok3);
|
||||
unsigned int temp4 = patterns[1]->cap(4).toUInt(&ok4);
|
||||
unsigned int temp5 = patterns[1]->cap(5).toUInt(&ok5);
|
||||
if(ok1) fSizeW = temp1;
|
||||
if(ok2) fSizeH = temp2;
|
||||
if(ok3) fpsNom = temp3;
|
||||
if(ok4) fpsDen = temp4;
|
||||
if(ok5) frames = temp5;
|
||||
}
|
||||
if(!line.isEmpty())
|
||||
{
|
||||
log(line);
|
||||
}
|
||||
if(line.contains("failed to load avisynth.dll", Qt::CaseInsensitive))
|
||||
{
|
||||
log(tr("\nWarning: It seems that %1-Bit Avisynth is not currently installed !!!").arg(m_preferences->getUseAvisyth64Bit() ? "64" : "32"));
|
||||
}
|
||||
if(line.contains(QRegExp("couldn't convert input clip to (YV16|YV24)", Qt::CaseInsensitive)))
|
||||
{
|
||||
log(tr("\nWarning: YV16 (4:2:2) and YV24 (4:4:4) color-spaces only supported in Avisynth 2.6 !!!"));
|
||||
}
|
||||
}
|
||||
|
||||
void AvisynthSource::buildCommandLine(QStringList &cmdLine)
|
||||
{
|
||||
cmdLine << QDir::toNativeSeparators(x264_path2ansi(m_sourceFile, true));
|
||||
cmdLine << "-";
|
||||
}
|
||||
|
||||
void AvisynthSource::flushProcess(QProcess &processInput)
|
||||
{
|
||||
while(processInput.bytesAvailable() > 0)
|
||||
{
|
||||
log(tr("av2y [info]: %1").arg(QString::fromUtf8(processInput.readLine()).simplified()));
|
||||
}
|
||||
|
||||
if(processInput.exitCode() != EXIT_SUCCESS)
|
||||
{
|
||||
const int exitCode = processInput.exitCode();
|
||||
log(tr("\nWARNING: Input process exited with error (code: %1), your encode might be *incomplete* !!!").arg(QString::number(exitCode)));
|
||||
if((exitCode < 0) || (exitCode >= 32))
|
||||
{
|
||||
log(tr("\nIMPORTANT: The Avs2YUV process terminated abnormally. This means Avisynth or one of your Avisynth-Plugin's just crashed."));
|
||||
log(tr("IMPORTANT: Please fix your Avisynth script and try again! If you use Avisynth-MT, try using a *stable* Avisynth instead!"));
|
||||
}
|
||||
}
|
||||
}
|
48
src/source_avisynth.h
Normal file
48
src/source_avisynth.h
Normal file
@ -0,0 +1,48 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Simple x264 Launcher
|
||||
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// http://www.gnu.org/licenses/gpl-2.0.txt
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "source_abstract.h"
|
||||
|
||||
class AvisynthSource : public AbstractSource
|
||||
{
|
||||
public:
|
||||
AvisynthSource(JobObject *jobObject, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences, JobStatus &jobStatus, volatile bool *abort, volatile bool *pause, QSemaphore *semaphorePause, const QString &sourceFile);
|
||||
virtual ~AvisynthSource(void);
|
||||
|
||||
virtual void printVersion(const unsigned int &revision, const bool &modified);
|
||||
virtual bool isVersionSupported(const unsigned int &revision, const bool &modified);
|
||||
|
||||
virtual void flushProcess(QProcess &processInput);
|
||||
|
||||
protected:
|
||||
void checkVersion_init(QList<QRegExp*> &patterns, QStringList &cmdLine);
|
||||
void checkVersion_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &coreVers, unsigned int &revision, bool &modified);
|
||||
|
||||
virtual void checkSourceProperties_init(QList<QRegExp*> &patterns, QStringList &cmdLine);
|
||||
virtual void checkSourceProperties_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &frames, unsigned int &fSizeW, unsigned int &fSizeH, unsigned int &fpsNom, unsigned int &fpsDen);
|
||||
|
||||
virtual const QString &getBinaryPath() { return m_binaryFile; }
|
||||
virtual void buildCommandLine(QStringList &cmdLine);
|
||||
|
||||
const QString m_binaryFile;
|
||||
};
|
152
src/source_vapoursynth.cpp
Normal file
152
src/source_vapoursynth.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Simple x264 Launcher
|
||||
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// http://www.gnu.org/licenses/gpl-2.0.txt
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "source_vapoursynth.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "model_preferences.h"
|
||||
#include "binaries.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QProcess>
|
||||
|
||||
static const unsigned int VER_X264_VSPIPE_VER = 242;
|
||||
|
||||
VapoursynthSource::VapoursynthSource(JobObject *jobObject, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences, JobStatus &jobStatus, volatile bool *abort, volatile bool *pause, QSemaphore *semaphorePause, const QString &sourceFile)
|
||||
:
|
||||
AbstractSource(jobObject, options, sysinfo, preferences, jobStatus, abort, pause, semaphorePause, sourceFile),
|
||||
m_binaryFile(VPS_BINARY(m_sysinfo, m_preferences))
|
||||
{
|
||||
/*Nothing to do here*/
|
||||
}
|
||||
|
||||
VapoursynthSource::~VapoursynthSource(void)
|
||||
{
|
||||
/*Nothing to do here*/
|
||||
}
|
||||
|
||||
void VapoursynthSource::checkVersion_init(QList<QRegExp*> &patterns, QStringList &cmdLine)
|
||||
{
|
||||
cmdLine << "--version";
|
||||
patterns << new QRegExp("\\bAvs2YUV (\\d+).(\\d+)bm(\\d)\\b", Qt::CaseInsensitive);
|
||||
patterns << new QRegExp("\\bAvs2YUV (\\d+).(\\d+)\\b", Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
void VapoursynthSource::checkVersion_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &coreVers, unsigned int &revision, bool &modified)
|
||||
{
|
||||
int offset = -1;
|
||||
if((offset = patterns[0]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
bool ok1 = false, ok2 = false;
|
||||
unsigned int temp1 = patterns[0]->cap(2).toUInt(&ok1);
|
||||
unsigned int temp2 = patterns[0]->cap(3).toUInt(&ok2);
|
||||
if(ok1) coreVers = temp1;
|
||||
if(ok2) revision = temp2;
|
||||
}
|
||||
else if((offset = patterns[1]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
bool ok1 = false, ok2 = false;
|
||||
unsigned int temp1 = patterns[1]->cap(2).toUInt(&ok1);
|
||||
unsigned int temp2 = patterns[1]->cap(3).toUInt(&ok2);
|
||||
if(ok1) coreVers = temp1;
|
||||
if(ok2) revision = temp2;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
void VapoursynthSource::printVersion(const unsigned int &revision, const bool &modified)
|
||||
{
|
||||
log(tr("Avs2YUV version: %1.%2.%3").arg(QString::number(revision / REV_MULT), QString::number((revision % REV_MULT) / 10),QString::number((revision % REV_MULT) % 10)));
|
||||
}
|
||||
|
||||
bool VapoursynthSource::isVersionSupported(const unsigned int &revision, const bool &modified)
|
||||
{
|
||||
if((revision != UINT_MAX) && ((revision % REV_MULT) != VER_X264_VSPIPE_VER))
|
||||
{
|
||||
log(tr("\nERROR: Your version of avs2yuv is unsupported (Required version: v0.24 BugMaster's mod 2)"));
|
||||
log(tr("You can find the required version at: http://komisar.gin.by/tools/avs2yuv/"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VapoursynthSource::checkSourceProperties_init(QList<QRegExp*> &patterns, QStringList &cmdLine)
|
||||
{
|
||||
cmdLine << QDir::toNativeSeparators(x264_path2ansi(m_sourceFile, true));
|
||||
cmdLine << "-" << "-info";
|
||||
|
||||
patterns << new QRegExp("\\bFrames:\\s+(\\d+)\\b");
|
||||
patterns << new QRegExp("\\bWidth:\\s+(\\d+)\\b");
|
||||
patterns << new QRegExp("\\bHeight:\\s+(\\d+)\\b");
|
||||
}
|
||||
|
||||
void VapoursynthSource::checkSourceProperties_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &frames, unsigned int &fSizeW, unsigned int &fSizeH, unsigned int &fpsNom, unsigned int &fpsDen)
|
||||
{
|
||||
int offset = -1;
|
||||
if((offset = patterns[0]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
bool ok = false;
|
||||
unsigned int temp = patterns[0]->cap(1).toUInt(&ok);
|
||||
if(ok) frames = temp;
|
||||
}
|
||||
if((offset = patterns[1]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
bool ok = false;
|
||||
unsigned int temp =patterns[1]->cap(1).toUInt(&ok);
|
||||
if(ok) fSizeW = temp;
|
||||
}
|
||||
if((offset = patterns[2]->lastIndexIn(line)) >= 0)
|
||||
{
|
||||
bool ok = false;
|
||||
unsigned int temp = patterns[2]->cap(1).toUInt(&ok);
|
||||
if(ok) fSizeH = temp;
|
||||
}
|
||||
if(!line.isEmpty())
|
||||
{
|
||||
log(line);
|
||||
}
|
||||
}
|
||||
|
||||
void VapoursynthSource::buildCommandLine(QStringList &cmdLine)
|
||||
{
|
||||
cmdLine << QDir::toNativeSeparators(x264_path2ansi(m_sourceFile, true));
|
||||
cmdLine << "-" << "-y4m";
|
||||
}
|
||||
|
||||
void VapoursynthSource::flushProcess(QProcess &processInput)
|
||||
{
|
||||
while(processInput.bytesAvailable() > 0)
|
||||
{
|
||||
log(tr("vpyp [info]: %1").arg(QString::fromUtf8(processInput.readLine()).simplified()));
|
||||
}
|
||||
|
||||
if(processInput.exitCode() != EXIT_SUCCESS)
|
||||
{
|
||||
const int exitCode = processInput.exitCode();
|
||||
log(tr("\nWARNING: Input process exited with error (code: %1), your encode might be *incomplete* !!!").arg(QString::number(exitCode)));
|
||||
if((exitCode < 0) || (exitCode >= 32))
|
||||
{
|
||||
log(tr("\nIMPORTANT: The Vapoursynth process terminated abnormally. This means Vapoursynth or one of your Vapoursynth-Plugin's just crashed."));
|
||||
}
|
||||
}
|
||||
}
|
48
src/source_vapoursynth.h
Normal file
48
src/source_vapoursynth.h
Normal file
@ -0,0 +1,48 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Simple x264 Launcher
|
||||
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// http://www.gnu.org/licenses/gpl-2.0.txt
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "source_abstract.h"
|
||||
|
||||
class VapoursynthSource : public AbstractSource
|
||||
{
|
||||
public:
|
||||
VapoursynthSource(JobObject *jobObject, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences, JobStatus &jobStatus, volatile bool *abort, volatile bool *pause, QSemaphore *semaphorePause, const QString &sourceFile);
|
||||
virtual ~VapoursynthSource(void);
|
||||
|
||||
virtual void printVersion(const unsigned int &revision, const bool &modified);
|
||||
virtual bool isVersionSupported(const unsigned int &revision, const bool &modified);
|
||||
|
||||
virtual void flushProcess(QProcess &processInput);
|
||||
|
||||
protected:
|
||||
void checkVersion_init(QList<QRegExp*> &patterns, QStringList &cmdLine);
|
||||
void checkVersion_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &coreVers, unsigned int &revision, bool &modified);
|
||||
|
||||
virtual void checkSourceProperties_init(QList<QRegExp*> &patterns, QStringList &cmdLine);
|
||||
virtual void checkSourceProperties_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &frames, unsigned int &fSizeW, unsigned int &fSizeH, unsigned int &fpsNom, unsigned int &fpsDen);
|
||||
|
||||
virtual const QString &getBinaryPath() { return m_binaryFile; }
|
||||
virtual void buildCommandLine(QStringList &cmdLine);
|
||||
|
||||
const QString m_binaryFile;
|
||||
};
|
@ -21,15 +21,23 @@
|
||||
|
||||
#include "thread_encode.h"
|
||||
|
||||
//Internal
|
||||
#include "global.h"
|
||||
#include "model_options.h"
|
||||
#include "model_preferences.h"
|
||||
#include "model_sysinfo.h"
|
||||
#include "encoder_x264.h"
|
||||
#include "encoder_x265.h"
|
||||
#include "job_object.h"
|
||||
#include "binaries.h"
|
||||
|
||||
//Encoders
|
||||
#include "encoder_x264.h"
|
||||
#include "encoder_x265.h"
|
||||
|
||||
//Source
|
||||
#include "source_avisynth.h"
|
||||
#include "source_vapoursynth.h"
|
||||
|
||||
//Qt Framework
|
||||
#include <QDate>
|
||||
#include <QTime>
|
||||
#include <QDateTime>
|
||||
@ -86,10 +94,20 @@ private:
|
||||
} \
|
||||
while(0)
|
||||
|
||||
/*
|
||||
* Input types
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
INPUT_NATIVE = 0,
|
||||
INPUT_AVISYN = 1,
|
||||
INPUT_VAPOUR = 2
|
||||
};
|
||||
|
||||
/*
|
||||
* Static vars
|
||||
*/
|
||||
static const char *VPS_TEST_FILE = "import vapoursynth as vs\ncore = vs.get_core()\nv = core.std.BlankClip()\nv.set_output()\n";
|
||||
//static const char *VPS_TEST_FILE = "import vapoursynth as vs\ncore = vs.get_core()\nv = core.std.BlankClip()\nv.set_output()\n";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor & Destructor
|
||||
@ -104,7 +122,9 @@ EncodeThread::EncodeThread(const QString &sourceFileName, const QString &outputF
|
||||
m_sysinfo(sysinfo),
|
||||
m_preferences(preferences),
|
||||
m_jobObject(new JobObject),
|
||||
m_semaphorePaused(0)
|
||||
m_semaphorePaused(0),
|
||||
m_encoder(NULL),
|
||||
m_pipedSource(NULL)
|
||||
{
|
||||
m_abort = false;
|
||||
m_pause = false;
|
||||
@ -122,11 +142,29 @@ EncodeThread::EncodeThread(const QString &sourceFileName, const QString &outputF
|
||||
throw "Unknown encoder type encountered!";
|
||||
}
|
||||
|
||||
//Create input handler object
|
||||
switch(getInputType(QFileInfo(m_sourceFileName).suffix()))
|
||||
{
|
||||
case INPUT_AVISYN:
|
||||
m_pipedSource = new AvisynthSource (m_jobObject, m_options, m_sysinfo, m_preferences, m_status, &m_abort, &m_pause, &m_semaphorePaused, m_sourceFileName);
|
||||
break;
|
||||
case INPUT_VAPOUR:
|
||||
m_pipedSource = new VapoursynthSource(m_jobObject, m_options, m_sysinfo, m_preferences, m_status, &m_abort, &m_pause, &m_semaphorePaused, m_sourceFileName);
|
||||
break;
|
||||
}
|
||||
|
||||
//Establish connections
|
||||
connect(m_encoder, SIGNAL(statusChanged(JobStatus)), this, SIGNAL(setStatus(QString)), Qt::DirectConnection);
|
||||
connect(m_encoder, SIGNAL(progressChanged(unsigned int)), this, SIGNAL(setProgress(QString)), Qt::DirectConnection);
|
||||
connect(m_encoder, SIGNAL(messageLogged(QString)), this, SIGNAL(log(QString)), Qt::DirectConnection);
|
||||
connect(m_encoder, SIGNAL(detailsChanged(QString)), this, SIGNAL(setDetails(QString)), Qt::DirectConnection);
|
||||
if(m_pipedSource)
|
||||
{
|
||||
connect(m_pipedSource, SIGNAL(statusChanged(JobStatus)), this, SIGNAL(setStatus(QString)), Qt::DirectConnection);
|
||||
connect(m_pipedSource, SIGNAL(progressChanged(unsigned int)), this, SIGNAL(setProgress(QString)), Qt::DirectConnection);
|
||||
connect(m_pipedSource, SIGNAL(messageLogged(QString)), this, SIGNAL(log(QString)), Qt::DirectConnection);
|
||||
connect(m_pipedSource, SIGNAL(detailsChanged(QString)), this, SIGNAL(setDetails(QString)), Qt::DirectConnection);
|
||||
}
|
||||
}
|
||||
|
||||
EncodeThread::~EncodeThread(void)
|
||||
@ -237,9 +275,6 @@ void EncodeThread::encode(void)
|
||||
bool ok = false;
|
||||
unsigned int frames = 0;
|
||||
|
||||
//Seletct type of input
|
||||
const int inputType = getInputType(QFileInfo(m_sourceFileName).suffix());
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Check Versions
|
||||
// -----------------------------------------------------------------------------------
|
||||
@ -248,26 +283,11 @@ void EncodeThread::encode(void)
|
||||
|
||||
//Check encoder version
|
||||
bool encoderModified = false;
|
||||
unsigned int encoderRevision = m_encoder->checkVersion(encoderModified);
|
||||
const unsigned int encoderRevision = m_encoder->checkVersion(encoderModified);
|
||||
CHECK_STATUS(m_abort, (ok = (encoderRevision != UINT_MAX)));
|
||||
|
||||
//Checking avs2yuv version
|
||||
unsigned int revision_avs2yuv = UINT_MAX;
|
||||
switch(inputType)
|
||||
{
|
||||
case INPUT_NATIVE: break;
|
||||
case INPUT_AVISYN: ok = ((revision_avs2yuv = checkVersionAvs2yuv()) != UINT_MAX); break;
|
||||
case INPUT_VAPOUR: ok = checkVersionVapoursynth(); break;
|
||||
default: throw "Invalid input type!";
|
||||
}
|
||||
CHECK_STATUS(m_abort, ok);
|
||||
|
||||
//Print versions
|
||||
//Print source versions
|
||||
m_encoder->printVersion(encoderRevision, encoderModified);
|
||||
if(revision_avs2yuv != UINT_MAX)
|
||||
{
|
||||
log(tr("Avs2YUV version: %1.%2.%3").arg(QString::number(revision_avs2yuv / REV_MULT), QString::number((revision_avs2yuv % REV_MULT) / 10),QString::number((revision_avs2yuv % REV_MULT) % 10)));
|
||||
}
|
||||
|
||||
//Is encoder version suppoprted?
|
||||
if(!m_encoder->isVersionSupported(encoderRevision, encoderModified))
|
||||
@ -276,72 +296,149 @@ void EncodeThread::encode(void)
|
||||
return;
|
||||
}
|
||||
|
||||
//Is Avs2YUV version supported?
|
||||
if((revision_avs2yuv != UINT_MAX) && ((revision_avs2yuv % REV_MULT) != x264_version_x264_avs2yuv_ver()))
|
||||
if(m_pipedSource)
|
||||
{
|
||||
//Checking source version
|
||||
bool sourceModified = false;
|
||||
const unsigned int sourceRevision = m_pipedSource->checkVersion(sourceModified);
|
||||
CHECK_STATUS(m_abort, (ok = (sourceRevision != UINT_MAX)));
|
||||
|
||||
//Print source versions
|
||||
m_pipedSource->printVersion(sourceModified, sourceModified);
|
||||
|
||||
//Is source version supported?
|
||||
if(!m_pipedSource->isVersionSupported(sourceRevision, sourceModified))
|
||||
{
|
||||
log(tr("\nERROR: Your version of avs2yuv is unsupported (Required version: v0.24 BugMaster's mod 2)"));
|
||||
log(tr("You can find the required version at: http://komisar.gin.by/tools/avs2yuv/"));
|
||||
setStatus(JobStatus_Failed);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Detect Source Info
|
||||
// -----------------------------------------------------------------------------------
|
||||
|
||||
//Detect source info
|
||||
if(inputType != INPUT_NATIVE)
|
||||
if(m_pipedSource)
|
||||
{
|
||||
log(tr("\n--- SOURCE INFO ---\n"));
|
||||
switch(inputType)
|
||||
{
|
||||
case INPUT_AVISYN:
|
||||
ok = checkPropertiesAVS(frames);
|
||||
log(tr("\n--- GET SOURCE INFO ---\n"));
|
||||
ok = m_pipedSource->checkSourceProperties(frames);
|
||||
CHECK_STATUS(m_abort, ok);
|
||||
break;
|
||||
case INPUT_VAPOUR:
|
||||
ok = checkPropertiesVPS(frames);
|
||||
CHECK_STATUS(m_abort, ok);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Encoding Passes
|
||||
// -----------------------------------------------------------------------------------
|
||||
|
||||
//Run encoding passes
|
||||
if(m_options->rcMode() == OptionsModel::RCMode_2Pass)
|
||||
{
|
||||
QFileInfo info(m_outputFileName);
|
||||
QString passLogFile = QString("%1/%2.stats").arg(info.path(), info.completeBaseName());
|
||||
const QString passLogFile = getPasslogFile(m_outputFileName);
|
||||
|
||||
if(QFileInfo(passLogFile).exists())
|
||||
{
|
||||
int n = 2;
|
||||
while(QFileInfo(passLogFile).exists())
|
||||
{
|
||||
passLogFile = QString("%1/%2.%3.stats").arg(info.path(), info.completeBaseName(), QString::number(n++));
|
||||
}
|
||||
}
|
||||
|
||||
log(tr("\n--- PASS 1 ---\n"));
|
||||
ok = runEncodingPass(inputType, frames, indexFile, 1, passLogFile);
|
||||
log(tr("\n--- ENCODING PASS #1 ---\n"));
|
||||
ok = m_encoder->runEncodingPass(m_pipedSource, m_outputFileName, frames, 1, passLogFile);
|
||||
CHECK_STATUS(m_abort, ok);
|
||||
|
||||
log(tr("\n--- PASS 2 ---\n"));
|
||||
ok = runEncodingPass(inputType, frames, indexFile, 2, passLogFile);
|
||||
log(tr("\n--- ENCODING PASS #2 ---\n"));
|
||||
ok = m_encoder->runEncodingPass(m_pipedSource, m_outputFileName, frames, 2, passLogFile);
|
||||
CHECK_STATUS(m_abort, ok);
|
||||
}
|
||||
else
|
||||
{
|
||||
log(tr("\n--- ENCODING ---\n"));
|
||||
ok = runEncodingPass(inputType, frames, indexFile);
|
||||
log(tr("\n--- ENCODING VIDEO ---\n"));
|
||||
ok = m_encoder->runEncodingPass(m_pipedSource, m_outputFileName, frames);
|
||||
CHECK_STATUS(m_abort, ok);
|
||||
}
|
||||
|
||||
log(tr("\n--- DONE ---\n"));
|
||||
// -----------------------------------------------------------------------------------
|
||||
// Encoding complete
|
||||
// -----------------------------------------------------------------------------------
|
||||
|
||||
log(tr("\n--- COMPLETED ---\n"));
|
||||
|
||||
int timePassed = startTime.secsTo(QDateTime::currentDateTime());
|
||||
log(tr("Job finished at %1, %2. Process took %3 minutes, %4 seconds.").arg(QDate::currentDate().toString(Qt::ISODate), QTime::currentTime().toString(Qt::ISODate), QString::number(timePassed / 60), QString::number(timePassed % 60)));
|
||||
setStatus(JobStatus_Completed);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Misc functions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EncodeThread::log(const QString &text)
|
||||
{
|
||||
emit messageLogged(m_jobId, text);
|
||||
}
|
||||
|
||||
void EncodeThread::setStatus(const JobStatus &newStatus)
|
||||
{
|
||||
if(m_status != newStatus)
|
||||
{
|
||||
if((newStatus != JobStatus_Completed) && (newStatus != JobStatus_Failed) && (newStatus != JobStatus_Aborted) && (newStatus != JobStatus_Paused))
|
||||
{
|
||||
if(m_status != JobStatus_Paused) setProgress(0);
|
||||
}
|
||||
if(newStatus == JobStatus_Failed)
|
||||
{
|
||||
setDetails("The job has failed. See log for details!");
|
||||
}
|
||||
if(newStatus == JobStatus_Aborted)
|
||||
{
|
||||
setDetails("The job was aborted by the user!");
|
||||
}
|
||||
m_status = newStatus;
|
||||
emit statusChanged(m_jobId, newStatus);
|
||||
}
|
||||
}
|
||||
|
||||
void EncodeThread::setProgress(const unsigned int &newProgress)
|
||||
{
|
||||
if(m_progress != newProgress)
|
||||
{
|
||||
m_progress = newProgress;
|
||||
emit progressChanged(m_jobId, m_progress);
|
||||
}
|
||||
}
|
||||
|
||||
void EncodeThread::setDetails(const QString &text)
|
||||
{
|
||||
emit detailsChanged(m_jobId, text);
|
||||
}
|
||||
|
||||
int EncodeThread::getInputType(const QString &fileExt)
|
||||
{
|
||||
int type = INPUT_NATIVE;
|
||||
|
||||
if(fileExt.compare("avs", Qt::CaseInsensitive) == 0) type = INPUT_AVISYN;
|
||||
if(fileExt.compare("avsi", Qt::CaseInsensitive) == 0) type = INPUT_AVISYN;
|
||||
if(fileExt.compare("vpy", Qt::CaseInsensitive) == 0) type = INPUT_VAPOUR;
|
||||
if(fileExt.compare("py", Qt::CaseInsensitive) == 0) type = INPUT_VAPOUR;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
QString EncodeThread::getPasslogFile(const QString &outputFile)
|
||||
{
|
||||
QFileInfo info(outputFile);
|
||||
QString passLogFile = QString("%1/%2.stats").arg(info.absolutePath(), info.completeBaseName());
|
||||
int counter = 1;
|
||||
|
||||
while(QFileInfo(passLogFile).exists())
|
||||
{
|
||||
passLogFile = QString("%1/%2_%3.stats").arg(info.absolutePath(), info.completeBaseName(), QString::number(++counter));
|
||||
}
|
||||
|
||||
return passLogFile;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ==========================================
|
||||
// DISABLED
|
||||
// ==========================================
|
||||
|
||||
/*
|
||||
unsigned int EncodeThread::checkVersionAvs2yuv(void)
|
||||
{
|
||||
if(!m_sysinfo->hasAVSSupport())
|
||||
@ -844,57 +941,4 @@ bool EncodeThread::checkPropertiesVPS(unsigned int &frames)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Misc functions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EncodeThread::log(const QString &text)
|
||||
{
|
||||
emit messageLogged(m_jobId, text);
|
||||
}
|
||||
|
||||
void EncodeThread::setStatus(const JobStatus &newStatus)
|
||||
{
|
||||
if(m_status != newStatus)
|
||||
{
|
||||
if((newStatus != JobStatus_Completed) && (newStatus != JobStatus_Failed) && (newStatus != JobStatus_Aborted) && (newStatus != JobStatus_Paused))
|
||||
{
|
||||
if(m_status != JobStatus_Paused) setProgress(0);
|
||||
}
|
||||
if(newStatus == JobStatus_Failed)
|
||||
{
|
||||
setDetails("The job has failed. See log for details!");
|
||||
}
|
||||
if(newStatus == JobStatus_Aborted)
|
||||
{
|
||||
setDetails("The job was aborted by the user!");
|
||||
}
|
||||
m_status = newStatus;
|
||||
emit statusChanged(m_jobId, newStatus);
|
||||
}
|
||||
}
|
||||
|
||||
void EncodeThread::setProgress(const unsigned int &newProgress)
|
||||
{
|
||||
if(m_progress != newProgress)
|
||||
{
|
||||
m_progress = newProgress;
|
||||
emit progressChanged(m_jobId, m_progress);
|
||||
}
|
||||
}
|
||||
|
||||
void EncodeThread::setDetails(const QString &text)
|
||||
{
|
||||
emit detailsChanged(m_jobId, text);
|
||||
}
|
||||
|
||||
int EncodeThread::getInputType(const QString &fileExt)
|
||||
{
|
||||
int type = INPUT_NATIVE;
|
||||
if(fileExt.compare("avs", Qt::CaseInsensitive) == 0) type = INPUT_AVISYN;
|
||||
else if(fileExt.compare("avsi", Qt::CaseInsensitive) == 0) type = INPUT_AVISYN;
|
||||
else if(fileExt.compare("vpy", Qt::CaseInsensitive) == 0) type = INPUT_VAPOUR;
|
||||
else if(fileExt.compare("py", Qt::CaseInsensitive) == 0) type = INPUT_VAPOUR;
|
||||
return type;
|
||||
}
|
||||
*/
|
||||
|
@ -35,6 +35,7 @@ class OptionsModel;
|
||||
class QProcess;
|
||||
class JobObject;
|
||||
class AbstractEncoder;
|
||||
class AbstractSource;
|
||||
|
||||
class EncodeThread : public QThread
|
||||
{
|
||||
@ -74,17 +75,9 @@ protected:
|
||||
|
||||
//Constants
|
||||
const QUuid m_jobId;
|
||||
const OptionsModel *m_options;
|
||||
const QString m_sourceFileName;
|
||||
const QString m_outputFileName;
|
||||
const OptionsModel *m_options;
|
||||
|
||||
//Types
|
||||
enum inputType_t
|
||||
{
|
||||
INPUT_NATIVE = 0,
|
||||
INPUT_AVISYN = 1,
|
||||
INPUT_VAPOUR = 2
|
||||
};
|
||||
|
||||
//Flags
|
||||
volatile bool m_abort;
|
||||
@ -102,26 +95,18 @@ protected:
|
||||
|
||||
//Encoder and Source objects
|
||||
AbstractEncoder *m_encoder;
|
||||
AbstractSource *m_pipedSource;
|
||||
|
||||
//Entry point
|
||||
virtual void run(void);
|
||||
virtual void checkedRun(void);
|
||||
|
||||
//Encode functions
|
||||
//Main encoding functions
|
||||
void encode(void);
|
||||
bool runEncodingPass(const int &inputType, const unsigned int &frames, const QString &indexFile, const int &pass = 0, const QString &passLogFile = QString());
|
||||
QStringList buildCommandLine(const bool &usePipe, const unsigned int &frames, const QString &indexFile, const int &pass = 0, const QString &passLogFile = QString());
|
||||
unsigned int checkVersionAvs2yuv(void);
|
||||
bool checkVersionVapoursynth(void);
|
||||
bool checkPropertiesAVS(unsigned int &frames);
|
||||
bool checkPropertiesVPS(unsigned int &frames);
|
||||
|
||||
//Auxiallary Stuff
|
||||
//QStringList splitParams(const QString ¶ms);
|
||||
|
||||
//Static functions
|
||||
static int getInputType(const QString &fileExt);
|
||||
static QString stringToHash(const QString &string);
|
||||
static QString getPasslogFile(const QString &outputFile);
|
||||
|
||||
signals:
|
||||
void statusChanged(const QUuid &jobId, const JobStatus &newStatus);
|
||||
|
@ -49,6 +49,99 @@ AbstractTool::AbstractTool(JobObject *jobObject, const OptionsModel *options, co
|
||||
/*nothing to do here*/
|
||||
}
|
||||
|
||||
unsigned int AbstractTool::checkVersion(bool &modified)
|
||||
{
|
||||
if(m_preferences->getSkipVersionTest())
|
||||
{
|
||||
log("Warning: Skipping the version check this time!");
|
||||
return (999 * REV_MULT) + (REV_MULT-1);
|
||||
}
|
||||
|
||||
QProcess process;
|
||||
QList<QRegExp*> patterns;
|
||||
QStringList cmdLine;
|
||||
|
||||
//Init encoder-specific values
|
||||
checkVersion_init(patterns, cmdLine);
|
||||
|
||||
log("Creating process:");
|
||||
if(!startProcess(process, getBinaryPath(), cmdLine))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bTimeout = false;
|
||||
bool bAborted = false;
|
||||
|
||||
unsigned int revision = UINT_MAX;
|
||||
unsigned int coreVers = UINT_MAX;
|
||||
modified = false;
|
||||
|
||||
while(process.state() != QProcess::NotRunning)
|
||||
{
|
||||
if(m_abort)
|
||||
{
|
||||
process.kill();
|
||||
bAborted = true;
|
||||
break;
|
||||
}
|
||||
if(!process.waitForReadyRead())
|
||||
{
|
||||
if(process.state() == QProcess::Running)
|
||||
{
|
||||
process.kill();
|
||||
qWarning("process timed out <-- killing!");
|
||||
log("\nPROCESS TIMEOUT !!!");
|
||||
bTimeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(process.bytesAvailable() > 0)
|
||||
{
|
||||
QList<QByteArray> lines = process.readLine().split('\r');
|
||||
while(!lines.isEmpty())
|
||||
{
|
||||
const QString text = QString::fromUtf8(lines.takeFirst().constData()).simplified();
|
||||
checkVersion_parseLine(text, patterns, coreVers, revision, modified);
|
||||
if(!text.isEmpty())
|
||||
{
|
||||
log(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process.waitForFinished();
|
||||
if(process.state() != QProcess::NotRunning)
|
||||
{
|
||||
process.kill();
|
||||
process.waitForFinished(-1);
|
||||
}
|
||||
|
||||
while(!patterns.isEmpty())
|
||||
{
|
||||
QRegExp *pattern = patterns.takeFirst();
|
||||
X264_DELETE(pattern);
|
||||
}
|
||||
|
||||
if(bTimeout || bAborted || process.exitCode() != EXIT_SUCCESS)
|
||||
{
|
||||
if(!(bTimeout || bAborted))
|
||||
{
|
||||
log(tr("\nPROCESS EXITED WITH ERROR CODE: %1").arg(QString::number(process.exitCode())));
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
if((revision == UINT_MAX) || (coreVers == UINT_MAX))
|
||||
{
|
||||
log(tr("\nFAILED TO DETERMINE VERSION INFO !!!"));
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
return (coreVers * REV_MULT) + (revision % REV_MULT);
|
||||
}
|
||||
|
||||
bool AbstractTool::startProcess(QProcess &process, const QString &program, const QStringList &args, bool mergeChannels)
|
||||
{
|
||||
QMutexLocker lock(&s_mutexStartProcess);
|
||||
|
@ -41,6 +41,12 @@ public:
|
||||
AbstractTool(JobObject *jobObject, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences, JobStatus &jobStatus, volatile bool *abort, volatile bool *pause, QSemaphore *semaphorePause);
|
||||
virtual ~AbstractTool(void) {/*NOP*/}
|
||||
|
||||
virtual unsigned int checkVersion(bool &modified);
|
||||
virtual bool isVersionSupported(const unsigned int &revision, const bool &modified) = 0;
|
||||
virtual void printVersion(const unsigned int &revision, const bool &modified) = 0;
|
||||
|
||||
static const unsigned int REV_MULT = 10000;
|
||||
|
||||
signals:
|
||||
void statusChanged(const JobStatus &newStatus);
|
||||
void progressChanged(unsigned int newProgress);
|
||||
@ -52,6 +58,11 @@ protected:
|
||||
static const unsigned int m_processTimeoutMaxCounter = 120;
|
||||
static const unsigned int m_processTimeoutWarning = 24;
|
||||
|
||||
virtual const QString &getBinaryPath(void) = 0;
|
||||
|
||||
virtual void checkVersion_init(QList<QRegExp*> &patterns, QStringList &cmdLine) = 0;
|
||||
virtual void checkVersion_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &coreVers, unsigned int &revision, bool &modified) = 0;
|
||||
|
||||
void log(const QString &text) { emit messageLogged(text); }
|
||||
void setStatus(const JobStatus &newStatus) { emit statusChanged(newStatus); }
|
||||
void setProgress(unsigned int newProgress) { emit progressChanged(newProgress); }
|
||||
|
@ -26,9 +26,7 @@
|
||||
#define VER_X264_MAJOR 2
|
||||
#define VER_X264_MINOR 3
|
||||
#define VER_X264_PATCH 2
|
||||
#define VER_X264_BUILD 786
|
||||
|
||||
#define VER_X264_AVS2YUV_VER 242
|
||||
#define VER_X264_BUILD 791
|
||||
|
||||
#define VER_X264_PORTABLE_EDITION (0)
|
||||
|
||||
|
@ -330,6 +330,9 @@ copy /Y "$(QTDIR)\plugins\imageformats\qgif4.dll" "$(TargetDir)\imageformats"
|
||||
<ClInclude Include="src\model_recently.h" />
|
||||
<ClInclude Include="src\model_status.h" />
|
||||
<ClInclude Include="src\model_sysinfo.h" />
|
||||
<ClInclude Include="src\source_abstract.h" />
|
||||
<ClInclude Include="src\source_avisynth.h" />
|
||||
<ClInclude Include="src\source_vapoursynth.h" />
|
||||
<ClInclude Include="src\targetver.h" />
|
||||
<ClInclude Include="src\taskbar7.h" />
|
||||
<CustomBuild Include="src\thread_avisynth.h">
|
||||
@ -356,7 +359,14 @@ copy /Y "$(QTDIR)\plugins\imageformats\qgif4.dll" "$(TargetDir)\imageformats"
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="src\tool_abstract.h" />
|
||||
<CustomBuild Include="src\tool_abstract.h">
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)"</Command>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)"</Command>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MOC "$(SolutionDir)tmp\moc\moc_%(Filename).cpp"</Message>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MOC "$(SolutionDir)tmp\moc\moc_%(Filename).cpp"</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="src\version.h" />
|
||||
<CustomBuild Include="src\win_main.h">
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)"</Command>
|
||||
@ -383,6 +393,9 @@ copy /Y "$(QTDIR)\plugins\imageformats\qgif4.dll" "$(TargetDir)\imageformats"
|
||||
<ClCompile Include="src\model_options.cpp" />
|
||||
<ClCompile Include="src\model_preferences.cpp" />
|
||||
<ClCompile Include="src\model_recently.cpp" />
|
||||
<ClCompile Include="src\source_abstract.cpp" />
|
||||
<ClCompile Include="src\source_avisynth.cpp" />
|
||||
<ClCompile Include="src\source_vapoursynth.cpp" />
|
||||
<ClCompile Include="src\taskbar7.cpp" />
|
||||
<ClCompile Include="src\thread_avisynth.cpp" />
|
||||
<ClCompile Include="src\thread_encode.cpp" />
|
||||
@ -404,6 +417,7 @@ copy /Y "$(QTDIR)\plugins\imageformats\qgif4.dll" "$(TargetDir)\imageformats"
|
||||
<ClCompile Include="tmp\moc\moc_thread_encode.cpp" />
|
||||
<ClCompile Include="tmp\moc\moc_thread_updater.cpp" />
|
||||
<ClCompile Include="tmp\moc\moc_thread_vapoursynth.cpp" />
|
||||
<ClCompile Include="tmp\moc\moc_tool_abstract.cpp" />
|
||||
<ClCompile Include="tmp\moc\moc_win_addJob.cpp" />
|
||||
<ClCompile Include="tmp\moc\moc_win_editor.cpp" />
|
||||
<ClCompile Include="tmp\moc\moc_win_help.cpp" />
|
||||
|
@ -96,6 +96,15 @@
|
||||
<ClInclude Include="src\encoder_x265.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\source_abstract.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\source_avisynth.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\source_vapoursynth.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\main.cpp">
|
||||
@ -227,6 +236,18 @@
|
||||
<ClCompile Include="src\encoder_x265.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\source_abstract.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\source_avisynth.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\source_vapoursynth.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tmp\moc\moc_tool_abstract.cpp">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="src\win_main.h">
|
||||
|
Loading…
Reference in New Issue
Block a user