1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2015 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"
27 #include <QMutexLocker>
28 #include <QApplication>
34 QMutex VapourSynthCheckThread::m_vpsLock;
35 QFile *VapourSynthCheckThread::m_vpsExePath = NULL;
36 QFile *VapourSynthCheckThread::m_vpsDllPath = NULL;
37 QLibrary *VapourSynthCheckThread::m_vpsLib = NULL;
39 #define VALID_DIR(STR) ((!(STR).isEmpty()) && QDir((STR)).exists())
41 static inline QString &cleanDir(QString &path)
45 path = QDir::fromNativeSeparators(path);
46 while(path.endsWith('/'))
54 //-------------------------------------
56 //-------------------------------------
58 int VapourSynthCheckThread::detect(QString &path)
61 QMutexLocker lock(&m_vpsLock);
64 VapourSynthCheckThread thread;
66 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
68 connect(&thread, SIGNAL(finished()), &loop, SLOT(quit()));
69 connect(&thread, SIGNAL(terminated()), &loop, SLOT(quit()));
72 QTimer::singleShot(15000, &loop, SLOT(quit()));
74 qDebug("VapourSynth thread has been created, please wait...");
75 loop.exec(QEventLoop::ExcludeUserInputEvents);
76 qDebug("VapourSynth thread finished.");
78 QApplication::restoreOverrideCursor();
80 if(!thread.wait(1000))
82 qWarning("VapourSynth thread encountered timeout -> probably deadlock!");
88 if(thread.getException())
90 qWarning("VapourSynth thread encountered an exception !!!");
94 if(thread.getSuccess())
96 path = thread.getPath();
97 qDebug("VapourSynth check completed successfully.");
101 qWarning("VapourSynth thread failed to detect installation!");
105 void VapourSynthCheckThread::unload(void)
107 QMutexLocker lock(&m_vpsLock);
111 if(m_vpsLib->isLoaded())
119 if (m_vpsExePath->isOpen())
121 m_vpsExePath->close();
127 if(m_vpsDllPath->isOpen())
129 m_vpsDllPath->close();
133 X264_DELETE(m_vpsExePath);
134 X264_DELETE(m_vpsDllPath);
135 X264_DELETE(m_vpsLib);
138 //-------------------------------------
140 //-------------------------------------
142 VapourSynthCheckThread::VapourSynthCheckThread(void)
149 VapourSynthCheckThread::~VapourSynthCheckThread(void)
153 void VapourSynthCheckThread::run(void)
155 m_exception = m_success = false;
156 m_success = detectVapourSynthPath1(m_vpsPath, &m_exception);
159 bool VapourSynthCheckThread::detectVapourSynthPath1(QString &path, volatile bool *exception)
163 return detectVapourSynthPath2(path, exception);
168 qWarning("Unhandled exception error in VapourSynth thread !!!");
173 bool VapourSynthCheckThread::detectVapourSynthPath2(QString &path, volatile bool *exception)
177 return detectVapourSynthPath3(path);
182 qWarning("VapourSynth initializdation raised an C++ exception!");
187 bool VapourSynthCheckThread::detectVapourSynthPath3(QString &path)
189 bool success = false;
190 X264_DELETE(m_vpsExePath);
191 X264_DELETE(m_vpsDllPath);
194 static const char *VPS_REG_KEYS[] =
196 "SOFTWARE\\VapourSynth",
197 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VapourSynth_is1",
200 static const char *VPS_REG_NAME[] =
204 "Inno Setup: App Path",
208 //Read VapourSynth path from registry
209 QString vapoursynthPath;
210 for(size_t i = 0; VPS_REG_KEYS[i]; i++)
212 for(size_t j = 0; VPS_REG_NAME[j]; j++)
214 vapoursynthPath = cleanDir(x264_query_reg_string(false, VPS_REG_KEYS[i], VPS_REG_NAME[j]));
215 if(VALID_DIR(vapoursynthPath)) break;
217 if(VALID_DIR(vapoursynthPath)) break;
220 //Make sure VapourSynth does exist
221 if(!VALID_DIR(vapoursynthPath))
223 qWarning("VapourSynth install path not found -> disable VapouSynth support!");
224 vapoursynthPath.clear();
227 //Make sure that 'vapoursynth.dll' and 'vspipe.exe' are available
228 bool vapoursynthComplete = false;
229 if(!vapoursynthPath.isEmpty())
231 static const char *CORE_PATH[3] = { "core32", "core64", "core" };
232 qDebug("VapourSynth Dir: %s", vapoursynthPath.toUtf8().constData());
233 for(int i = 0; (i < 3) && (!vapoursynthComplete); i++)
235 QFileInfo vpsExeInfo(QString("%1/%2/vspipe.exe" ).arg(vapoursynthPath, CORE_PATH[i]));
236 QFileInfo vpsDllInfo(QString("%1/%2/vapoursynth.dll").arg(vapoursynthPath, CORE_PATH[i]));
237 qDebug("VapourSynth EXE: %s", vpsExeInfo.absoluteFilePath().toUtf8().constData());
238 qDebug("VapourSynth DLL: %s", vpsDllInfo.absoluteFilePath().toUtf8().constData());
239 if(vpsExeInfo.exists() && vpsDllInfo.exists())
241 m_vpsExePath = new QFile(vpsExeInfo.canonicalFilePath());
242 m_vpsDllPath = new QFile(vpsDllInfo.canonicalFilePath());
243 if(m_vpsExePath->open(QIODevice::ReadOnly) && m_vpsDllPath->open(QIODevice::ReadOnly))
245 if(vapoursynthComplete = x264_is_executable(m_vpsExePath->fileName()))
247 vapoursynthPath.append("/").append(CORE_PATH[i]);
251 X264_DELETE(m_vpsExePath);
252 X264_DELETE(m_vpsDllPath);
255 if(!vapoursynthComplete)
257 qWarning("VapourSynth installation incomplete -> disable VapouSynth support!");
261 //Make sure 'vsscript.dll' can be loaded successfully
262 if(vapoursynthComplete && m_vpsExePath)
264 qDebug("VapourSynth detection is running, please stand by...");
265 success = checkVapourSynth(m_vpsExePath->fileName());
268 //Return VapourSynth path
271 path = vapoursynthPath;
277 bool VapourSynthCheckThread::checkVapourSynth(const QString vspipePath)
282 //Setup process object
283 process.setWorkingDirectory(QDir::tempPath());
284 process.setProcessChannelMode(QProcess::MergedChannels);
285 process.setReadChannel(QProcess::StandardOutput);
287 //Try to start VSPIPE.EXE
288 process.start(vspipePath, QStringList() << "--version");
289 if(!process.waitForStarted())
291 qWarning("Failed to launch VSPIPE.EXE -> %s", process.errorString().toUtf8().constData());
295 //Wait for process to finish
296 while(process.state() != QProcess::NotRunning)
298 if(process.waitForReadyRead(12000))
300 while(process.canReadLine())
302 output << QString::fromUtf8(process.readLine()).simplified();
306 if(process.state() != QProcess::NotRunning)
308 qWarning("VSPIPE.EXE process encountered a deadlock -> aborting now!");
313 //Make sure VSPIPE.EXE has terminated!
314 process.waitForFinished(2500);
315 if(process.state() != QProcess::NotRunning)
317 qWarning("VSPIPE.EXE process still running, going to kill it!");
319 process.waitForFinished(-1);
323 while(process.canReadLine())
325 output << QString::fromUtf8(process.readLine()).simplified();
329 if(process.exitCode() != 0)
331 qWarning("VSPIPE.EXE failed with code 0x%08X -> disable Vapousynth support!", process.exitCode());
335 //Init regular expressions
336 QRegExp vpsLogo("VapourSynth\\s+Video\\s+Processing\\s+Library");
338 //Check for version info
339 bool vapoursynthLogo = false;
340 for(QStringList::ConstIterator iter = output.constBegin(); iter != output.constEnd(); iter++)
342 if(vpsLogo.lastIndexIn(*iter) >= 0)
344 vapoursynthLogo = true;
349 //Minimum required version found?
352 qDebug("VapourSynth was detected successfully.");
356 //Failed to determine version
357 qWarning("Failed to determine VapourSynth version -> disable Vapousynth support!");
358 qWarning("VapourSynth version is unsupported or VapourSynth installation is corrupted.");