Happy new year 2020!
[simple-x264-launcher.git] / src / thread_avisynth.cpp
blob41c0a1aab9df36796d6eac9143a06972b7bd24f4
1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2020 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
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.
9 //
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_avisynth.h"
24 //Qt
25 #include <QEventLoop>
26 #include <QTimer>
27 #include <QApplication>
28 #include <QDir>
30 //Internal
31 #include "global.h"
32 #include "model_sysinfo.h"
34 //MUtils
35 #include <MUtils/Global.h>
36 #include <MUtils/OSSupport.h>
38 //Const
39 static const bool ENABLE_PORTABLE_AVS = true;
41 //Static
42 QMutex AvisynthCheckThread::m_avsLock;
43 QScopedPointer<QFile> AvisynthCheckThread::m_avsDllPath[2];
45 //-------------------------------------
46 // Auxilary functions
47 //-------------------------------------
49 #define VALID_DIR(STR) ((!(STR).isEmpty()) && QDir((STR)).exists())
50 #define BOOLIFY(X) ((X) ? '1' : '0')
52 QString AVS_CHECK_BINARY(const SysinfoModel *sysinfo, const bool& x64)
54 return QString("%1/toolset/%2/avs_check_%2.exe").arg(sysinfo->getAppPath(), (x64 ? "x64": "x86"));
57 class Wow64RedirectionDisabler
59 public:
60 Wow64RedirectionDisabler(void)
62 m_disabled = MUtils::OS::wow64fsredir_disable(m_oldValue);
64 ~Wow64RedirectionDisabler(void)
66 if(m_disabled)
68 if(!MUtils::OS::wow64fsredir_revert(m_oldValue))
70 qWarning("Failed to renable WOW64 filesystem redirection!");
74 private:
75 bool m_disabled;
76 uintptr_t m_oldValue;
79 //-------------------------------------
80 // External API
81 //-------------------------------------
83 bool AvisynthCheckThread::detect(SysinfoModel *sysinfo)
85 sysinfo->clearAvisynth();
86 double version = 0.0;
87 QMutexLocker lock(&m_avsLock);
89 QEventLoop loop;
90 AvisynthCheckThread thread(sysinfo);
92 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
94 connect(&thread, SIGNAL(finished()), &loop, SLOT(quit()));
95 connect(&thread, SIGNAL(terminated()), &loop, SLOT(quit()));
97 thread.start();
98 QTimer::singleShot(30000, &loop, SLOT(quit()));
100 qDebug("Avisynth thread has been created, please wait...");
101 loop.exec(QEventLoop::ExcludeUserInputEvents);
102 qDebug("Avisynth thread finished.");
104 QApplication::restoreOverrideCursor();
106 if(!thread.wait(1000))
108 qWarning("Avisynth thread encountered timeout -> probably deadlock!");
109 thread.terminate();
110 thread.wait();
111 return false;
114 if(thread.getException())
116 qWarning("Avisynth thread encountered an exception !!!");
117 return false;
120 if(thread.getSuccess())
122 sysinfo->setAvisynth(SysinfoModel::Avisynth_X86, thread.getSuccess() & AVISYNTH_X86);
123 sysinfo->setAvisynth(SysinfoModel::Avisynth_X64, thread.getSuccess() & AVISYNTH_X64);
124 sysinfo->setAVSPath(thread.getPath());
125 qDebug("Avisynth support is officially enabled now! [x86=%c, x64=%c]", BOOLIFY(sysinfo->getAvisynth(SysinfoModel::Avisynth_X86)), BOOLIFY(sysinfo->getAvisynth(SysinfoModel::Avisynth_X64)));
127 else
129 qWarning("Avisynth could not be found -> Avisynth support disabled!");
132 return true;
135 //-------------------------------------
136 // Thread class
137 //-------------------------------------
139 AvisynthCheckThread::AvisynthCheckThread(const SysinfoModel *const sysinfo)
141 m_sysinfo(sysinfo)
143 m_basePath.clear();
146 AvisynthCheckThread::~AvisynthCheckThread(void)
150 void AvisynthCheckThread::run(void)
152 m_basePath.clear();
153 StarupThread::run();
156 int AvisynthCheckThread::threadMain(void)
158 int flags = 0;
160 QFile *avsPath32;
161 if(checkAvisynth(m_basePath, m_sysinfo, avsPath32, false))
163 m_avsDllPath[0].reset(avsPath32);
164 flags |= AVISYNTH_X86;
165 qDebug("Avisynth 32-Bit edition found!");
167 else
169 qDebug("Avisynth 32-Bit edition *not* found!");
172 if(m_sysinfo->getCPUFeatures(SysinfoModel::CPUFeatures_X64))
174 QFile *avsPath64;
175 if(checkAvisynth(m_basePath, m_sysinfo, avsPath64, true))
177 m_avsDllPath[1].reset(avsPath64);
178 flags |= AVISYNTH_X64;
179 qDebug("Avisynth 64-Bit edition found!");
181 else
183 qDebug("Avisynth 64-Bit edition *not* found!");
186 else
188 qWarning("Skipping 64-Bit Avisynth check on non-x64 system!");
191 return flags;
194 //-------------------------------------
195 // Internal functions
196 //-------------------------------------
198 bool AvisynthCheckThread::checkAvisynth(QString &basePath, const SysinfoModel *const sysinfo, QFile *&path, const bool &x64)
200 qDebug("Avisynth %s-Bit support is being tested.", x64 ? "64" : "32");
202 //Look for "portable" Avisynth version
203 static const char *const ARCH_DIR[] = { "x64", "x86" };
204 const QLatin1String archSuffix = QLatin1String(ARCH_DIR[x64 ? 1 : 0]);
205 if (ENABLE_PORTABLE_AVS)
207 const QString avsPortableDir = QString("%1/extra/Avisynth").arg(QCoreApplication::applicationDirPath());
208 if (VALID_DIR(avsPortableDir))
210 QFileInfo avsDllFile(QString("%1/%2/avisynth.dll").arg(avsPortableDir, archSuffix)), devilDllFile(QString("%1/%2/devil.dll").arg(avsPortableDir, archSuffix));
211 if (avsDllFile.exists() && devilDllFile.exists() && avsDllFile.isFile() && devilDllFile.isFile())
213 qWarning("Adding portable Avisynth to PATH environment variable: %s", MUTILS_UTF8(avsPortableDir));
214 basePath = avsPortableDir;
219 //Get extra paths
220 QStringList avisynthExtraPaths;
221 if (!basePath.isEmpty())
223 avisynthExtraPaths << QString("%1/%2").arg(basePath, archSuffix);
226 //Setup process object
227 const QStringList output = runProcess(AVS_CHECK_BINARY(sysinfo, x64), QStringList(), &avisynthExtraPaths);
229 //Init regular expressions
230 QRegExp avsLogo("Avisynth\\s+Checker\\s+(x86|x64)");
231 QRegExp avsPath("Avisynth_DLLPath=(.+)");
232 QRegExp avsVers("Avisynth_Version=(\\d+)\\.(\\d+)");
234 //Check for version info
235 bool avisynthLogo = false;
236 quint32 avisynthVersion[2] = { 0, 0 };
237 QString avisynthPath;
238 for(QStringList::ConstIterator iter = output.constBegin(); iter != output.constEnd(); iter++)
240 if(avisynthLogo)
242 if(avsPath.indexIn(*iter) >= 0)
244 avisynthPath = avsPath.cap(1).trimmed();
246 else if(avsVers.indexIn(*iter) >= 0)
248 quint32 temp[2];
249 if(MUtils::regexp_parse_uint32(avsVers, temp, 2))
251 avisynthVersion[0] = temp[0];
252 avisynthVersion[1] = temp[1];
256 else
258 if(avsLogo.lastIndexIn(*iter) >= 0)
260 avisynthLogo = true;
265 //Minimum required version found?
266 if((avisynthVersion[0] >= 2) && (avisynthVersion[1] >= 50) && (!avisynthPath.isEmpty()))
268 Wow64RedirectionDisabler disableWow64Redir;
269 path = new QFile(avisynthPath);
270 if(!path->open(QIODevice::ReadOnly))
272 MUTILS_DELETE(path);
274 qDebug("Avisynth was detected successfully (current version: %u.%02u).", avisynthVersion[0], avisynthVersion[1]);
275 qDebug("Avisynth DLL path: %s", MUTILS_UTF8(avisynthPath));
276 return true;
279 //Failed to determine version
280 qWarning("Failed to determine Avisynth version!");
281 return false;