Simple-x264-Launcher/src/thread_vapoursynth.cpp

398 lines
9.8 KiB
C++
Raw Normal View History

///////////////////////////////////////////////////////////////////////////////
// Simple x264 Launcher
2016-01-01 23:59:55 +01:00
// Copyright (C) 2004-2016 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 "thread_vapoursynth.h"
//Mutils
#include <MUtils/OSSupport.h>
#include <MUtils/Registry.h>
//Qt
#include <QLibrary>
#include <QEventLoop>
#include <QTimer>
#include <QMutexLocker>
#include <QApplication>
#include <QDir>
#include <QProcess>
2015-02-27 19:05:18 +01:00
//Internal
#include "global.h"
#include "model_sysinfo.h"
2015-02-27 19:05:18 +01:00
//CRT
#include <cassert>
//Static
QMutex VapourSynthCheckThread::m_vpsLock;
2015-02-27 19:05:18 +01:00
QScopedPointer<QFile> VapourSynthCheckThread::m_vpsExePath[2];
QScopedPointer<QFile> VapourSynthCheckThread::m_vpsDllPath[2];
2013-11-08 17:39:16 +01:00
#define VALID_DIR(STR) ((!(STR).isEmpty()) && QDir((STR)).exists())
#define BOOLIFY(X) ((X) ? '1' : '0')
2013-11-08 17:39:16 +01:00
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)
{
sysinfo->clearVapourSynth();
sysinfo->clearVPSPath();
QMutexLocker lock(&m_vpsLock);
QEventLoop loop;
VapourSynthCheckThread thread;
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
connect(&thread, SIGNAL(finished()), &loop, SLOT(quit()));
connect(&thread, SIGNAL(terminated()), &loop, SLOT(quit()));
thread.start();
2013-11-08 17:39:16 +01:00
QTimer::singleShot(15000, &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))
{
qWarning("VapourSynth thread encountered timeout -> probably deadlock!");
thread.terminate();
thread.wait();
return false;
}
if(thread.getException())
{
qWarning("VapourSynth thread encountered an exception !!!");
return false;
}
if(thread.getSuccess())
{
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)));
}
else
{
qWarning("VapourSynth could not be found -> VapourSynth support disabled!");
}
return true;
}
//-------------------------------------
// Thread class
//-------------------------------------
VapourSynthCheckThread::VapourSynthCheckThread(void)
{
m_success &= 0;
m_exception = false;
m_vpsPath.clear();
}
VapourSynthCheckThread::~VapourSynthCheckThread(void)
{
}
void VapourSynthCheckThread::run(void)
{
m_success &= 0;
2015-02-27 19:05:18 +01:00
m_exception = false;
m_vpsPath.clear();
2015-02-27 19:05:18 +01:00
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!");
}
}
void VapourSynthCheckThread::detectVapourSynthPath3(int &success, QString &path)
{
success &= 0;
path.clear();
2013-11-08 17:39:16 +01:00
static const char *VPS_REG_KEYS[] =
{
"SOFTWARE\\VapourSynth",
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VapourSynth_is1",
NULL
};
static const char *VPS_REG_NAME[] =
{
"Path",
"InstallLocation",
"Inno Setup: App Path",
NULL
};
static const MUtils::Registry::reg_scope_t REG_SCOPE[3] =
{
MUtils::Registry::scope_default,
MUtils::Registry::scope_wow_x32,
MUtils::Registry::scope_wow_x64
};
2013-11-08 17:39:16 +01:00
//Read VapourSynth path from registry
QString vapoursynthPath;
for(size_t i = 0; VPS_REG_KEYS[i]; i++)
{
for(size_t j = 0; VPS_REG_NAME[j]; j++)
{
for (size_t k = 0; k < 3; 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]))
{
temp = cleanDir(temp);
if (VALID_DIR(temp))
{
vapoursynthPath = temp;
break;
}
}
}
if (!vapoursynthPath.isEmpty())
{
break;
}
}
if (!vapoursynthPath.isEmpty())
{
break;
2013-11-08 17:39:16 +01:00
}
}
2013-11-08 17:39:16 +01:00
//Make sure VapourSynth does exist
if(!VALID_DIR(vapoursynthPath))
{
qWarning("VapourSynth install path not found -> disable VapouSynth support!");
return;
}
2015-02-27 19:05:18 +01:00
qDebug("VapourSynth Dir: %s", vapoursynthPath.toUtf8().constData());
//Look for 32-Bit edition of VapourSynth first
QFile *vpsExeFile32, *vpsDllFile32;
if(isVapourSynthComplete(QString("%1/core32").arg(vapoursynthPath), vpsExeFile32, vpsDllFile32))
{
2015-02-27 19:05:18 +01:00
if(vpsExeFile32 && checkVapourSynth(vpsExeFile32->fileName()))
{
2015-02-27 19:05:18 +01:00
success |= VAPOURSYNTH_X86;
qDebug("VapourSynth 32-Bit edition found!");
m_vpsExePath[0].reset(vpsExeFile32);
m_vpsDllPath[0].reset(vpsDllFile32);
}
2015-02-27 19:05:18 +01:00
else
{
2015-02-27 19:05:18 +01:00
qWarning("VapourSynth 32-Bit edition was found, but version check has failed!");
}
}
2015-02-27 19:05:18 +01:00
else
{
qDebug("VapourSynth 32-Bit edition *not* found!");
}
2015-02-27 19:05:18 +01:00
//Look for 64-Bit edition of VapourSynth next
QFile *vpsExeFile64, *vpsDllFile64;
if(isVapourSynthComplete(QString("%1/core64").arg(vapoursynthPath), vpsExeFile64, vpsDllFile64))
{
if(vpsExeFile64 && checkVapourSynth(vpsExeFile64->fileName()))
{
success |= VAPOURSYNTH_X64;
qDebug("VapourSynth 64-Bit edition found!");
m_vpsExePath[1].reset(vpsExeFile64);
m_vpsDllPath[1].reset(vpsDllFile64);
}
else
{
qWarning("VapourSynth 64-Bit edition was found, but version check has failed!");
}
}
else
{
2015-02-27 19:05:18 +01:00
qDebug("VapourSynth 64-Bit edition *not* found!");
}
//Return VapourSynth path
if(success)
{
path = vapoursynthPath;
}
}
2015-02-27 19:05:18 +01:00
bool VapourSynthCheckThread::isVapourSynthComplete(const QString &vsCorePath, 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())
{
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());
}
}
if(!complete)
{
MUTILS_DELETE(vpsExeFile);
MUTILS_DELETE(vpsDllFile);
}
return complete;
}
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;
}
//Init regular expressions
QRegExp vpsLogo("VapourSynth\\s+Video\\s+Processing\\s+Library");
//Check for version info
bool vapoursynthLogo = false;
for(QStringList::ConstIterator iter = output.constBegin(); iter != output.constEnd(); iter++)
{
if(vpsLogo.lastIndexIn(*iter) >= 0)
{
vapoursynthLogo = true;
break;
}
}
//Minimum required version found?
if(vapoursynthLogo)
{
2015-02-27 19:05:18 +01:00
qDebug("VapourSynth version was detected successfully.");
return true;
}
//Failed to determine version
2015-02-27 19:05:18 +01:00
qWarning("Failed to determine VapourSynth version!");
return false;
}