2013-08-07 15:34:02 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Simple x264 Launcher
|
2015-01-31 19:56:04 +01:00
|
|
|
// Copyright (C) 2004-2015 LoRd_MuldeR <MuldeR2@GMX.de>
|
2013-08-07 15:34:02 +02:00
|
|
|
//
|
|
|
|
// 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"
|
|
|
|
|
2015-02-02 22:11:06 +01:00
|
|
|
//Mutils
|
|
|
|
#include <MUtils/OSSupport.h>
|
|
|
|
|
|
|
|
//Qt
|
2013-08-07 15:34:02 +02:00
|
|
|
#include <QLibrary>
|
|
|
|
#include <QEventLoop>
|
|
|
|
#include <QTimer>
|
|
|
|
#include <QMutexLocker>
|
|
|
|
#include <QApplication>
|
|
|
|
#include <QDir>
|
2014-05-05 15:07:31 +02:00
|
|
|
#include <QProcess>
|
2013-08-07 15:34:02 +02:00
|
|
|
|
2015-02-27 19:05:18 +01:00
|
|
|
//Internal
|
2013-08-07 15:34:02 +02:00
|
|
|
#include "global.h"
|
|
|
|
|
2015-02-27 19:05:18 +01:00
|
|
|
//CRT
|
|
|
|
#include <cassert>
|
|
|
|
|
2013-08-07 15:34:02 +02:00
|
|
|
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-08-07 15:34:02 +02:00
|
|
|
|
2013-11-08 17:39:16 +01:00
|
|
|
#define VALID_DIR(STR) ((!(STR).isEmpty()) && QDir((STR)).exists())
|
|
|
|
|
|
|
|
static inline QString &cleanDir(QString &path)
|
|
|
|
{
|
|
|
|
if(!path.isEmpty())
|
|
|
|
{
|
|
|
|
path = QDir::fromNativeSeparators(path);
|
|
|
|
while(path.endsWith('/'))
|
|
|
|
{
|
|
|
|
path.chop(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
2013-08-07 15:34:02 +02:00
|
|
|
//-------------------------------------
|
|
|
|
// External API
|
|
|
|
//-------------------------------------
|
|
|
|
|
2015-02-28 17:12:35 +01:00
|
|
|
int VapourSynthCheckThread::detect(QString &path, VapourSynthType &type)
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
|
|
|
path.clear();
|
2015-02-28 17:12:35 +01:00
|
|
|
type &= 0;
|
2013-08-07 15:34:02 +02:00
|
|
|
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()));
|
2013-08-07 15:34:02 +02:00
|
|
|
|
|
|
|
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 -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(thread.getException())
|
|
|
|
{
|
|
|
|
qWarning("VapourSynth thread encountered an exception !!!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-02-28 17:12:35 +01:00
|
|
|
if(!!thread.getSuccess())
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
2015-02-28 17:12:35 +01:00
|
|
|
type |= thread.getSuccess();
|
2013-08-07 15:34:02 +02:00
|
|
|
path = thread.getPath();
|
|
|
|
qDebug("VapourSynth check completed successfully.");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
qWarning("VapourSynth thread failed to detect installation!");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------
|
|
|
|
// Thread class
|
|
|
|
//-------------------------------------
|
|
|
|
|
|
|
|
VapourSynthCheckThread::VapourSynthCheckThread(void)
|
|
|
|
{
|
2015-02-28 17:12:35 +01:00
|
|
|
m_success &= 0;
|
2013-08-07 15:34:02 +02:00
|
|
|
m_exception = false;
|
|
|
|
m_vpsPath.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
VapourSynthCheckThread::~VapourSynthCheckThread(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void VapourSynthCheckThread::run(void)
|
|
|
|
{
|
2015-02-28 17:12:35 +01:00
|
|
|
m_success &= 0;
|
2015-02-27 19:05:18 +01:00
|
|
|
m_exception = false;
|
2015-02-28 17:12:35 +01:00
|
|
|
m_vpsPath.clear();
|
2015-02-27 19:05:18 +01:00
|
|
|
|
2015-02-28 17:12:35 +01:00
|
|
|
detectVapourSynthPath1(m_success, m_vpsPath, &m_exception);
|
2013-08-07 15:34:02 +02:00
|
|
|
}
|
|
|
|
|
2015-02-28 17:12:35 +01:00
|
|
|
void VapourSynthCheckThread::detectVapourSynthPath1(VapourSynthType &success, QString &path, volatile bool *exception)
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
|
|
|
__try
|
|
|
|
{
|
2015-02-28 17:12:35 +01:00
|
|
|
return detectVapourSynthPath2(success, path, exception);
|
2013-08-07 15:34:02 +02:00
|
|
|
}
|
|
|
|
__except(1)
|
|
|
|
{
|
|
|
|
*exception = true;
|
|
|
|
qWarning("Unhandled exception error in VapourSynth thread !!!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-28 17:12:35 +01:00
|
|
|
void VapourSynthCheckThread::detectVapourSynthPath2(VapourSynthType &success, QString &path, volatile bool *exception)
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2015-02-28 17:12:35 +01:00
|
|
|
return detectVapourSynthPath3(success, path);
|
2013-08-07 15:34:02 +02:00
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
|
|
|
*exception = true;
|
|
|
|
qWarning("VapourSynth initializdation raised an C++ exception!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-28 17:12:35 +01:00
|
|
|
void VapourSynthCheckThread::detectVapourSynthPath3(VapourSynthType &success, QString &path)
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
2015-02-28 17:12:35 +01:00
|
|
|
success &= 0;
|
2013-08-07 15:34:02 +02:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
|
//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++)
|
|
|
|
{
|
|
|
|
vapoursynthPath = cleanDir(x264_query_reg_string(false, VPS_REG_KEYS[i], VPS_REG_NAME[j]));
|
|
|
|
if(VALID_DIR(vapoursynthPath)) break;
|
|
|
|
}
|
|
|
|
if(VALID_DIR(vapoursynthPath)) break;
|
|
|
|
}
|
2013-08-07 15:34:02 +02:00
|
|
|
|
2013-11-08 17:39:16 +01:00
|
|
|
//Make sure VapourSynth does exist
|
|
|
|
if(!VALID_DIR(vapoursynthPath))
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
2014-05-05 15:07:31 +02:00
|
|
|
qWarning("VapourSynth install path not found -> disable VapouSynth support!");
|
2015-02-28 17:12:35 +01:00
|
|
|
return;
|
2013-08-07 15:34:02 +02:00
|
|
|
}
|
|
|
|
|
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))
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
2015-02-27 19:05:18 +01:00
|
|
|
if(vpsExeFile32 && checkVapourSynth(vpsExeFile32->fileName()))
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
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);
|
2013-08-07 15:34:02 +02:00
|
|
|
}
|
2015-02-27 19:05:18 +01:00
|
|
|
else
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
2015-02-27 19:05:18 +01:00
|
|
|
qWarning("VapourSynth 32-Bit edition was found, but version check has failed!");
|
2013-08-07 15:34:02 +02:00
|
|
|
}
|
|
|
|
}
|
2015-02-27 19:05:18 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
qDebug("VapourSynth 32-Bit edition *not* found!");
|
|
|
|
}
|
2013-08-07 15:34:02 +02:00
|
|
|
|
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
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
2015-02-27 19:05:18 +01:00
|
|
|
qDebug("VapourSynth 64-Bit edition *not* found!");
|
2014-05-05 15:07:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//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)
|
2014-05-05 15:07:31 +02:00
|
|
|
{
|
|
|
|
QProcess process;
|
|
|
|
QStringList output;
|
|
|
|
|
|
|
|
//Setup process object
|
|
|
|
process.setWorkingDirectory(QDir::tempPath());
|
|
|
|
process.setProcessChannelMode(QProcess::MergedChannels);
|
|
|
|
process.setReadChannel(QProcess::StandardOutput);
|
|
|
|
|
|
|
|
//Try to start VSPIPE.EXE
|
2014-08-13 16:07:57 +02:00
|
|
|
process.start(vspipePath, QStringList() << "--version");
|
2014-05-05 15:07:31 +02:00
|
|
|
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))
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
2014-05-05 15:07:31 +02:00
|
|
|
while(process.canReadLine())
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
2014-05-05 15:07:31 +02:00
|
|
|
output << QString::fromUtf8(process.readLine()).simplified();
|
2013-08-07 15:34:02 +02:00
|
|
|
}
|
2014-05-05 15:07:31 +02:00
|
|
|
continue;
|
2013-08-07 15:34:02 +02:00
|
|
|
}
|
2014-05-05 15:07:31 +02:00
|
|
|
if(process.state() != QProcess::NotRunning)
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
2014-05-05 15:07:31 +02:00
|
|
|
qWarning("VSPIPE.EXE process encountered a deadlock -> aborting now!");
|
|
|
|
break;
|
2013-08-07 15:34:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-05 15:07:31 +02:00
|
|
|
//Make sure VSPIPE.EXE has terminated!
|
|
|
|
process.waitForFinished(2500);
|
|
|
|
if(process.state() != QProcess::NotRunning)
|
2013-08-07 15:34:02 +02:00
|
|
|
{
|
2014-05-05 15:07:31 +02:00
|
|
|
qWarning("VSPIPE.EXE process still running, going to kill it!");
|
|
|
|
process.kill();
|
|
|
|
process.waitForFinished(-1);
|
2013-08-07 15:34:02 +02:00
|
|
|
}
|
|
|
|
|
2014-05-05 15:07:31 +02:00
|
|
|
//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
|
2014-05-06 00:22:18 +02:00
|
|
|
bool vapoursynthLogo = false;
|
2014-05-05 15:07:31 +02:00
|
|
|
for(QStringList::ConstIterator iter = output.constBegin(); iter != output.constEnd(); iter++)
|
|
|
|
{
|
|
|
|
if(vpsLogo.lastIndexIn(*iter) >= 0)
|
|
|
|
{
|
|
|
|
vapoursynthLogo = true;
|
2014-05-06 00:22:18 +02:00
|
|
|
break;
|
2014-05-05 15:07:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Minimum required version found?
|
2014-05-06 00:22:18 +02:00
|
|
|
if(vapoursynthLogo)
|
2014-05-05 15:07:31 +02:00
|
|
|
{
|
2015-02-27 19:05:18 +01:00
|
|
|
qDebug("VapourSynth version was detected successfully.");
|
2014-05-05 15:07:31 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Failed to determine version
|
2015-02-27 19:05:18 +01:00
|
|
|
qWarning("Failed to determine VapourSynth version!");
|
2014-05-05 15:07:31 +02:00
|
|
|
return false;
|
2013-08-07 15:34:02 +02:00
|
|
|
}
|