1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2014 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 static const unsigned int VAPOURSYNTH_VERSION_MIN = 20;
36 QMutex VapourSynthCheckThread::m_vpsLock;
37 QFile *VapourSynthCheckThread::m_vpsExePath = NULL;
38 QFile *VapourSynthCheckThread::m_vpsDllPath = NULL;
39 QLibrary *VapourSynthCheckThread::m_vpsLib = NULL;
41 #define VALID_DIR(STR) ((!(STR).isEmpty()) && QDir((STR)).exists())
43 static inline QString &cleanDir(QString &path)
47 path = QDir::fromNativeSeparators(path);
48 while(path.endsWith('/'))
56 //-------------------------------------
58 //-------------------------------------
60 int VapourSynthCheckThread::detect(QString &path)
63 QMutexLocker lock(&m_vpsLock);
66 VapourSynthCheckThread thread;
68 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
70 connect(&thread, SIGNAL(finished()), &loop, SLOT(quit()));
71 connect(&thread, SIGNAL(terminated()), &loop, SLOT(quit()));
74 QTimer::singleShot(15000, &loop, SLOT(quit()));
76 qDebug("VapourSynth thread has been created, please wait...");
77 loop.exec(QEventLoop::ExcludeUserInputEvents);
78 qDebug("VapourSynth thread finished.");
80 QApplication::restoreOverrideCursor();
82 if(!thread.wait(1000))
84 qWarning("VapourSynth thread encountered timeout -> probably deadlock!");
90 if(thread.getException())
92 qWarning("VapourSynth thread encountered an exception !!!");
96 if(thread.getSuccess())
98 path = thread.getPath();
99 qDebug("VapourSynth check completed successfully.");
103 qWarning("VapourSynth thread failed to detect installation!");
107 void VapourSynthCheckThread::unload(void)
109 QMutexLocker lock(&m_vpsLock);
113 if(m_vpsLib->isLoaded())
121 if (m_vpsExePath->isOpen())
123 m_vpsExePath->close();
129 if(m_vpsDllPath->isOpen())
131 m_vpsDllPath->close();
135 X264_DELETE(m_vpsExePath);
136 X264_DELETE(m_vpsDllPath);
137 X264_DELETE(m_vpsLib);
140 //-------------------------------------
142 //-------------------------------------
144 VapourSynthCheckThread::VapourSynthCheckThread(void)
151 VapourSynthCheckThread::~VapourSynthCheckThread(void)
155 void VapourSynthCheckThread::run(void)
157 m_exception = m_success = false;
158 m_success = detectVapourSynthPath1(m_vpsPath, &m_exception);
161 bool VapourSynthCheckThread::detectVapourSynthPath1(QString &path, volatile bool *exception)
165 return detectVapourSynthPath2(path, exception);
170 qWarning("Unhandled exception error in VapourSynth thread !!!");
175 bool VapourSynthCheckThread::detectVapourSynthPath2(QString &path, volatile bool *exception)
179 return detectVapourSynthPath3(path);
184 qWarning("VapourSynth initializdation raised an C++ exception!");
189 bool VapourSynthCheckThread::detectVapourSynthPath3(QString &path)
191 bool success = false;
192 X264_DELETE(m_vpsExePath);
193 X264_DELETE(m_vpsDllPath);
196 static const char *VPS_REG_KEYS[] =
198 "SOFTWARE\\VapourSynth",
199 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VapourSynth_is1",
202 static const char *VPS_REG_NAME[] =
206 "Inno Setup: App Path",
210 //Read VapourSynth path from registry
211 QString vapoursynthPath;
212 for(size_t i = 0; VPS_REG_KEYS[i]; i++)
214 for(size_t j = 0; VPS_REG_NAME[j]; j++)
216 vapoursynthPath = cleanDir(x264_query_reg_string(false, VPS_REG_KEYS[i], VPS_REG_NAME[j]));
217 if(VALID_DIR(vapoursynthPath)) break;
219 if(VALID_DIR(vapoursynthPath)) break;
222 //Make sure VapourSynth does exist
223 if(!VALID_DIR(vapoursynthPath))
225 qWarning("VapourSynth install path not found -> disable VapouSynth support!");
226 vapoursynthPath.clear();
229 //Make sure that 'vapoursynth.dll' and 'vspipe.exe' are available
230 bool vapoursynthComplete = false;
231 if(!vapoursynthPath.isEmpty())
233 static const char *CORE_PATH[3] = { "core32", "core64", "core" };
234 qDebug("VapourSynth Dir: %s", vapoursynthPath.toUtf8().constData());
235 for(int i = 0; (i < 3) && (!vapoursynthComplete); i++)
237 QFileInfo vpsExeInfo(QString("%1/%2/vspipe.exe" ).arg(vapoursynthPath, CORE_PATH[i]));
238 QFileInfo vpsDllInfo(QString("%1/%2/vapoursynth.dll").arg(vapoursynthPath, CORE_PATH[i]));
239 qDebug("VapourSynth EXE: %s", vpsExeInfo.absoluteFilePath().toUtf8().constData());
240 qDebug("VapourSynth DLL: %s", vpsDllInfo.absoluteFilePath().toUtf8().constData());
241 if(vpsExeInfo.exists() && vpsDllInfo.exists())
243 m_vpsExePath = new QFile(vpsExeInfo.canonicalFilePath());
244 m_vpsDllPath = new QFile(vpsDllInfo.canonicalFilePath());
245 if(m_vpsExePath->open(QIODevice::ReadOnly) && m_vpsDllPath->open(QIODevice::ReadOnly))
247 if(vapoursynthComplete = x264_is_executable(m_vpsExePath->fileName()))
249 vapoursynthPath.append("/").append(CORE_PATH[i]);
253 X264_DELETE(m_vpsExePath);
254 X264_DELETE(m_vpsDllPath);
257 if(!vapoursynthComplete)
259 qWarning("VapourSynth installation incomplete -> disable VapouSynth support!");
263 //Make sure 'vsscript.dll' can be loaded successfully
264 if(vapoursynthComplete && m_vpsExePath)
266 qDebug("VapourSynth detection is running, please stand by...");
267 success = checkVapourSynthVersion(m_vpsExePath->fileName());
270 //Return VapourSynth path
273 path = vapoursynthPath;
279 bool VapourSynthCheckThread::checkVapourSynthVersion(const QString vspipePath)
284 //Setup process object
285 process.setWorkingDirectory(QDir::tempPath());
286 process.setProcessChannelMode(QProcess::MergedChannels);
287 process.setReadChannel(QProcess::StandardOutput);
289 //Try to start VSPIPE.EXE
290 process.start(vspipePath, QStringList() << "-version");
291 if(!process.waitForStarted())
293 qWarning("Failed to launch VSPIPE.EXE -> %s", process.errorString().toUtf8().constData());
297 //Wait for process to finish
298 while(process.state() != QProcess::NotRunning)
300 if(process.waitForReadyRead(12000))
302 while(process.canReadLine())
304 output << QString::fromUtf8(process.readLine()).simplified();
308 if(process.state() != QProcess::NotRunning)
310 qWarning("VSPIPE.EXE process encountered a deadlock -> aborting now!");
315 //Make sure VSPIPE.EXE has terminated!
316 process.waitForFinished(2500);
317 if(process.state() != QProcess::NotRunning)
319 qWarning("VSPIPE.EXE process still running, going to kill it!");
321 process.waitForFinished(-1);
325 while(process.canReadLine())
327 output << QString::fromUtf8(process.readLine()).simplified();
331 if(process.exitCode() != 0)
333 qWarning("VSPIPE.EXE failed with code 0x%08X -> disable Vapousynth support!", process.exitCode());
337 //Init regular expressions
338 unsigned int vapursynthVersion = 0;
339 bool vapoursynthLogo = false;
340 QRegExp vpsLogo("VapourSynth\\s+Video\\s+Processing\\s+Library");
341 QRegExp vpsCore("Core\\s+r(\\d+)");
343 //Check for version info
344 for(QStringList::ConstIterator iter = output.constBegin(); iter != output.constEnd(); iter++)
346 if(vpsLogo.lastIndexIn(*iter) >= 0)
348 vapoursynthLogo = true;
351 if(vapoursynthLogo && (vpsCore.lastIndexIn(*iter) >= 0))
354 const unsigned int temp = vpsCore.cap(1).toUInt(&ok);
355 if(ok) vapursynthVersion = temp;
359 //Minimum required version found?
360 if(vapoursynthLogo && (vapursynthVersion > 0))
362 qDebug("VapourSynth version \"Core r%u\" detected.", vapursynthVersion);
363 if(vapursynthVersion < VAPOURSYNTH_VERSION_MIN)
365 qWarning("VapourSynth version is too old -> disable Vapousynth support!");
371 //Failed to determine version
372 qWarning("Failed to determine VapourSynth version -> disable Vapousynth support!");
373 qWarning("VapourSynth version is unsupported or VapourSynth installation is corrupted.");