1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2024 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>
34 #include <QAbstractFileEngine.h>
38 #include "model_sysinfo.h"
44 QMutex
VapourSynthCheckThread::m_vpsLock
;
45 QScopedPointer
<QFile
> VapourSynthCheckThread::m_vpsExePath
[2];
46 QScopedPointer
<QFile
> VapourSynthCheckThread::m_vpsDllPath
[2];
49 static const char* const VPS_DLL_NAME
= "vapoursynth.dll";
50 static const char* const VPS_EXE_NAME
= "vspipe.exe";
51 static const char* const VPS_REG_KEY1
= "SOFTWARE\\VapourSynth";
52 static const char* const VPS_REG_KEY2
= "SOFTWARE\\VapourSynth-32";
53 static const char* const VPS_REG_NAME
= "VapourSynthDLL";
55 //Default VapurSynth architecture
56 #if _WIN64 || __x86_64__
57 #define VAPOURSYNTH_DEF VAPOURSYNTH_X64
59 #define VAPOURSYNTH_DEF VAPOURSYNTH_X86;
62 //Enable detection of "portabel" edition?
63 #define ENABLE_PORTABLE_VPS true
66 #define REG_ROOT_EOL (MUtils::Registry::reg_root_t (-1))
67 #define REG_SCOPE_EOL (MUtils::Registry::reg_scope_t(-1))
70 #define BOOLIFY(X) ((X) ? '1' : '0')
71 #define VPS_BITNESS(X) (((X) + 1U) * 32U)
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_root_t REG_ROOTS
[] =
170 MUtils::Registry::root_machine
,
171 MUtils::Registry::root_user
,
174 static const char* const REG_PATHS_HKLM
[] =
179 static const char* const REG_PATHS_HKCU
[] =
185 static const MUtils::Registry::reg_scope_t REG_SCOPE_X86
[] =
187 MUtils::Registry::scope_default
,
190 static const MUtils::Registry::reg_scope_t REG_SCOPE_X64
[] =
192 MUtils::Registry::scope_wow_x32
,
193 MUtils::Registry::scope_wow_x64
,
197 QHash
<int, QFileInfo
> vpsDllInfo
, vpsExeInfo
;
200 //Look for "portable" VapourSynth version
201 for (size_t i
= 0; i
< 2U; i
++)
203 const QDir
vpsPortableDir(QString("%1/extra/VapourSynth-%2").arg(QCoreApplication::applicationDirPath(), QString::number(VPS_BITNESS(i
))));
204 if (vpsPortableDir
.exists())
206 const QFileInfo
vpsPortableDll(vpsPortableDir
.absoluteFilePath(VPS_DLL_NAME
));
207 const QFileInfo
vpsPortableExe(vpsPortableDir
.absoluteFilePath(VPS_EXE_NAME
));
208 if ((vpsPortableDll
.exists() && vpsPortableDll
.isFile()) || (vpsPortableExe
.exists() && vpsPortableExe
.isFile()))
210 vpsDllInfo
.insert(VPS_BIT_FLAG
[i
], vpsPortableDll
);
211 vpsExeInfo
.insert(VPS_BIT_FLAG
[i
], vpsPortableExe
);
216 //Read VapourSynth path from registry
217 if (vpsDllInfo
.isEmpty() && vpsExeInfo
.isEmpty())
219 for (size_t i
= 0; REG_ROOTS
[i
] != REG_ROOT_EOL
; i
++)
221 const char *const *const paths
= (REG_ROOTS
[i
] == MUtils::Registry::root_machine
) ? REG_PATHS_HKLM
: REG_PATHS_HKCU
;
222 const MUtils::Registry::reg_scope_t
* const scopes
= (REG_ROOTS
[i
] == MUtils::Registry::root_machine
) ? ((MUtils::OS::os_architecture() == MUtils::OS::ARCH_X64
) ? REG_SCOPE_X64
: REG_SCOPE_X86
) : REG_SCOPE_X86
;
223 for (size_t j
= 0; paths
[j
]; j
++)
225 for (size_t k
= 0; scopes
[k
] != REG_SCOPE_EOL
; k
++)
227 if (MUtils::Registry::reg_key_exists(REG_ROOTS
[i
], QString::fromLatin1(paths
[j
]), scopes
[k
]))
229 QString vpsRegDllPath
;
230 if (MUtils::Registry::reg_value_read(REG_ROOTS
[i
], QString::fromLatin1(paths
[j
]), QString::fromLatin1(VPS_REG_NAME
), vpsRegDllPath
, scopes
[k
]))
232 QFileInfo
vpsRegDllInfo(QDir::fromNativeSeparators(vpsRegDllPath
));
233 vpsRegDllInfo
.makeAbsolute();
234 if (vpsRegDllInfo
.exists() && vpsRegDllInfo
.isFile())
236 const int vpsArch
= (REG_ROOTS
[i
] == MUtils::Registry::root_machine
) ? getVapourSynthType(scopes
[k
]) : ((j
> 0U) ? VAPOURSYNTH_X86
: VAPOURSYNTH_X64
);
237 if ((!vpsDllInfo
.contains(vpsArch
)) || (!vpsExeInfo
.contains(vpsArch
)))
239 vpsDllInfo
.insert(vpsArch
, vpsRegDllInfo
);
240 vpsExeInfo
.insert(vpsArch
, vpsRegDllInfo
.absoluteDir().absoluteFilePath(VPS_EXE_NAME
)); /*derive VSPipe.EXE path from VapourSynth.DLL path!*/
250 //Abort, if VapourSynth was *not* found
251 if (vpsDllInfo
.isEmpty() || vpsExeInfo
.isEmpty())
253 qWarning("VapourSynth install path not found -> disable VapouSynth support!");
257 //Validate the VapourSynth installation now!
258 for (size_t i
= 0; i
< 2U; i
++)
260 qDebug("VapourSynth %u-Bit support is being tested.", VPS_BITNESS(i
));
261 if (vpsDllInfo
.contains(VPS_BIT_FLAG
[i
]) && vpsExeInfo
.contains(VPS_BIT_FLAG
[i
]))
263 QFile
*vpsExeFile
, *vpsDllFile
;
264 if (isVapourSynthComplete(vpsDllInfo
[VPS_BIT_FLAG
[i
]], vpsExeInfo
[VPS_BIT_FLAG
[i
]], vpsExeFile
, vpsDllFile
))
266 m_vpsExePath
[i
].reset(vpsExeFile
);
267 m_vpsDllPath
[i
].reset(vpsDllFile
);
268 if (checkVapourSynth(m_vpsExePath
[i
]->fileEngine()->fileName(QAbstractFileEngine::CanonicalName
)))
270 qDebug("VapourSynth %u-Bit edition found!", VPS_BITNESS(i
));
271 m_vpsPath
[i
] = m_vpsExePath
[i
]->fileEngine()->fileName(QAbstractFileEngine::CanonicalPathName
);
272 flags
|= VPS_BIT_FLAG
[i
];
276 qWarning("VapourSynth %u-Bit edition was found, but version check has failed!", VPS_BITNESS(i
));
281 qWarning("VapourSynth %u-Bit edition was found, but appears to be incomplete!", VPS_BITNESS(i
));
286 qDebug("VapourSynth %u-Bit edition *not* found!", VPS_BITNESS(i
));
293 //-------------------------------------
294 // Internal functions
295 //-------------------------------------
297 VapourSynthCheckThread::VapourSynthFlags
VapourSynthCheckThread::getVapourSynthType(const int scope
)
299 if (MUtils::OS::os_architecture() == MUtils::OS::ARCH_X64
)
303 case MUtils::Registry::scope_wow_x32
:
304 return VAPOURSYNTH_X86
;
305 case MUtils::Registry::scope_wow_x64
:
306 return VAPOURSYNTH_X64
;
308 return VAPOURSYNTH_DEF
;
313 return VAPOURSYNTH_X86
; /*ignore scope on 32-Bit OS*/
317 bool VapourSynthCheckThread::isVapourSynthComplete(const QFileInfo
& vpsDllInfo
, const QFileInfo
& vpsExeInfo
, QFile
*& vpsExeFile
, QFile
*& vpsDllFile
)
319 bool complete
= false;
320 vpsExeFile
= vpsDllFile
= NULL
;
322 qDebug("VapourSynth EXE: %s", vpsExeInfo
.absoluteFilePath().toUtf8().constData());
323 qDebug("VapourSynth DLL: %s", vpsDllInfo
.absoluteFilePath().toUtf8().constData());
325 if (vpsDllInfo
.exists() && vpsDllInfo
.isFile() && vpsExeInfo
.exists() && vpsExeInfo
.isFile())
327 vpsExeFile
= new QFile(vpsExeInfo
.canonicalFilePath());
328 vpsDllFile
= new QFile(vpsDllInfo
.canonicalFilePath());
329 if(vpsExeFile
->open(QIODevice::ReadOnly
) && vpsDllFile
->open(QIODevice::ReadOnly
))
331 complete
= MUtils::OS::is_executable_file(vpsExeFile
->fileEngine()->fileName(QAbstractFileEngine::CanonicalName
));
337 MUTILS_DELETE(vpsExeFile
);
338 MUTILS_DELETE(vpsDllFile
);
344 bool VapourSynthCheckThread::checkVapourSynth(const QString
&vspipePath
)
346 //Try to run VSPIPE.EXE
347 const QStringList output
= runProcess(vspipePath
, QStringList() << "--version");
349 //Init regular expressions
350 QRegExp
vpsLogo("VapourSynth\\s+Video\\s+Processing\\s+Library");
352 //Check for version info
353 bool vapoursynthLogo
= false;
354 for(QStringList::ConstIterator iter
= output
.constBegin(); iter
!= output
.constEnd(); iter
++)
356 if(vpsLogo
.lastIndexIn(*iter
) >= 0)
358 vapoursynthLogo
= true;
363 //Minimum required version found?
366 qDebug("VapourSynth version was detected successfully.");
370 //Failed to determine version
371 qWarning("Failed to determine VapourSynth version!");