1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2021 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_avisynth.h"
27 #include <QApplication>
32 #include "model_sysinfo.h"
35 #include <MUtils/Global.h>
36 #include <MUtils/OSSupport.h>
39 static const bool ENABLE_PORTABLE_AVS = true;
42 QMutex AvisynthCheckThread::m_avsLock;
43 QScopedPointer<QFile> AvisynthCheckThread::m_avsDllPath[2];
45 //-------------------------------------
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
60 Wow64RedirectionDisabler(void)
62 m_disabled = MUtils::OS::wow64fsredir_disable(m_oldValue);
64 ~Wow64RedirectionDisabler(void)
68 if(!MUtils::OS::wow64fsredir_revert(m_oldValue))
70 qWarning("Failed to renable WOW64 filesystem redirection!");
79 //-------------------------------------
81 //-------------------------------------
83 bool AvisynthCheckThread::detect(SysinfoModel *sysinfo)
85 sysinfo->clearAvisynth();
87 QMutexLocker lock(&m_avsLock);
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()));
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!");
114 if(thread.getException())
116 qWarning("Avisynth thread encountered an exception !!!");
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)));
129 qWarning("Avisynth could not be found -> Avisynth support disabled!");
135 //-------------------------------------
137 //-------------------------------------
139 AvisynthCheckThread::AvisynthCheckThread(const SysinfoModel *const sysinfo)
146 AvisynthCheckThread::~AvisynthCheckThread(void)
150 void AvisynthCheckThread::run(void)
156 int AvisynthCheckThread::threadMain(void)
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!");
169 qDebug("Avisynth 32-Bit edition *not* found!");
172 if(m_sysinfo->getCPUFeatures(SysinfoModel::CPUFeatures_X64))
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!");
183 qDebug("Avisynth 64-Bit edition *not* found!");
188 qWarning("Skipping 64-Bit Avisynth check on non-x64 system!");
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;
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++)
242 if(avsPath.indexIn(*iter) >= 0)
244 avisynthPath = avsPath.cap(1).trimmed();
246 else if(avsVers.indexIn(*iter) >= 0)
249 if(MUtils::regexp_parse_uint32(avsVers, temp, 2))
251 avisynthVersion[0] = temp[0];
252 avisynthVersion[1] = temp[1];
258 if(avsLogo.lastIndexIn(*iter) >= 0)
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))
274 qDebug("Avisynth was detected successfully (current version: %u.%02u).", avisynthVersion[0], avisynthVersion[1]);
275 qDebug("Avisynth DLL path: %s", MUTILS_UTF8(avisynthPath));
279 //Failed to determine version
280 qWarning("Failed to determine Avisynth version!");