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>
32 #include <QApplication>
37 #include "model_sysinfo.h"
43 static const bool ENABLE_PORTABLE_VPS
= true;
46 QMutex
VapourSynthCheckThread::m_vpsLock
;
47 QScopedPointer
<QFile
> VapourSynthCheckThread::m_vpsExePath
[2];
48 QScopedPointer
<QFile
> VapourSynthCheckThread::m_vpsDllPath
[2];
50 #define VALID_DIR(STR) ((!(STR).isEmpty()) && QDir((STR)).exists())
51 #define BOOLIFY(X) ((X) ? '1' : '0')
52 #define VPS_BITNESS(X) (((X) + 1U) * 32U)
54 static inline QString
&cleanDir(QString
&path
)
58 path
= QDir::fromNativeSeparators(path
);
59 while(path
.endsWith('/'))
67 //-------------------------------------
69 //-------------------------------------
71 bool VapourSynthCheckThread::detect(SysinfoModel
*sysinfo
)
73 sysinfo
->clearVapourSynth();
74 sysinfo
->clearVPSPath();
76 QMutexLocker
lock(&m_vpsLock
);
79 VapourSynthCheckThread thread
;
81 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor
));
83 connect(&thread
, SIGNAL(finished()), &loop
, SLOT(quit()));
84 connect(&thread
, SIGNAL(terminated()), &loop
, SLOT(quit()));
87 QTimer::singleShot(30000, &loop
, SLOT(quit()));
89 qDebug("VapourSynth thread has been created, please wait...");
90 loop
.exec(QEventLoop::ExcludeUserInputEvents
);
91 qDebug("VapourSynth thread finished.");
93 QApplication::restoreOverrideCursor();
95 if(!thread
.wait(1000))
97 qWarning("VapourSynth thread encountered timeout -> probably deadlock!");
103 if(thread
.getException())
105 qWarning("VapourSynth thread encountered an exception !!!");
109 if(thread
.getSuccess())
111 sysinfo
->setVapourSynth(SysinfoModel::VapourSynth_X86
, thread
.getSuccess() & VAPOURSYNTH_X86
);
112 sysinfo
->setVapourSynth(SysinfoModel::VapourSynth_X64
, thread
.getSuccess() & VAPOURSYNTH_X64
);
113 sysinfo
->setVPSPath(thread
.getPath());
114 qDebug("VapourSynth support is officially enabled now! [x86=%c, x64=%c]", BOOLIFY(sysinfo
->getVapourSynth(SysinfoModel::VapourSynth_X86
)), BOOLIFY(sysinfo
->getVapourSynth(SysinfoModel::VapourSynth_X64
)));
118 qWarning("VapourSynth could not be found -> VapourSynth support disabled!");
124 //-------------------------------------
126 //-------------------------------------
128 VapourSynthCheckThread::VapourSynthCheckThread(void)
135 VapourSynthCheckThread::~VapourSynthCheckThread(void)
139 void VapourSynthCheckThread::run(void)
145 detectVapourSynthPath1(m_success
, m_vpsPath
, &m_exception
);
148 void VapourSynthCheckThread::detectVapourSynthPath1(int &success
, QString
&path
, volatile bool *exception
)
152 return detectVapourSynthPath2(success
, path
, exception
);
157 qWarning("Unhandled exception error in VapourSynth thread !!!");
161 void VapourSynthCheckThread::detectVapourSynthPath2(int &success
, QString
&path
, volatile bool *exception
)
165 return detectVapourSynthPath3(success
, path
);
170 qWarning("VapourSynth initializdation raised an C++ exception!");
174 void VapourSynthCheckThread::detectVapourSynthPath3(int &success
, QString
&path
)
179 static const char *VPS_CORE_DIR
[] =
185 static const int VPS_BIT_FLAG
[] =
191 static const char *VPS_REG_KEYS
[] =
193 "SOFTWARE\\VapourSynth",
194 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VapourSynth_is1",
197 static const char *VPS_REG_NAME
[] =
201 "Inno Setup: App Path",
204 static const MUtils::Registry::reg_scope_t REG_SCOPE
[3] =
206 MUtils::Registry::scope_default
,
207 MUtils::Registry::scope_wow_x32
,
208 MUtils::Registry::scope_wow_x64
211 QString vapoursynthPath
;
213 //Look for "portable" VapourSynth version
214 if (ENABLE_PORTABLE_VPS
)
216 const QString vpsPortableDir
= QString("%1/extra/VapourSynth").arg(QCoreApplication::applicationDirPath());
217 if (VALID_DIR(vpsPortableDir
))
219 for (size_t i
= 0; VPS_CORE_DIR
[i
]; i
++)
221 const QFileInfo vpsPortableDll
= QFileInfo(QString("%1/%2/VapourSynth.dll").arg(vpsPortableDir
, QString::fromLatin1(VPS_CORE_DIR
[i
])));
222 if (vpsPortableDll
.exists() && vpsPortableDll
.isFile())
224 vapoursynthPath
= vpsPortableDir
;
231 //Read VapourSynth path from registry
232 if (vapoursynthPath
.isEmpty())
234 for (size_t i
= 0; VPS_REG_KEYS
[i
]; i
++)
236 for (size_t j
= 0; VPS_REG_NAME
[j
]; j
++)
238 for (size_t k
= 0; k
< 3; k
++)
240 if (MUtils::Registry::reg_key_exists(MUtils::Registry::root_machine
, QString::fromLatin1(VPS_REG_KEYS
[i
]), REG_SCOPE
[k
]))
243 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
]))
245 temp
= cleanDir(temp
);
248 vapoursynthPath
= temp
;
254 if (!vapoursynthPath
.isEmpty())
259 if (!vapoursynthPath
.isEmpty())
266 //Make sure VapourSynth directory does exist
267 if(vapoursynthPath
.isEmpty())
269 qWarning("VapourSynth install path not found -> disable VapouSynth support!");
273 //Validate the VapourSynth installation now!
274 qDebug("VapourSynth Dir: %s", vapoursynthPath
.toUtf8().constData());
275 for (size_t i
= 0; VPS_CORE_DIR
[i
]; i
++)
277 QFile
*vpsExeFile
, *vpsDllFile
;
278 if (isVapourSynthComplete(QString("%1/%2").arg(vapoursynthPath
, QString::fromLatin1(VPS_CORE_DIR
[i
])), vpsExeFile
, vpsDllFile
))
280 if (vpsExeFile
&& checkVapourSynth(vpsExeFile
->fileName()))
282 success
|= VPS_BIT_FLAG
[i
];
283 qDebug("VapourSynth %u-Bit edition found!", VPS_BITNESS(i
));
284 m_vpsExePath
[i
].reset(vpsExeFile
);
285 m_vpsDllPath
[i
].reset(vpsDllFile
);
289 qWarning("VapourSynth %u-Bit edition was found, but version check has failed!", VPS_BITNESS(i
));
294 qDebug("VapourSynth %u-Bit edition *not* found!", VPS_BITNESS(i
));
298 //Return VapourSynth path
301 path
= vapoursynthPath
;
305 bool VapourSynthCheckThread::isVapourSynthComplete(const QString
&vsCorePath
, QFile
*&vpsExeFile
, QFile
*&vpsDllFile
)
307 bool complete
= false;
308 vpsExeFile
= vpsDllFile
= NULL
;
310 QFileInfo
vpsExeInfo(QString("%1/vspipe.exe" ).arg(vsCorePath
));
311 QFileInfo
vpsDllInfo(QString("%1/vapoursynth.dll").arg(vsCorePath
));
313 qDebug("VapourSynth EXE: %s", vpsExeInfo
.absoluteFilePath().toUtf8().constData());
314 qDebug("VapourSynth DLL: %s", vpsDllInfo
.absoluteFilePath().toUtf8().constData());
316 if(vpsExeInfo
.exists() && vpsDllInfo
.exists())
318 vpsExeFile
= new QFile(vpsExeInfo
.canonicalFilePath());
319 vpsDllFile
= new QFile(vpsDllInfo
.canonicalFilePath());
320 if(vpsExeFile
->open(QIODevice::ReadOnly
) && vpsDllFile
->open(QIODevice::ReadOnly
))
322 complete
= MUtils::OS::is_executable_file(vpsExeFile
->fileName());
328 MUTILS_DELETE(vpsExeFile
);
329 MUTILS_DELETE(vpsDllFile
);
335 bool VapourSynthCheckThread::checkVapourSynth(const QString
&vspipePath
)
337 //Try to run VSPIPE.EXE
338 const QStringList output
= runProcess(vspipePath
, QStringList() << "--version");
340 //Init regular expressions
341 QRegExp
vpsLogo("VapourSynth\\s+Video\\s+Processing\\s+Library");
343 //Check for version info
344 bool vapoursynthLogo
= false;
345 for(QStringList::ConstIterator iter
= output
.constBegin(); iter
!= output
.constEnd(); iter
++)
347 if(vpsLogo
.lastIndexIn(*iter
) >= 0)
349 vapoursynthLogo
= true;
354 //Minimum required version found?
357 qDebug("VapourSynth version was detected successfully.");
361 //Failed to determine version
362 qWarning("Failed to determine VapourSynth version!");