///////////////////////////////////////////////////////////////////////////////
// Simple x264 Launcher
-// Copyright (C) 2004-2019 LoRd_MuldeR <MuldeR2@GMX.de>
+// Copyright (C) 2004-2020 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 <MUtils/Registry.h>
//Qt
-#include <QLibrary>
#include <QEventLoop>
#include <QTimer>
-#include <QMutexLocker>
#include <QApplication>
#include <QDir>
-#include <QProcess>
+#include <QHash>
+#include <QAbstractFileEngine.h>
//Internal
#include "global.h"
//CRT
#include <cassert>
-//Const
-static const bool ENABLE_PORTABLE_VPS = true;
-
//Static
QMutex VapourSynthCheckThread::m_vpsLock;
QScopedPointer<QFile> VapourSynthCheckThread::m_vpsExePath[2];
QScopedPointer<QFile> VapourSynthCheckThread::m_vpsDllPath[2];
-#define VALID_DIR(STR) ((!(STR).isEmpty()) && QDir((STR)).exists())
+//Const
+static const char* const VPS_DLL_NAME = "vapoursynth.dll";
+static const char* const VPS_EXE_NAME = "vspipe.exe";
+static const char* const VPS_REG_KEY1 = "SOFTWARE\\VapourSynth";
+static const char* const VPS_REG_KEY2 = "SOFTWARE\\VapourSynth-32";
+static const char* const VPS_REG_NAME = "VapourSynthDLL";
+
+//Default VapurSynth architecture
+#if _WIN64 || __x86_64__
+#define VAPOURSYNTH_DEF VAPOURSYNTH_X64
+#else
+#define VAPOURSYNTH_DEF VAPOURSYNTH_X86;
+#endif
+
+//Enable detection of "portabel" edition?
+#define ENABLE_PORTABLE_VPS true
+
+//EOL flags
+#define REG_ROOT_EOL (MUtils::Registry::reg_root_t (-1))
+#define REG_SCOPE_EOL (MUtils::Registry::reg_scope_t(-1))
+
+//Auxilary functions
#define BOOLIFY(X) ((X) ? '1' : '0')
#define VPS_BITNESS(X) (((X) + 1U) * 32U)
-static inline QString &cleanDir(QString &path)
-{
- if(!path.isEmpty())
- {
- path = QDir::fromNativeSeparators(path);
- while(path.endsWith('/'))
- {
- path.chop(1);
- }
- }
- return path;
-}
-
//-------------------------------------
// External API
//-------------------------------------
-bool VapourSynthCheckThread::detect(SysinfoModel *sysinfo)
+bool VapourSynthCheckThread::detect(SysinfoModel* sysinfo)
{
- sysinfo->clearVapourSynth();
- sysinfo->clearVPSPath();
-
QMutexLocker lock(&m_vpsLock);
+ sysinfo->clearVapourSynth();
+ sysinfo->clearVPS32Path();
+ sysinfo->clearVPS64Path();
+
QEventLoop loop;
VapourSynthCheckThread thread;
connect(&thread, SIGNAL(finished()), &loop, SLOT(quit()));
connect(&thread, SIGNAL(terminated()), &loop, SLOT(quit()));
-
+
thread.start();
- QTimer::singleShot(15000, &loop, SLOT(quit()));
-
+ QTimer::singleShot(30000, &loop, SLOT(quit()));
+
qDebug("VapourSynth thread has been created, please wait...");
loop.exec(QEventLoop::ExcludeUserInputEvents);
qDebug("VapourSynth thread finished.");
QApplication::restoreOverrideCursor();
- if(!thread.wait(1000))
+ if (!thread.wait(1000))
{
qWarning("VapourSynth thread encountered timeout -> probably deadlock!");
thread.terminate();
return false;
}
- if(thread.getException())
+ if (thread.getException())
{
qWarning("VapourSynth thread encountered an exception !!!");
return false;
}
- if(thread.getSuccess())
+ const int success = thread.getSuccess();
+ if (!success)
{
- sysinfo->setVapourSynth(SysinfoModel::VapourSynth_X86, thread.getSuccess() & VAPOURSYNTH_X86);
- sysinfo->setVapourSynth(SysinfoModel::VapourSynth_X64, thread.getSuccess() & VAPOURSYNTH_X64);
- sysinfo->setVPSPath(thread.getPath());
- qDebug("VapourSynth support is officially enabled now! [x86=%c, x64=%c]", BOOLIFY(sysinfo->getVapourSynth(SysinfoModel::VapourSynth_X86)), BOOLIFY(sysinfo->getVapourSynth(SysinfoModel::VapourSynth_X64)));
+ qWarning("VapourSynth could not be found -> VapourSynth support disabled!");
+ return true;
}
- else
+
+ if (success & VAPOURSYNTH_X86)
{
- qWarning("VapourSynth could not be found -> VapourSynth support disabled!");
+ sysinfo->setVapourSynth(SysinfoModel::VapourSynth_X86, true);
+ sysinfo->setVPS32Path(thread.getPath32());
+ }
+
+ if (success & VAPOURSYNTH_X64)
+ {
+ sysinfo->setVapourSynth(SysinfoModel::VapourSynth_X64, true);
+ sysinfo->setVPS64Path(thread.getPath64());
}
+ qDebug("VapourSynth support is officially enabled now! [x86=%c, x64=%c]", BOOLIFY(sysinfo->getVapourSynth(SysinfoModel::VapourSynth_X86)), BOOLIFY(sysinfo->getVapourSynth(SysinfoModel::VapourSynth_X64)));
return true;
}
//-------------------------------------
-// Thread class
+// Thread functions
//-------------------------------------
VapourSynthCheckThread::VapourSynthCheckThread(void)
{
- m_success &= 0;
- m_exception = false;
- m_vpsPath.clear();
+ m_vpsPath[0U].clear();
+ m_vpsPath[1U].clear();
}
VapourSynthCheckThread::~VapourSynthCheckThread(void)
void VapourSynthCheckThread::run(void)
{
- m_success &= 0;
- m_exception = false;
- m_vpsPath.clear();
-
- detectVapourSynthPath1(m_success, m_vpsPath, &m_exception);
-}
-
-void VapourSynthCheckThread::detectVapourSynthPath1(int &success, QString &path, volatile bool *exception)
-{
- __try
- {
- return detectVapourSynthPath2(success, path, exception);
- }
- __except(1)
- {
- *exception = true;
- qWarning("Unhandled exception error in VapourSynth thread !!!");
- }
-}
-
-void VapourSynthCheckThread::detectVapourSynthPath2(int &success, QString &path, volatile bool *exception)
-{
- try
- {
- return detectVapourSynthPath3(success, path);
- }
- catch(...)
- {
- *exception = true;
- qWarning("VapourSynth initializdation raised an C++ exception!");
- }
+ m_vpsPath[0U].clear();
+ m_vpsPath[1U].clear();
+ StarupThread::run();
}
-void VapourSynthCheckThread::detectVapourSynthPath3(int &success, QString &path)
+int VapourSynthCheckThread::threadMain(void)
{
- success &= 0;
- path.clear();
-
- static const char *VPS_CORE_DIR[] =
- {
- "core32",
- "core64",
- NULL
- };
static const int VPS_BIT_FLAG[] =
{
VAPOURSYNTH_X86,
VAPOURSYNTH_X64,
NULL
};
- static const char *VPS_REG_KEYS[] =
+ static const MUtils::Registry::reg_root_t REG_ROOTS[] =
{
- "SOFTWARE\\VapourSynth",
- "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VapourSynth_is1",
+ MUtils::Registry::root_machine,
+ MUtils::Registry::root_user,
+ REG_ROOT_EOL
+ };
+ static const char* const REG_PATHS_HKLM[] =
+ {
+ VPS_REG_KEY1,
NULL
};
- static const char *VPS_REG_NAME[] =
+ static const char* const REG_PATHS_HKCU[] =
{
- "Path",
- "InstallLocation",
- "Inno Setup: App Path",
+ VPS_REG_KEY1,
+ VPS_REG_KEY2,
NULL
};
- static const MUtils::Registry::reg_scope_t REG_SCOPE[3] =
+ static const MUtils::Registry::reg_scope_t REG_SCOPE_X86[] =
{
MUtils::Registry::scope_default,
+ REG_SCOPE_EOL
+ };
+ static const MUtils::Registry::reg_scope_t REG_SCOPE_X64[] =
+ {
MUtils::Registry::scope_wow_x32,
- MUtils::Registry::scope_wow_x64
+ MUtils::Registry::scope_wow_x64,
+ REG_SCOPE_EOL
};
- QString vapoursynthPath;
+ QHash<int, QFileInfo> vpsDllInfo, vpsExeInfo;
+ int flags = 0;
//Look for "portable" VapourSynth version
- if (ENABLE_PORTABLE_VPS)
+ for (size_t i = 0; i < 2U; i++)
{
- const QString vpsPortableDir = QString("%1/extra/VapourSynth").arg(QCoreApplication::applicationDirPath());
- if (VALID_DIR(vpsPortableDir))
+ const QDir vpsPortableDir(QString("%1/extra/VapourSynth-%2").arg(QCoreApplication::applicationDirPath(), QString::number(VPS_BITNESS(i))));
+ if (vpsPortableDir.exists())
{
- for (size_t i = 0; VPS_CORE_DIR[i]; i++)
+ const QFileInfo vpsPortableDll(vpsPortableDir.absoluteFilePath(VPS_DLL_NAME));
+ const QFileInfo vpsPortableExe(vpsPortableDir.absoluteFilePath(VPS_EXE_NAME));
+ if ((vpsPortableDll.exists() && vpsPortableDll.isFile()) || (vpsPortableExe.exists() && vpsPortableExe.isFile()))
{
- const QFileInfo vpsPortableDll = QFileInfo(QString("%1/%2/VapourSynth.dll").arg(vpsPortableDir, QString::fromLatin1(VPS_CORE_DIR[i])));
- if (vpsPortableDll.exists() && vpsPortableDll.isFile())
- {
- vapoursynthPath = vpsPortableDir;
- break;
- }
+ vpsDllInfo.insert(VPS_BIT_FLAG[i], vpsPortableDll);
+ vpsExeInfo.insert(VPS_BIT_FLAG[i], vpsPortableExe);
}
}
}
//Read VapourSynth path from registry
- if (vapoursynthPath.isEmpty())
+ if (vpsDllInfo.isEmpty() && vpsExeInfo.isEmpty())
{
- for (size_t i = 0; VPS_REG_KEYS[i]; i++)
+ for (size_t i = 0; REG_ROOTS[i] != REG_ROOT_EOL; i++)
{
- for (size_t j = 0; VPS_REG_NAME[j]; j++)
+ const char *const *const paths = (REG_ROOTS[i] == MUtils::Registry::root_machine) ? REG_PATHS_HKLM : REG_PATHS_HKCU;
+ const MUtils::Registry::reg_scope_t* const scopes = (REG_ROOTS[i] == MUtils::Registry::root_machine) ? ((MUtils::OS::os_architecture() == MUtils::OS::ARCH_X64) ? REG_SCOPE_X64 : REG_SCOPE_X86) : REG_SCOPE_X86;
+ for (size_t j = 0; paths[j]; j++)
{
- for (size_t k = 0; k < 3; k++)
+ for (size_t k = 0; scopes[k] != REG_SCOPE_EOL; k++)
{
- if (MUtils::Registry::reg_key_exists(MUtils::Registry::root_machine, QString::fromLatin1(VPS_REG_KEYS[i]), REG_SCOPE[k]))
+ if (MUtils::Registry::reg_key_exists(REG_ROOTS[i], QString::fromLatin1(paths[j]), scopes[k]))
{
- QString temp;
- if (MUtils::Registry::reg_value_read(MUtils::Registry::root_machine, QString::fromLatin1(VPS_REG_KEYS[i]), QString::fromLatin1(VPS_REG_NAME[j]), temp, REG_SCOPE[k]))
+ QString vpsRegDllPath;
+ if (MUtils::Registry::reg_value_read(REG_ROOTS[i], QString::fromLatin1(paths[j]), QString::fromLatin1(VPS_REG_NAME), vpsRegDllPath, scopes[k]))
{
- temp = cleanDir(temp);
- if (VALID_DIR(temp))
+ QFileInfo vpsRegDllInfo(QDir::fromNativeSeparators(vpsRegDllPath));
+ vpsRegDllInfo.makeAbsolute();
+ if (vpsRegDllInfo.exists() && vpsRegDllInfo.isFile())
{
- vapoursynthPath = temp;
- break;
+ const int vpsArch = (REG_ROOTS[i] == MUtils::Registry::root_machine) ? getVapourSynthType(scopes[k]) : ((j > 0U) ? VAPOURSYNTH_X86 : VAPOURSYNTH_X64);
+ if ((!vpsDllInfo.contains(vpsArch)) || (!vpsExeInfo.contains(vpsArch)))
+ {
+ vpsDllInfo.insert(vpsArch, vpsRegDllInfo);
+ vpsExeInfo.insert(vpsArch, vpsRegDllInfo.absoluteDir().absoluteFilePath(VPS_EXE_NAME)); /*derive VSPipe.EXE path from VapourSynth.DLL path!*/
+ }
}
}
}
}
- if (!vapoursynthPath.isEmpty())
- {
- break;
- }
- }
- if (!vapoursynthPath.isEmpty())
- {
- break;
}
}
}
- //Make sure VapourSynth directory does exist
- if(vapoursynthPath.isEmpty())
+ //Abort, if VapourSynth was *not* found
+ if (vpsDllInfo.isEmpty() || vpsExeInfo.isEmpty())
{
qWarning("VapourSynth install path not found -> disable VapouSynth support!");
- return;
+ return 0;
}
//Validate the VapourSynth installation now!
- qDebug("VapourSynth Dir: %s", vapoursynthPath.toUtf8().constData());
- for (size_t i = 0; VPS_CORE_DIR[i]; i++)
+ for (size_t i = 0; i < 2U; i++)
{
- QFile *vpsExeFile, *vpsDllFile;
- if (isVapourSynthComplete(QString("%1/%2").arg(vapoursynthPath, QString::fromLatin1(VPS_CORE_DIR[i])), vpsExeFile, vpsDllFile))
+ qDebug("VapourSynth %u-Bit support is being tested.", VPS_BITNESS(i));
+ if (vpsDllInfo.contains(VPS_BIT_FLAG[i]) && vpsExeInfo.contains(VPS_BIT_FLAG[i]))
{
- if (vpsExeFile && checkVapourSynth(vpsExeFile->fileName()))
+ QFile *vpsExeFile, *vpsDllFile;
+ if (isVapourSynthComplete(vpsDllInfo[VPS_BIT_FLAG[i]], vpsExeInfo[VPS_BIT_FLAG[i]], vpsExeFile, vpsDllFile))
{
- success |= VPS_BIT_FLAG[i];
- qDebug("VapourSynth %u-Bit edition found!", VPS_BITNESS(i));
m_vpsExePath[i].reset(vpsExeFile);
m_vpsDllPath[i].reset(vpsDllFile);
+ if (checkVapourSynth(m_vpsExePath[i]->fileEngine()->fileName(QAbstractFileEngine::CanonicalName)))
+ {
+ qDebug("VapourSynth %u-Bit edition found!", VPS_BITNESS(i));
+ m_vpsPath[i] = m_vpsExePath[i]->fileEngine()->fileName(QAbstractFileEngine::CanonicalPathName);
+ flags |= VPS_BIT_FLAG[i];
+ }
+ else
+ {
+ qWarning("VapourSynth %u-Bit edition was found, but version check has failed!", VPS_BITNESS(i));
+ }
}
else
{
- qWarning("VapourSynth %u-Bit edition was found, but version check has failed!", VPS_BITNESS(i));
+ qWarning("VapourSynth %u-Bit edition was found, but appears to be incomplete!", VPS_BITNESS(i));
}
}
else
}
}
- //Return VapourSynth path
- if(success)
+ return flags;
+}
+
+//-------------------------------------
+// Internal functions
+//-------------------------------------
+
+VapourSynthCheckThread::VapourSynthFlags VapourSynthCheckThread::getVapourSynthType(const int scope)
+{
+ if (MUtils::OS::os_architecture() == MUtils::OS::ARCH_X64)
+ {
+ switch (scope)
+ {
+ case MUtils::Registry::scope_wow_x32:
+ return VAPOURSYNTH_X86;
+ case MUtils::Registry::scope_wow_x64:
+ return VAPOURSYNTH_X64;
+ default:
+ return VAPOURSYNTH_DEF;
+ }
+ }
+ else
{
- path = vapoursynthPath;
+ return VAPOURSYNTH_X86; /*ignore scope on 32-Bit OS*/
}
}
-bool VapourSynthCheckThread::isVapourSynthComplete(const QString &vsCorePath, QFile *&vpsExeFile, QFile *&vpsDllFile)
+bool VapourSynthCheckThread::isVapourSynthComplete(const QFileInfo& vpsDllInfo, const QFileInfo& vpsExeInfo, QFile*& vpsExeFile, QFile*& vpsDllFile)
{
bool complete = false;
vpsExeFile = vpsDllFile = NULL;
-
- QFileInfo vpsExeInfo(QString("%1/vspipe.exe" ).arg(vsCorePath));
- QFileInfo vpsDllInfo(QString("%1/vapoursynth.dll").arg(vsCorePath));
qDebug("VapourSynth EXE: %s", vpsExeInfo.absoluteFilePath().toUtf8().constData());
qDebug("VapourSynth DLL: %s", vpsDllInfo.absoluteFilePath().toUtf8().constData());
- if(vpsExeInfo.exists() && vpsDllInfo.exists())
+ if (vpsDllInfo.exists() && vpsDllInfo.isFile() && vpsExeInfo.exists() && vpsExeInfo.isFile())
{
vpsExeFile = new QFile(vpsExeInfo.canonicalFilePath());
vpsDllFile = new QFile(vpsDllInfo.canonicalFilePath());
if(vpsExeFile->open(QIODevice::ReadOnly) && vpsDllFile->open(QIODevice::ReadOnly))
{
- complete = MUtils::OS::is_executable_file(vpsExeFile->fileName());
+ complete = MUtils::OS::is_executable_file(vpsExeFile->fileEngine()->fileName(QAbstractFileEngine::CanonicalName));
}
}
bool VapourSynthCheckThread::checkVapourSynth(const QString &vspipePath)
{
- 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(vspipePath, QStringList() << "--version");
- if(!process.waitForStarted())
- {
- qWarning("Failed to launch VSPIPE.EXE -> %s", process.errorString().toUtf8().constData());
- return false;
- }
-
- //Wait for process to finish
- while(process.state() != QProcess::NotRunning)
- {
- if(process.waitForReadyRead(12000))
- {
- while(process.canReadLine())
- {
- output << QString::fromUtf8(process.readLine()).simplified();
- }
- continue;
- }
- if(process.state() != QProcess::NotRunning)
- {
- qWarning("VSPIPE.EXE process encountered a deadlock -> aborting now!");
- break;
- }
- }
-
- //Make sure VSPIPE.EXE has terminated!
- process.waitForFinished(2500);
- if(process.state() != QProcess::NotRunning)
- {
- qWarning("VSPIPE.EXE process still running, going to kill it!");
- process.kill();
- process.waitForFinished(-1);
- }
-
- //Read pending lines
- while(process.canReadLine())
- {
- output << QString::fromUtf8(process.readLine()).simplified();
- }
-
- //Check exit code
- if(process.exitCode() != 0)
- {
- qWarning("VSPIPE.EXE failed with code 0x%08X -> disable Vapousynth support!", process.exitCode());
- return false;
- }
+ //Try to run VSPIPE.EXE
+ const QStringList output = runProcess(vspipePath, QStringList() << "--version");
//Init regular expressions
QRegExp vpsLogo("VapourSynth\\s+Video\\s+Processing\\s+Library");