Refactored source types (Avisynth, VapourSynth, etc) into separate classes + loads of fixes.

This commit is contained in:
LoRd_MuldeR 2014-02-24 23:13:42 +01:00
parent 6164e48604
commit 38e7dbae56
21 changed files with 1139 additions and 335 deletions

View File

@ -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))

View File

@ -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;

View File

@ -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)

View File

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

View File

@ -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);
}
}

View File

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

View File

@ -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
*/

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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;
};

View File

@ -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;
}
*/

View File

@ -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 &params);
//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);

View File

@ -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);

View File

@ -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); }

View File

@ -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)

View File

@ -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" />

View File

@ -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">