1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
22 #include "thread_encode.h"
26 #include "model_options.h"
27 #include "model_preferences.h"
28 #include "model_sysinfo.h"
29 #include "job_object.h"
33 #include "encoder_x264.h"
34 #include "encoder_x265.h"
37 #include "source_avisynth.h"
38 #include "source_vapoursynth.h"
50 #include <QCryptographicHash>
53 * RAII execution state handler
55 class ExecutionStateHandler
58 ExecutionStateHandler(void)
60 x264_set_thread_execution_state(true);
62 ~ExecutionStateHandler(void)
64 x264_set_thread_execution_state(false);
67 //Disable copy constructor and assignment
68 ExecutionStateHandler(const ExecutionStateHandler &other) {}
69 ExecutionStateHandler &operator=(const ExecutionStateHandler &) {}
71 //Prevent object allocation on the heap
72 void *operator new(size_t); void *operator new[](size_t);
73 void operator delete(void *); void operator delete[](void*);
79 #define CHECK_STATUS(ABORT_FLAG, OK_FLAG) do \
83 log("\nPROCESS ABORTED BY USER !!!"); \
84 setStatus(JobStatus_Aborted); \
85 if(QFileInfo(m_outputFileName).exists() && (QFileInfo(m_outputFileName).size() == 0)) QFile::remove(m_outputFileName); \
90 setStatus(JobStatus_Failed); \
91 if(QFileInfo(m_outputFileName).exists() && (QFileInfo(m_outputFileName).size() == 0)) QFile::remove(m_outputFileName); \
110 //static const char *VPS_TEST_FILE = "import vapoursynth as vs\ncore = vs.get_core()\nv = core.std.BlankClip()\nv.set_output()\n";
112 ///////////////////////////////////////////////////////////////////////////////
113 // Constructor & Destructor
114 ///////////////////////////////////////////////////////////////////////////////
116 EncodeThread::EncodeThread(const QString &sourceFileName, const QString &outputFileName, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences)
118 m_jobId(QUuid::createUuid()),
119 m_sourceFileName(sourceFileName),
120 m_outputFileName(outputFileName),
121 m_options(new OptionsModel(*options)),
123 m_preferences(preferences),
124 m_jobObject(new JobObject),
125 m_semaphorePaused(0),
132 //Create encoder object
133 switch(options->encType())
135 case OptionsModel::EncType_X264:
136 m_encoder = new X264Encoder(m_jobObject, m_options, m_sysinfo, m_preferences, m_status, &m_abort, &m_pause, &m_semaphorePaused, m_sourceFileName, m_outputFileName);
138 case OptionsModel::EncType_X265:
139 m_encoder = new X265Encoder(m_jobObject, m_options, m_sysinfo, m_preferences, m_status, &m_abort, &m_pause, &m_semaphorePaused, m_sourceFileName, m_outputFileName);
142 throw "Unknown encoder type encountered!";
145 //Create input handler object
146 switch(getInputType(QFileInfo(m_sourceFileName).suffix()))
149 m_pipedSource = new AvisynthSource (m_jobObject, m_options, m_sysinfo, m_preferences, m_status, &m_abort, &m_pause, &m_semaphorePaused, m_sourceFileName);
152 m_pipedSource = new VapoursynthSource(m_jobObject, m_options, m_sysinfo, m_preferences, m_status, &m_abort, &m_pause, &m_semaphorePaused, m_sourceFileName);
156 //Establish connections
157 connect(m_encoder, SIGNAL(statusChanged(JobStatus)), this, SIGNAL(setStatus(QString)), Qt::DirectConnection);
158 connect(m_encoder, SIGNAL(progressChanged(unsigned int)), this, SIGNAL(setProgress(QString)), Qt::DirectConnection);
159 connect(m_encoder, SIGNAL(messageLogged(QString)), this, SIGNAL(log(QString)), Qt::DirectConnection);
160 connect(m_encoder, SIGNAL(detailsChanged(QString)), this, SIGNAL(setDetails(QString)), Qt::DirectConnection);
163 connect(m_pipedSource, SIGNAL(statusChanged(JobStatus)), this, SIGNAL(setStatus(QString)), Qt::DirectConnection);
164 connect(m_pipedSource, SIGNAL(progressChanged(unsigned int)), this, SIGNAL(setProgress(QString)), Qt::DirectConnection);
165 connect(m_pipedSource, SIGNAL(messageLogged(QString)), this, SIGNAL(log(QString)), Qt::DirectConnection);
166 connect(m_pipedSource, SIGNAL(detailsChanged(QString)), this, SIGNAL(setDetails(QString)), Qt::DirectConnection);
170 EncodeThread::~EncodeThread(void)
172 X264_DELETE(m_encoder);
173 X264_DELETE(m_jobObject);
174 X264_DELETE(m_options);
177 ///////////////////////////////////////////////////////////////////////////////
178 // Thread entry point
179 ///////////////////////////////////////////////////////////////////////////////
181 void EncodeThread::run(void)
190 qWarning("STRUCTURED EXCEPTION ERROR IN ENCODE THREAD !!!");
198 m_jobObject->terminateJob(42);
199 X264_DELETE(m_jobObject);
203 void EncodeThread::checkedRun(void)
206 m_status = JobStatus_Starting;
212 ExecutionStateHandler executionStateHandler;
217 log(tr("EXCEPTION ERROR IN THREAD: ").append(QString::fromLatin1(msg)));
218 setStatus(JobStatus_Failed);
222 log(tr("UNHANDLED EXCEPTION ERROR IN THREAD !!!"));
223 setStatus(JobStatus_Failed);
228 x264_fatal_exit(L"Unhandeled exception error in encode thread!");
232 void EncodeThread::start(Priority priority)
234 qDebug("Thread starting...");
239 while(m_semaphorePaused.tryAcquire(1, 0));
240 QThread::start(priority);
243 ///////////////////////////////////////////////////////////////////////////////
245 ///////////////////////////////////////////////////////////////////////////////
247 void EncodeThread::encode(void)
249 QDateTime startTime = QDateTime::currentDateTime();
251 // -----------------------------------------------------------------------------------
253 // -----------------------------------------------------------------------------------
255 //Print some basic info
256 log(tr("Simple x264 Launcher (Build #%1), built %2\n").arg(QString::number(x264_version_build()), x264_version_date().toString(Qt::ISODate)));
257 log(tr("Job started at %1, %2.\n").arg(QDate::currentDate().toString(Qt::ISODate), QTime::currentTime().toString( Qt::ISODate)));
258 log(tr("Source file: %1").arg(QDir::toNativeSeparators(m_sourceFileName)));
259 log(tr("Output file: %1").arg(QDir::toNativeSeparators(m_outputFileName)));
262 log(tr("\n--- SYSTEMINFO ---\n"));
263 log(tr("Binary Path: %1").arg(QDir::toNativeSeparators(m_sysinfo->getAppPath())));
264 log(tr("Avisynth OK: %1").arg(m_sysinfo->hasAVSSupport() ? tr("Yes") : tr("No")));
265 log(tr("VapourSynth: %1").arg(m_sysinfo->hasVPSSupport() ? QDir::toNativeSeparators(m_sysinfo->getVPSPath()) : tr("N/A")));
267 //Print encoder settings
268 log(tr("\n--- SETTINGS ---\n"));
269 log(tr("RC Mode: %1").arg(OptionsModel::rcMode2String(m_options->rcMode())));
270 log(tr("Preset: %1").arg(m_options->preset()));
271 log(tr("Tuning: %1").arg(m_options->tune()));
272 log(tr("Profile: %1").arg(m_options->profile()));
273 log(tr("Custom: %1").arg(m_options->customEncParams().isEmpty() ? tr("(None)") : m_options->customEncParams()));
276 unsigned int frames = 0;
278 // -----------------------------------------------------------------------------------
280 // -----------------------------------------------------------------------------------
282 log(tr("\n--- CHECK VERSION ---\n"));
284 //Check encoder version
285 bool encoderModified = false;
286 const unsigned int encoderRevision = m_encoder->checkVersion(encoderModified);
287 CHECK_STATUS(m_abort, (ok = (encoderRevision != UINT_MAX)));
289 //Print source versions
290 m_encoder->printVersion(encoderRevision, encoderModified);
292 //Is encoder version suppoprted?
293 if(!m_encoder->isVersionSupported(encoderRevision, encoderModified))
295 setStatus(JobStatus_Failed);
301 //Checking source version
302 bool sourceModified = false;
303 const unsigned int sourceRevision = m_pipedSource->checkVersion(sourceModified);
304 CHECK_STATUS(m_abort, (ok = (sourceRevision != UINT_MAX)));
306 //Print source versions
307 m_pipedSource->printVersion(sourceModified, sourceModified);
309 //Is source version supported?
310 if(!m_pipedSource->isVersionSupported(sourceRevision, sourceModified))
312 setStatus(JobStatus_Failed);
317 // -----------------------------------------------------------------------------------
318 // Detect Source Info
319 // -----------------------------------------------------------------------------------
324 log(tr("\n--- GET SOURCE INFO ---\n"));
325 ok = m_pipedSource->checkSourceProperties(frames);
326 CHECK_STATUS(m_abort, ok);
329 // -----------------------------------------------------------------------------------
331 // -----------------------------------------------------------------------------------
333 //Run encoding passes
334 if(m_options->rcMode() == OptionsModel::RCMode_2Pass)
336 const QString passLogFile = getPasslogFile(m_outputFileName);
338 log(tr("\n--- ENCODING PASS #1 ---\n"));
339 ok = m_encoder->runEncodingPass(m_pipedSource, m_outputFileName, frames, 1, passLogFile);
340 CHECK_STATUS(m_abort, ok);
342 log(tr("\n--- ENCODING PASS #2 ---\n"));
343 ok = m_encoder->runEncodingPass(m_pipedSource, m_outputFileName, frames, 2, passLogFile);
344 CHECK_STATUS(m_abort, ok);
348 log(tr("\n--- ENCODING VIDEO ---\n"));
349 ok = m_encoder->runEncodingPass(m_pipedSource, m_outputFileName, frames);
350 CHECK_STATUS(m_abort, ok);
353 // -----------------------------------------------------------------------------------
355 // -----------------------------------------------------------------------------------
357 log(tr("\n--- COMPLETED ---\n"));
359 int timePassed = startTime.secsTo(QDateTime::currentDateTime());
360 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)));
361 setStatus(JobStatus_Completed);
364 ///////////////////////////////////////////////////////////////////////////////
366 ///////////////////////////////////////////////////////////////////////////////
368 void EncodeThread::log(const QString &text)
370 emit messageLogged(m_jobId, text);
373 void EncodeThread::setStatus(const JobStatus &newStatus)
375 if(m_status != newStatus)
377 if((newStatus != JobStatus_Completed) && (newStatus != JobStatus_Failed) && (newStatus != JobStatus_Aborted) && (newStatus != JobStatus_Paused))
379 if(m_status != JobStatus_Paused) setProgress(0);
381 if(newStatus == JobStatus_Failed)
383 setDetails("The job has failed. See log for details!");
385 if(newStatus == JobStatus_Aborted)
387 setDetails("The job was aborted by the user!");
389 m_status = newStatus;
390 emit statusChanged(m_jobId, newStatus);
394 void EncodeThread::setProgress(const unsigned int &newProgress)
396 if(m_progress != newProgress)
398 m_progress = newProgress;
399 emit progressChanged(m_jobId, m_progress);
403 void EncodeThread::setDetails(const QString &text)
405 emit detailsChanged(m_jobId, text);
408 int EncodeThread::getInputType(const QString &fileExt)
410 int type = INPUT_NATIVE;
412 if(fileExt.compare("avs", Qt::CaseInsensitive) == 0) type = INPUT_AVISYN;
413 if(fileExt.compare("avsi", Qt::CaseInsensitive) == 0) type = INPUT_AVISYN;
414 if(fileExt.compare("vpy", Qt::CaseInsensitive) == 0) type = INPUT_VAPOUR;
415 if(fileExt.compare("py", Qt::CaseInsensitive) == 0) type = INPUT_VAPOUR;
420 QString EncodeThread::getPasslogFile(const QString &outputFile)
422 QFileInfo info(outputFile);
423 QString passLogFile = QString("%1/%2.stats").arg(info.absolutePath(), info.completeBaseName());
426 while(QFileInfo(passLogFile).exists())
428 passLogFile = QString("%1/%2_%3.stats").arg(info.absolutePath(), info.completeBaseName(), QString::number(++counter));
437 // ==========================================
439 // ==========================================
442 unsigned int EncodeThread::checkVersionAvs2yuv(void)
444 if(!m_sysinfo->hasAVSSupport())
446 log(tr("\nAVS INPUT REQUIRES VAPOURSYNTH, BUT IT IS *NOT* AVAILABLE !!!"));
452 log("\nCreating process:");
453 if(!startProcess(process, AVS_BINARY(m_sysinfo, m_preferences), QStringList()))
458 QRegExp regExpVersionMod("\\bAvs2YUV (\\d+).(\\d+)bm(\\d)\\b", Qt::CaseInsensitive);
459 QRegExp regExpVersionOld("\\bAvs2YUV (\\d+).(\\d+)\\b", Qt::CaseInsensitive);
461 bool bTimeout = false;
462 bool bAborted = false;
464 unsigned int ver_maj = UINT_MAX;
465 unsigned int ver_min = UINT_MAX;
466 unsigned int ver_mod = 0;
468 while(process.state() != QProcess::NotRunning)
476 if(!process.waitForReadyRead())
478 if(process.state() == QProcess::Running)
481 qWarning("Avs2YUV process timed out <-- killing!");
482 log("\nPROCESS TIMEOUT !!!");
487 while(process.bytesAvailable() > 0)
489 QList<QByteArray> lines = process.readLine().split('\r');
490 while(!lines.isEmpty())
492 QString text = QString::fromUtf8(lines.takeFirst().constData()).simplified();
494 if((ver_maj == UINT_MAX) || (ver_min == UINT_MAX) || (ver_mod == UINT_MAX))
501 if((offset = regExpVersionMod.lastIndexIn(text)) >= 0)
503 bool ok1 = false, ok2 = false, ok3 = false;
504 unsigned int temp1 = regExpVersionMod.cap(1).toUInt(&ok1);
505 unsigned int temp2 = regExpVersionMod.cap(2).toUInt(&ok2);
506 unsigned int temp3 = regExpVersionMod.cap(3).toUInt(&ok3);
507 if(ok1) ver_maj = temp1;
508 if(ok2) ver_min = temp2;
509 if(ok3) ver_mod = temp3;
511 else if((offset = regExpVersionOld.lastIndexIn(text)) >= 0)
513 bool ok1 = false, ok2 = false;
514 unsigned int temp1 = regExpVersionOld.cap(1).toUInt(&ok1);
515 unsigned int temp2 = regExpVersionOld.cap(2).toUInt(&ok2);
516 if(ok1) ver_maj = temp1;
517 if(ok2) ver_min = temp2;
523 process.waitForFinished();
524 if(process.state() != QProcess::NotRunning)
527 process.waitForFinished(-1);
530 if(bTimeout || bAborted || ((process.exitCode() != EXIT_SUCCESS) && (process.exitCode() != 2)))
532 if(!(bTimeout || bAborted))
534 log(tr("\nPROCESS EXITED WITH ERROR CODE: %1").arg(QString::number(process.exitCode())));
539 if((ver_maj == UINT_MAX) || (ver_min == UINT_MAX))
541 log(tr("\nFAILED TO DETERMINE AVS2YUV VERSION !!!"));
545 return (ver_maj * REV_MULT) + ((ver_min % REV_MULT) * 10) + (ver_mod % 10);
548 bool EncodeThread::checkVersionVapoursynth(void)
550 //Is VapourSynth available at all?
551 if((!m_sysinfo->hasVPSSupport()) || (!QFileInfo(VPS_BINARY(m_sysinfo, m_preferences)).isFile()))
553 log(tr("\nVPY INPUT REQUIRES VAPOURSYNTH, BUT IT IS *NOT* AVAILABLE !!!"));
559 log("\nCreating process:");
560 if(!startProcess(process, VPS_BINARY(m_sysinfo, m_preferences), QStringList()))
565 QRegExp regExpSignature("\\bVSPipe\\s+usage\\b", Qt::CaseInsensitive);
567 bool bTimeout = false;
568 bool bAborted = false;
570 bool vspipeSignature = false;
572 while(process.state() != QProcess::NotRunning)
580 if(!process.waitForReadyRead())
582 if(process.state() == QProcess::Running)
585 qWarning("VSPipe process timed out <-- killing!");
586 log("\nPROCESS TIMEOUT !!!");
591 while(process.bytesAvailable() > 0)
593 QList<QByteArray> lines = process.readLine().split('\r');
594 while(!lines.isEmpty())
596 QString text = QString::fromUtf8(lines.takeFirst().constData()).simplified();
597 if(regExpSignature.lastIndexIn(text) >= 0)
599 vspipeSignature = true;
609 process.waitForFinished();
610 if(process.state() != QProcess::NotRunning)
613 process.waitForFinished(-1);
616 if(bTimeout || bAborted || ((process.exitCode() != EXIT_SUCCESS) && (process.exitCode() != 1)))
618 if(!(bTimeout || bAborted))
620 log(tr("\nPROCESS EXITED WITH ERROR CODE: %1").arg(QString::number(process.exitCode())));
627 log(tr("\nFAILED TO DETECT VSPIPE SIGNATURE !!!"));
631 return vspipeSignature;
634 bool EncodeThread::checkPropertiesAVS(unsigned int &frames)
639 if(!m_options->customAvs2YUV().isEmpty())
641 cmdLine.append(splitParams(m_options->customAvs2YUV()));
644 cmdLine << "-frames" << "1";
645 cmdLine << QDir::toNativeSeparators(x264_path2ansi(m_sourceFileName, true)) << "NUL";
647 log("Creating process:");
648 if(!startProcess(process, AVS_BINARY(m_sysinfo, m_preferences), cmdLine))
653 QRegExp regExpInt(": (\\d+)x(\\d+), (\\d+) fps, (\\d+) frames");
654 QRegExp regExpFrc(": (\\d+)x(\\d+), (\\d+)/(\\d+) fps, (\\d+) frames");
656 QTextCodec *localCodec = QTextCodec::codecForName("System");
658 bool bTimeout = false;
659 bool bAborted = false;
663 unsigned int fpsNom = 0;
664 unsigned int fpsDen = 0;
665 unsigned int fSizeW = 0;
666 unsigned int fSizeH = 0;
668 unsigned int waitCounter = 0;
670 while(process.state() != QProcess::NotRunning)
678 if(!process.waitForReadyRead(m_processTimeoutInterval))
680 if(process.state() == QProcess::Running)
682 if(++waitCounter > m_processTimeoutMaxCounter)
684 if(m_preferences->getAbortOnTimeout())
687 qWarning("Avs2YUV process timed out <-- killing!");
688 log("\nPROCESS TIMEOUT !!!");
689 log("\nAvisynth has encountered a deadlock or your script takes EXTREMELY long to initialize!");
694 else if(waitCounter == m_processTimeoutWarning)
696 unsigned int timeOut = (waitCounter * m_processTimeoutInterval) / 1000U;
697 log(tr("Warning: Avisynth did not respond for %1 seconds, potential deadlock...").arg(QString::number(timeOut)));
705 while(process.bytesAvailable() > 0)
707 QList<QByteArray> lines = process.readLine().split('\r');
708 while(!lines.isEmpty())
710 QString text = localCodec->toUnicode(lines.takeFirst().constData()).simplified();
712 if((offset = regExpInt.lastIndexIn(text)) >= 0)
714 bool ok1 = false, ok2 = false;
715 bool ok3 = false, ok4 = false;
716 unsigned int temp1 = regExpInt.cap(1).toUInt(&ok1);
717 unsigned int temp2 = regExpInt.cap(2).toUInt(&ok2);
718 unsigned int temp3 = regExpInt.cap(3).toUInt(&ok3);
719 unsigned int temp4 = regExpInt.cap(4).toUInt(&ok4);
720 if(ok1) fSizeW = temp1;
721 if(ok2) fSizeH = temp2;
722 if(ok3) fpsNom = temp3;
723 if(ok4) frames = temp4;
725 else if((offset = regExpFrc.lastIndexIn(text)) >= 0)
727 bool ok1 = false, ok2 = false;
728 bool ok3 = false, ok4 = false, ok5 = false;
729 unsigned int temp1 = regExpFrc.cap(1).toUInt(&ok1);
730 unsigned int temp2 = regExpFrc.cap(2).toUInt(&ok2);
731 unsigned int temp3 = regExpFrc.cap(3).toUInt(&ok3);
732 unsigned int temp4 = regExpFrc.cap(4).toUInt(&ok4);
733 unsigned int temp5 = regExpFrc.cap(5).toUInt(&ok5);
734 if(ok1) fSizeW = temp1;
735 if(ok2) fSizeH = temp2;
736 if(ok3) fpsNom = temp3;
737 if(ok4) fpsDen = temp4;
738 if(ok5) frames = temp5;
744 if(text.contains("failed to load avisynth.dll", Qt::CaseInsensitive))
746 log(tr("\nWarning: It seems that %1-Bit Avisynth is not currently installed !!!").arg(m_preferences->getUseAvisyth64Bit() ? "64" : "32"));
748 if(text.contains(QRegExp("couldn't convert input clip to (YV16|YV24)", Qt::CaseInsensitive)))
750 log(tr("\nWarning: YV16 (4:2:2) and YV24 (4:4:4) color-spaces only supported in Avisynth 2.6 !!!"));
756 process.waitForFinished();
757 if(process.state() != QProcess::NotRunning)
760 process.waitForFinished(-1);
763 if(bTimeout || bAborted || process.exitCode() != EXIT_SUCCESS)
765 if(!(bTimeout || bAborted))
767 const int exitCode = process.exitCode();
768 log(tr("\nPROCESS EXITED WITH ERROR CODE: %1").arg(QString::number(exitCode)));
769 if((exitCode < 0) || (exitCode >= 32))
771 log(tr("\nIMPORTANT: The Avs2YUV process terminated abnormally. This means Avisynth or one of your Avisynth-Plugin's just crashed."));
772 log(tr("IMPORTANT: Please fix your Avisynth script and try again! If you use Avisynth-MT, try using a *stable* Avisynth instead!"));
780 log(tr("\nFAILED TO DETERMINE AVS PROPERTIES !!!"));
786 if((fSizeW > 0) && (fSizeH > 0))
788 log(tr("Resolution: %1x%2").arg(QString::number(fSizeW), QString::number(fSizeH)));
790 if((fpsNom > 0) && (fpsDen > 0))
792 log(tr("Frame Rate: %1/%2").arg(QString::number(fpsNom), QString::number(fpsDen)));
794 if((fpsNom > 0) && (fpsDen == 0))
796 log(tr("Frame Rate: %1").arg(QString::number(fpsNom)));
800 log(tr("No. Frames: %1").arg(QString::number(frames)));
806 bool EncodeThread::checkPropertiesVPS(unsigned int &frames)
811 cmdLine << QDir::toNativeSeparators(x264_path2ansi(m_sourceFileName, true));
812 cmdLine << "-" << "-info";
814 log("Creating process:");
815 if(!startProcess(process, VPS_BINARY(m_sysinfo, m_preferences), cmdLine))
820 QRegExp regExpFrm("\\bFrames:\\s+(\\d+)\\b");
821 QRegExp regExpSzW("\\bWidth:\\s+(\\d+)\\b");
822 QRegExp regExpSzH("\\bHeight:\\s+(\\d+)\\b");
824 QTextCodec *localCodec = QTextCodec::codecForName("System");
826 bool bTimeout = false;
827 bool bAborted = false;
831 unsigned int fSizeW = 0;
832 unsigned int fSizeH = 0;
834 unsigned int waitCounter = 0;
836 while(process.state() != QProcess::NotRunning)
844 if(!process.waitForReadyRead(m_processTimeoutInterval))
846 if(process.state() == QProcess::Running)
848 if(++waitCounter > m_processTimeoutMaxCounter)
850 if(m_preferences->getAbortOnTimeout())
853 qWarning("VSPipe process timed out <-- killing!");
854 log("\nPROCESS TIMEOUT !!!");
855 log("\nVapoursynth has encountered a deadlock or your script takes EXTREMELY long to initialize!");
860 else if(waitCounter == m_processTimeoutWarning)
862 unsigned int timeOut = (waitCounter * m_processTimeoutInterval) / 1000U;
863 log(tr("Warning: nVapoursynth did not respond for %1 seconds, potential deadlock...").arg(QString::number(timeOut)));
871 while(process.bytesAvailable() > 0)
873 QList<QByteArray> lines = process.readLine().split('\r');
874 while(!lines.isEmpty())
876 QString text = localCodec->toUnicode(lines.takeFirst().constData()).simplified();
878 if((offset = regExpFrm.lastIndexIn(text)) >= 0)
881 unsigned int temp = regExpFrm.cap(1).toUInt(&ok);
882 if(ok) frames = temp;
884 if((offset = regExpSzW.lastIndexIn(text)) >= 0)
887 unsigned int temp = regExpSzW.cap(1).toUInt(&ok);
888 if(ok) fSizeW = temp;
890 if((offset = regExpSzH.lastIndexIn(text)) >= 0)
893 unsigned int temp = regExpSzH.cap(1).toUInt(&ok);
894 if(ok) fSizeH = temp;
904 process.waitForFinished();
905 if(process.state() != QProcess::NotRunning)
908 process.waitForFinished(-1);
911 if(bTimeout || bAborted || process.exitCode() != EXIT_SUCCESS)
913 if(!(bTimeout || bAborted))
915 const int exitCode = process.exitCode();
916 log(tr("\nPROCESS EXITED WITH ERROR CODE: %1").arg(QString::number(exitCode)));
917 if((exitCode < 0) || (exitCode >= 32))
919 log(tr("\nIMPORTANT: The Vapoursynth process terminated abnormally. This means Vapoursynth or one of your Vapoursynth-Plugin's just crashed."));
927 log(tr("\nFAILED TO DETERMINE VPY PROPERTIES !!!"));
933 if((fSizeW > 0) && (fSizeH > 0))
935 log(tr("Resolution: %1x%2").arg(QString::number(fSizeW), QString::number(fSizeH)));
939 log(tr("No. Frames: %1").arg(QString::number(frames)));