1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2016 LoRd_MuldeR <MuldeR2@GMX.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
22 #include "thread_vapoursynth.h"
25 #include <MUtils/OSSupport.h>
26 #include <MUtils/Registry.h>
32 #include <QMutexLocker>
33 #include <QApplication>
39 #include "model_sysinfo.h"
45 QMutex
VapourSynthCheckThread::m_vpsLock
;
46 QScopedPointer
<QFile
> VapourSynthCheckThread::m_vpsExePath
[2];
47 QScopedPointer
<QFile
> VapourSynthCheckThread::m_vpsDllPath
[2];
49 #define VALID_DIR(STR) ((!(STR).isEmpty()) && QDir((STR)).exists())
50 #define BOOLIFY(X) ((X) ? '1' : '0')
52 static inline QString
&cleanDir(QString
&path
)
56 path
= QDir::fromNativeSeparators(path
);
57 while(path
.endsWith('/'))
65 //-------------------------------------
67 //-------------------------------------
69 bool VapourSynthCheckThread::detect(SysinfoModel
*sysinfo
)
71 sysinfo
->clearVapourSynth();
72 sysinfo
->clearVPSPath();
74 QMutexLocker
lock(&m_vpsLock
);
77 VapourSynthCheckThread thread
;
79 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor
));
81 connect(&thread
, SIGNAL(finished()), &loop
, SLOT(quit()));
82 connect(&thread
, SIGNAL(terminated()), &loop
, SLOT(quit()));
85 QTimer::singleShot(15000, &loop
, SLOT(quit()));
87 qDebug("VapourSynth thread has been created, please wait...");
88 loop
.exec(QEventLoop::ExcludeUserInputEvents
);
89 qDebug("VapourSynth thread finished.");
91 QApplication::restoreOverrideCursor();
93 if(!thread
.wait(1000))
95 qWarning("VapourSynth thread encountered timeout -> probably deadlock!");
101 if(thread
.getException())
103 qWarning("VapourSynth thread encountered an exception !!!");
107 if(thread
.getSuccess())
109 sysinfo
->setVapourSynth(SysinfoModel::VapourSynth_X86
, thread
.getSuccess() & VAPOURSYNTH_X86
);
110 sysinfo
->setVapourSynth(SysinfoModel::VapourSynth_X64
, thread
.getSuccess() & VAPOURSYNTH_X64
);
111 sysinfo
->setVPSPath(thread
.getPath());
112 qDebug("VapourSynth support is officially enabled now! [x86=%c, x64=%c]", BOOLIFY(sysinfo
->getVapourSynth(SysinfoModel::VapourSynth_X86
)), BOOLIFY(sysinfo
->getVapourSynth(SysinfoModel::VapourSynth_X64
)));
116 qWarning("VapourSynth could not be found -> VapourSynth support disabled!");
122 //-------------------------------------
124 //-------------------------------------
126 VapourSynthCheckThread::VapourSynthCheckThread(void)
133 VapourSynthCheckThread::~VapourSynthCheckThread(void)
137 void VapourSynthCheckThread::run(void)
143 detectVapourSynthPath1(m_success
, m_vpsPath
, &m_exception
);
146 void VapourSynthCheckThread::detectVapourSynthPath1(int &success
, QString
&path
, volatile bool *exception
)
150 return detectVapourSynthPath2(success
, path
, exception
);
155 qWarning("Unhandled exception error in VapourSynth thread !!!");
159 void VapourSynthCheckThread::detectVapourSynthPath2(int &success
, QString
&path
, volatile bool *exception
)
163 return detectVapourSynthPath3(success
, path
);
168 qWarning("VapourSynth initializdation raised an C++ exception!");
172 void VapourSynthCheckThread::detectVapourSynthPath3(int &success
, QString
&path
)
177 static const char *VPS_REG_KEYS
[] =
179 "SOFTWARE\\VapourSynth",
180 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VapourSynth_is1",
183 static const char *VPS_REG_NAME
[] =
187 "Inno Setup: App Path",
190 static const MUtils::Registry::reg_scope_t REG_SCOPE
[3] =
192 MUtils::Registry::scope_default
,
193 MUtils::Registry::scope_wow_x32
,
194 MUtils::Registry::scope_wow_x64
197 //Read VapourSynth path from registry
198 QString vapoursynthPath
;
199 for(size_t i
= 0; VPS_REG_KEYS
[i
]; i
++)
201 for(size_t j
= 0; VPS_REG_NAME
[j
]; j
++)
203 for (size_t k
= 0; k
< 3; k
++)
206 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
]))
208 temp
= cleanDir(temp
);
211 vapoursynthPath
= temp
;
216 if (!vapoursynthPath
.isEmpty())
221 if (!vapoursynthPath
.isEmpty())
227 //Make sure VapourSynth does exist
228 if(!VALID_DIR(vapoursynthPath
))
230 qWarning("VapourSynth install path not found -> disable VapouSynth support!");
234 qDebug("VapourSynth Dir: %s", vapoursynthPath
.toUtf8().constData());
236 //Look for 32-Bit edition of VapourSynth first
237 QFile
*vpsExeFile32
, *vpsDllFile32
;
238 if(isVapourSynthComplete(QString("%1/core32").arg(vapoursynthPath
), vpsExeFile32
, vpsDllFile32
))
240 if(vpsExeFile32
&& checkVapourSynth(vpsExeFile32
->fileName()))
242 success
|= VAPOURSYNTH_X86
;
243 qDebug("VapourSynth 32-Bit edition found!");
244 m_vpsExePath
[0].reset(vpsExeFile32
);
245 m_vpsDllPath
[0].reset(vpsDllFile32
);
249 qWarning("VapourSynth 32-Bit edition was found, but version check has failed!");
254 qDebug("VapourSynth 32-Bit edition *not* found!");
257 //Look for 64-Bit edition of VapourSynth next
258 QFile
*vpsExeFile64
, *vpsDllFile64
;
259 if(isVapourSynthComplete(QString("%1/core64").arg(vapoursynthPath
), vpsExeFile64
, vpsDllFile64
))
261 if(vpsExeFile64
&& checkVapourSynth(vpsExeFile64
->fileName()))
263 success
|= VAPOURSYNTH_X64
;
264 qDebug("VapourSynth 64-Bit edition found!");
265 m_vpsExePath
[1].reset(vpsExeFile64
);
266 m_vpsDllPath
[1].reset(vpsDllFile64
);
270 qWarning("VapourSynth 64-Bit edition was found, but version check has failed!");
275 qDebug("VapourSynth 64-Bit edition *not* found!");
278 //Return VapourSynth path
281 path
= vapoursynthPath
;
285 bool VapourSynthCheckThread::isVapourSynthComplete(const QString
&vsCorePath
, QFile
*&vpsExeFile
, QFile
*&vpsDllFile
)
287 bool complete
= false;
288 vpsExeFile
= vpsDllFile
= NULL
;
290 QFileInfo
vpsExeInfo(QString("%1/vspipe.exe" ).arg(vsCorePath
));
291 QFileInfo
vpsDllInfo(QString("%1/vapoursynth.dll").arg(vsCorePath
));
293 qDebug("VapourSynth EXE: %s", vpsExeInfo
.absoluteFilePath().toUtf8().constData());
294 qDebug("VapourSynth DLL: %s", vpsDllInfo
.absoluteFilePath().toUtf8().constData());
296 if(vpsExeInfo
.exists() && vpsDllInfo
.exists())
298 vpsExeFile
= new QFile(vpsExeInfo
.canonicalFilePath());
299 vpsDllFile
= new QFile(vpsDllInfo
.canonicalFilePath());
300 if(vpsExeFile
->open(QIODevice::ReadOnly
) && vpsDllFile
->open(QIODevice::ReadOnly
))
302 complete
= MUtils::OS::is_executable_file(vpsExeFile
->fileName());
308 MUTILS_DELETE(vpsExeFile
);
309 MUTILS_DELETE(vpsDllFile
);
315 bool VapourSynthCheckThread::checkVapourSynth(const QString
&vspipePath
)
320 //Setup process object
321 process
.setWorkingDirectory(QDir::tempPath());
322 process
.setProcessChannelMode(QProcess::MergedChannels
);
323 process
.setReadChannel(QProcess::StandardOutput
);
325 //Try to start VSPIPE.EXE
326 process
.start(vspipePath
, QStringList() << "--version");
327 if(!process
.waitForStarted())
329 qWarning("Failed to launch VSPIPE.EXE -> %s", process
.errorString().toUtf8().constData());
333 //Wait for process to finish
334 while(process
.state() != QProcess::NotRunning
)
336 if(process
.waitForReadyRead(12000))
338 while(process
.canReadLine())
340 output
<< QString::fromUtf8(process
.readLine()).simplified();
344 if(process
.state() != QProcess::NotRunning
)
346 qWarning("VSPIPE.EXE process encountered a deadlock -> aborting now!");
351 //Make sure VSPIPE.EXE has terminated!
352 process
.waitForFinished(2500);
353 if(process
.state() != QProcess::NotRunning
)
355 qWarning("VSPIPE.EXE process still running, going to kill it!");
357 process
.waitForFinished(-1);
361 while(process
.canReadLine())
363 output
<< QString::fromUtf8(process
.readLine()).simplified();
367 if(process
.exitCode() != 0)
369 qWarning("VSPIPE.EXE failed with code 0x%08X -> disable Vapousynth support!", process
.exitCode());
373 //Init regular expressions
374 QRegExp
vpsLogo("VapourSynth\\s+Video\\s+Processing\\s+Library");
376 //Check for version info
377 bool vapoursynthLogo
= false;
378 for(QStringList::ConstIterator iter
= output
.constBegin(); iter
!= output
.constEnd(); iter
++)
380 if(vpsLogo
.lastIndexIn(*iter
) >= 0)
382 vapoursynthLogo
= true;
387 //Minimum required version found?
390 qDebug("VapourSynth version was detected successfully.");
394 //Failed to determine version
395 qWarning("Failed to determine VapourSynth version!");