OSDN Git Service

Various improvements to Avisynth and VapourSynth detection code. Refactored common...
[x264-launcher/x264-launcher.git] / src / thread_avisynth.cpp
index b421e44..129fb3d 100644 (file)
@@ -1,6 +1,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 // Simple x264 Launcher
-// Copyright (C) 2004-2016 LoRd_MuldeR <MuldeR2@GMX.de>
+// Copyright (C) 2004-2019 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
 
 #include "thread_avisynth.h"
 
+//Qt
 #include <QLibrary>
 #include <QEventLoop>
 #include <QTimer>
-#include <QMutexLocker>
 #include <QApplication>
-#include <QProcess>
 #include <QDir>
 
 //Internal
 #include <MUtils/Global.h>
 #include <MUtils/OSSupport.h>
 
+//Const
+static const bool ENABLE_PORTABLE_AVS = true;
+
 //Static
 QMutex AvisynthCheckThread::m_avsLock;
 QScopedPointer<QFile> AvisynthCheckThread::m_avsDllPath[2];
 
 //Helper
+#define VALID_DIR(STR) ((!(STR).isEmpty()) && QDir((STR)).exists())
 #define BOOLIFY(X) ((X) ? '1' : '0')
 
 //Utility function
@@ -92,7 +95,7 @@ bool AvisynthCheckThread::detect(SysinfoModel *sysinfo)
        connect(&thread, SIGNAL(terminated()), &loop, SLOT(quit()));
        
        thread.start();
-       QTimer::singleShot(15000, &loop, SLOT(quit()));
+       QTimer::singleShot(30000, &loop, SLOT(quit()));
        
        qDebug("Avisynth thread has been created, please wait...");
        loop.exec(QEventLoop::ExcludeUserInputEvents);
@@ -118,6 +121,7 @@ bool AvisynthCheckThread::detect(SysinfoModel *sysinfo)
        {
                sysinfo->setAvisynth(SysinfoModel::Avisynth_X86, thread.getSuccess() & AVISYNTH_X86);
                sysinfo->setAvisynth(SysinfoModel::Avisynth_X64, thread.getSuccess() & AVISYNTH_X64);
+               sysinfo->setAVSPath(thread.getPath());
                qDebug("Avisynth support is officially enabled now! [x86=%c, x64=%c]", BOOLIFY(sysinfo->getAvisynth(SysinfoModel::Avisynth_X86)), BOOLIFY(sysinfo->getAvisynth(SysinfoModel::Avisynth_X64)));
        }
        else
@@ -148,15 +152,16 @@ void AvisynthCheckThread::run(void)
 {
        m_exception = false;
        m_success &= 0;
+       m_basePath.clear();
 
-       detectAvisynthVersion1(m_success, m_sysinfo, &m_exception);
+       detectAvisynthVersion1(m_success, m_basePath, m_sysinfo, &m_exception);
 }
 
-void AvisynthCheckThread::detectAvisynthVersion1(int &success, const SysinfoModel *const sysinfo, volatile bool *exception)
+void AvisynthCheckThread::detectAvisynthVersion1(int &success, QString &basePath, const SysinfoModel *const sysinfo, volatile bool *exception)
 {
        __try
        {
-               detectAvisynthVersion2(success, sysinfo, exception);
+               detectAvisynthVersion2(success, basePath, sysinfo, exception);
        }
        __except(1)
        {
@@ -165,11 +170,11 @@ void AvisynthCheckThread::detectAvisynthVersion1(int &success, const SysinfoMode
        }
 }
 
-void AvisynthCheckThread::detectAvisynthVersion2(int &success, const SysinfoModel *const sysinfo, volatile bool *exception)
+void AvisynthCheckThread::detectAvisynthVersion2(int &success, QString &basePath, const SysinfoModel *const sysinfo, volatile bool *exception)
 {
        try
        {
-               return detectAvisynthVersion3(success, sysinfo);
+               return detectAvisynthVersion3(success, basePath, sysinfo);
        }
        catch(...)
        {
@@ -178,12 +183,12 @@ void AvisynthCheckThread::detectAvisynthVersion2(int &success, const SysinfoMode
        }
 }
 
-void AvisynthCheckThread::detectAvisynthVersion3(int &success, const SysinfoModel *const sysinfo)
+void AvisynthCheckThread::detectAvisynthVersion3(int &success, QString &basePath, const SysinfoModel *const sysinfo)
 {
        success &= 0;
 
        QFile *avsPath32;
-       if(checkAvisynth(sysinfo, avsPath32, false))
+       if(checkAvisynth(basePath, sysinfo, avsPath32, false))
        {
                m_avsDllPath[0].reset(avsPath32);
                success |= AVISYNTH_X86;
@@ -197,7 +202,7 @@ void AvisynthCheckThread::detectAvisynthVersion3(int &success, const SysinfoMode
        if(sysinfo->getCPUFeatures(SysinfoModel::CPUFeatures_X64))
        {
                QFile *avsPath64;
-               if(checkAvisynth(sysinfo, avsPath64, true))
+               if(checkAvisynth(basePath, sysinfo, avsPath64, true))
                {
                        m_avsDllPath[1].reset(avsPath64);
                        success |= AVISYNTH_X64;
@@ -214,65 +219,36 @@ void AvisynthCheckThread::detectAvisynthVersion3(int &success, const SysinfoMode
        }
 }
 
-bool AvisynthCheckThread::checkAvisynth(const SysinfoModel *const sysinfo, QFile *&path, const bool &x64)
+bool AvisynthCheckThread::checkAvisynth(QString &basePath, const SysinfoModel *const sysinfo, QFile *&path, const bool &x64)
 {
        qDebug("Avisynth %s-Bit support is being tested.", x64 ? "64" : "32");
 
-       QProcess process;
-       QStringList output;
-
-       //Setup process object
-       process.setWorkingDirectory(QDir::tempPath());
-       process.setProcessChannelMode(QProcess::MergedChannels);
-       process.setReadChannel(QProcess::StandardOutput);
-
-       //Try to start VSPIPE.EXE
-       process.start(AVS_CHECK_BINARY(sysinfo, x64), QStringList());
-       if(!process.waitForStarted())
+       //Look for "portable" Avisynth version
+       static const char *const ARCH_DIR[] = { "x64", "x86" };
+       const QLatin1String archSuffix = QLatin1String(ARCH_DIR[x64 ? 1 : 0]);
+       if (ENABLE_PORTABLE_AVS)
        {
-               qWarning("Failed to launch AVS_CHECK.EXE -> %s", process.errorString().toUtf8().constData());
-               return false;
-       }
-
-       //Wait for process to finish
-       while(process.state() != QProcess::NotRunning)
-       {
-               if(process.waitForReadyRead(12000))
+               const QString avsPortableDir = QString("%1/extra/Avisynth").arg(QCoreApplication::applicationDirPath());
+               if (VALID_DIR(avsPortableDir))
                {
-                       while(process.canReadLine())
+                       QFileInfo avsDllFile(QString("%1/%2/avisynth.dll").arg(avsPortableDir, archSuffix)), devilDllFile(QString("%1/%2/devil.dll").arg(avsPortableDir, archSuffix));
+                       if (avsDllFile.exists() && devilDllFile.exists() && avsDllFile.isFile() && devilDllFile.isFile())
                        {
-                               output << QString::fromUtf8(process.readLine()).simplified();
+                               qWarning("Adding portable Avisynth to PATH environment variable: %s", MUTILS_UTF8(avsPortableDir));
+                               basePath = avsPortableDir;
                        }
-                       continue;
-               }
-               if(process.state() != QProcess::NotRunning)
-               {
-                       qWarning("AVS_CHECK.EXE process encountered a deadlock -> aborting now!");
-                       break;
                }
        }
 
-       //Make sure VSPIPE.EXE has terminated!
-       process.waitForFinished(2500);
-       if(process.state() != QProcess::NotRunning)
+       //Get extra paths
+       QStringList avisynthExtraPaths;
+       if (!basePath.isEmpty())
        {
-               qWarning("AVS_CHECK.EXE process still running, going to kill it!");
-               process.kill();
-               process.waitForFinished(-1);
+               avisynthExtraPaths << QString("%1/%2").arg(basePath, archSuffix);
        }
 
-       //Read pending lines
-       while(process.canReadLine())
-       {
-               output << QString::fromUtf8(process.readLine()).simplified();
-       }
-
-       //Check exit code
-       if(process.exitCode() != 0)
-       {
-               qWarning("AVS_CHECK.EXE failed with code 0x%08X -> disable Avisynth support!", process.exitCode());
-               return false;
-       }
+       //Setup process object
+       const QStringList output = runProcess(AVS_CHECK_BINARY(sysinfo, x64), QStringList(), &avisynthExtraPaths);
 
        //Init regular expressions
        QRegExp avsLogo("Avisynth\\s+Checker\\s+(x86|x64)");
@@ -319,7 +295,6 @@ bool AvisynthCheckThread::checkAvisynth(const SysinfoModel *const sysinfo, QFile
                {
                        MUTILS_DELETE(path);
                }
-
                qDebug("Avisynth was detected successfully (current version: %u.%02u).", avisynthVersion[0], avisynthVersion[1]);
                qDebug("Avisynth DLL path: %s", MUTILS_UTF8(avisynthPath));
                return true;