2013-08-07 15:34:02 +02:00
///////////////////////////////////////////////////////////////////////////////
// Simple x264 Launcher
2016-01-01 23:59:55 +01:00
// Copyright (C) 2004-2016 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>
2016-03-11 19:08:29 +01:00
# include <MUtils/Registry.h>
2015-02-02 22:11:06 +01:00
//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-03-01 22:00:05 +01:00
# include "model_sysinfo.h"
2013-08-07 15:34:02 +02:00
2015-02-27 19:05:18 +01:00
//CRT
# include <cassert>
2015-03-01 22:00:05 +01:00
//Static
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())
2015-03-01 22:00:05 +01:00
# 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 ;
}
2013-08-07 15:34:02 +02:00
//-------------------------------------
// External API
//-------------------------------------
2015-03-01 22:00:05 +01:00
bool VapourSynthCheckThread : : detect ( SysinfoModel * sysinfo )
2013-08-07 15:34:02 +02:00
{
2015-03-01 22:00:05 +01:00
sysinfo - > clearVapourSynth ( ) ;
sysinfo - > clearVPSPath ( ) ;
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 ( ) ;
2015-03-01 22:00:05 +01:00
return false ;
2013-08-07 15:34:02 +02:00
}
if ( thread . getException ( ) )
{
qWarning ( " VapourSynth thread encountered an exception !!! " ) ;
2015-03-01 22:00:05 +01:00
return false ;
2013-08-07 15:34:02 +02:00
}
2015-03-01 22:00:05 +01:00
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
2013-08-07 15:34:02 +02:00
{
2015-03-01 22:00:05 +01:00
qWarning ( " VapourSynth could not be found -> VapourSynth support disabled! " ) ;
2013-08-07 15:34:02 +02:00
}
2015-03-01 22:00:05 +01:00
return true ;
2013-08-07 15:34:02 +02:00
}
//-------------------------------------
// 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-03-01 22:00:05 +01:00
void VapourSynthCheckThread : : detectVapourSynthPath1 ( int & 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-03-01 22:00:05 +01:00
void VapourSynthCheckThread : : detectVapourSynthPath2 ( int & 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-03-01 22:00:05 +01:00
void VapourSynthCheckThread : : detectVapourSynthPath3 ( int & 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
} ;
2016-03-11 19:08:29 +01:00
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 + + )
{
2016-03-11 19:08:29 +01:00
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-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
}