1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2019 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>
31 #include <QApplication>
37 #include "model_sysinfo.h"
43 QMutex VapourSynthCheckThread::m_vpsLock;
44 QScopedPointer<QFile> VapourSynthCheckThread::m_vpsExePath[2];
45 QScopedPointer<QFile> VapourSynthCheckThread::m_vpsDllPath[2];
48 static const char* const VPS_REG_KEYS = "SOFTWARE\\VapourSynth";
49 static const char* const VPS_REG_NAME = "VapourSynthDLL";
51 //Default VapurSynth architecture
52 #if _WIN64 || __x86_64__
53 #define VAPOURSYNTH_DEF VAPOURSYNTH_X64
55 #define VAPOURSYNTH_DEF VAPOURSYNTH_X86;
58 //Enable detection of "portabel" edition?
59 #define ENABLE_PORTABLE_VPS true
61 //-------------------------------------
63 //-------------------------------------
65 #define BOOLIFY(X) ((X) ? '1' : '0')
66 #define VPS_BITNESS(X) (((X) + 1U) * 32U)
68 static inline bool VALID_DIR(const QString &path)
70 return (!path.isEmpty()) && QDir(path).exists();
73 //-------------------------------------
75 //-------------------------------------
77 bool VapourSynthCheckThread::detect(SysinfoModel* sysinfo)
79 QMutexLocker lock(&m_vpsLock);
81 sysinfo->clearVapourSynth();
82 sysinfo->clearVPS32Path();
83 sysinfo->clearVPS64Path();
86 VapourSynthCheckThread thread;
88 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
90 connect(&thread, SIGNAL(finished()), &loop, SLOT(quit()));
91 connect(&thread, SIGNAL(terminated()), &loop, SLOT(quit()));
94 QTimer::singleShot(30000, &loop, SLOT(quit()));
96 qDebug("VapourSynth thread has been created, please wait...");
97 loop.exec(QEventLoop::ExcludeUserInputEvents);
98 qDebug("VapourSynth thread finished.");
100 QApplication::restoreOverrideCursor();
102 if (!thread.wait(1000))
104 qWarning("VapourSynth thread encountered timeout -> probably deadlock!");
110 if (thread.getException())
112 qWarning("VapourSynth thread encountered an exception !!!");
116 const int success = thread.getSuccess();
119 qWarning("VapourSynth could not be found -> VapourSynth support disabled!");
123 if (success & VAPOURSYNTH_X86)
125 sysinfo->setVapourSynth(SysinfoModel::VapourSynth_X86, true);
126 sysinfo->setVPS32Path(thread.getPath32());
129 if (success & VAPOURSYNTH_X64)
131 sysinfo->setVapourSynth(SysinfoModel::VapourSynth_X64, true);
132 sysinfo->setVPS64Path(thread.getPath64());
135 qDebug("VapourSynth support is officially enabled now! [x86=%c, x64=%c]", BOOLIFY(sysinfo->getVapourSynth(SysinfoModel::VapourSynth_X86)), BOOLIFY(sysinfo->getVapourSynth(SysinfoModel::VapourSynth_X64)));
139 //-------------------------------------
141 //-------------------------------------
143 VapourSynthCheckThread::VapourSynthCheckThread(void)
145 m_vpsPath[0U].clear();
146 m_vpsPath[1U].clear();
149 VapourSynthCheckThread::~VapourSynthCheckThread(void)
153 void VapourSynthCheckThread::run(void)
155 m_vpsPath[0U].clear();
156 m_vpsPath[1U].clear();
160 int VapourSynthCheckThread::threadMain(void)
162 static const int VPS_BIT_FLAG[] =
168 static const MUtils::Registry::reg_scope_t REG_SCOPE[3] =
170 MUtils::Registry::scope_wow_x32,
171 MUtils::Registry::scope_wow_x64,
172 MUtils::Registry::scope_default
175 QHash<int, QString> vapoursynthPath;
178 //Look for "portable" VapourSynth version
179 for (size_t i = 0; i < 2U; i++)
181 const QString vpsPortableDir = QString("%1/extra/VapourSynth-%2").arg(QCoreApplication::applicationDirPath(), QString::number(VPS_BITNESS(i)));
182 if (VALID_DIR(vpsPortableDir))
184 const QFileInfo vpsPortableFile = QFileInfo(QString("%1/vspipe.exe").arg(vpsPortableDir));
185 if (vpsPortableFile.exists() && vpsPortableFile.isFile())
187 vapoursynthPath.insert(VPS_BIT_FLAG[i], vpsPortableDir);
192 //Read VapourSynth path from the registry
193 if (vapoursynthPath.isEmpty())
195 for (size_t i = 0; i < 3U; i++)
197 if (MUtils::Registry::reg_key_exists(MUtils::Registry::root_machine, QString::fromLatin1(VPS_REG_KEYS), REG_SCOPE[i]))
200 if (MUtils::Registry::reg_value_read(MUtils::Registry::root_machine, QString::fromLatin1(VPS_REG_KEYS), QString::fromLatin1(VPS_REG_NAME), vpsDllPath, REG_SCOPE[i]))
202 const QFileInfo vpsDllInfo(QDir::fromNativeSeparators(vpsDllPath));
203 if (vpsDllInfo.exists() && vpsDllInfo.isFile())
205 const QString vpsCorePath = vpsDllInfo.canonicalPath();
206 if (!vpsCorePath.isEmpty())
208 const int flag = getVapourSynthType(REG_SCOPE[i]);
209 if (!vapoursynthPath.contains(flag))
211 vapoursynthPath.insert(flag, vpsCorePath);
220 //Make sure VapourSynth directory does exist
221 if(vapoursynthPath.isEmpty())
223 qWarning("VapourSynth install path not found -> disable VapouSynth support!");
227 //Validate the VapourSynth installation now!
228 for (size_t i = 0; i < 2U; i++)
230 if (vapoursynthPath.contains(VPS_BIT_FLAG[i]))
232 const QString path = vapoursynthPath[VPS_BIT_FLAG[i]];
233 qDebug("VapourSynth %u-Bit \"core\" path: %s", VPS_BITNESS(i), MUTILS_UTF8(path));
234 QFile *vpsExeFile, *vpsDllFile;
235 if (isVapourSynthComplete(path, vpsExeFile, vpsDllFile))
237 if (vpsExeFile && checkVapourSynth(vpsExeFile->fileName()))
239 qDebug("VapourSynth %u-Bit edition found!", VPS_BITNESS(i));
240 m_vpsExePath[i].reset(vpsExeFile);
241 m_vpsDllPath[i].reset(vpsDllFile);
243 flags |= VPS_BIT_FLAG[i];
247 qWarning("VapourSynth %u-Bit edition was found, but version check has failed!", VPS_BITNESS(i));
252 qWarning("VapourSynth %u-Bit edition was found, but appears to be incomplete!", VPS_BITNESS(i));
257 qDebug("VapourSynth %u-Bit edition *not* found!", VPS_BITNESS(i));
264 //-------------------------------------
265 // Internal functions
266 //-------------------------------------
268 VapourSynthCheckThread::VapourSynthFlags VapourSynthCheckThread::getVapourSynthType(const int scope)
272 case MUtils::Registry::scope_wow_x32:
273 return VAPOURSYNTH_X86;
274 case MUtils::Registry::scope_wow_x64:
275 return VAPOURSYNTH_X64;
277 return VAPOURSYNTH_DEF;
281 bool VapourSynthCheckThread::isVapourSynthComplete(const QString &vsCorePath, QFile *&vpsExeFile, QFile *&vpsDllFile)
283 bool complete = false;
284 vpsExeFile = vpsDllFile = NULL;
286 QFileInfo vpsExeInfo(QString("%1/vspipe.exe" ).arg(vsCorePath));
287 QFileInfo vpsDllInfo(QString("%1/vapoursynth.dll").arg(vsCorePath));
289 qDebug("VapourSynth EXE: %s", vpsExeInfo.absoluteFilePath().toUtf8().constData());
290 qDebug("VapourSynth DLL: %s", vpsDllInfo.absoluteFilePath().toUtf8().constData());
292 if(vpsExeInfo.exists() && vpsDllInfo.exists())
294 vpsExeFile = new QFile(vpsExeInfo.canonicalFilePath());
295 vpsDllFile = new QFile(vpsDllInfo.canonicalFilePath());
296 if(vpsExeFile->open(QIODevice::ReadOnly) && vpsDllFile->open(QIODevice::ReadOnly))
298 complete = MUtils::OS::is_executable_file(vpsExeFile->fileName());
304 MUTILS_DELETE(vpsExeFile);
305 MUTILS_DELETE(vpsDllFile);
311 bool VapourSynthCheckThread::checkVapourSynth(const QString &vspipePath)
313 //Try to run VSPIPE.EXE
314 const QStringList output = runProcess(vspipePath, QStringList() << "--version");
316 //Init regular expressions
317 QRegExp vpsLogo("VapourSynth\\s+Video\\s+Processing\\s+Library");
319 //Check for version info
320 bool vapoursynthLogo = false;
321 for(QStringList::ConstIterator iter = output.constBegin(); iter != output.constEnd(); iter++)
323 if(vpsLogo.lastIndexIn(*iter) >= 0)
325 vapoursynthLogo = true;
330 //Minimum required version found?
333 qDebug("VapourSynth version was detected successfully.");
337 //Failed to determine version
338 qWarning("Failed to determine VapourSynth version!");