Fixed CQ and CRF mode being mixed up.
[simple-x264-launcher.git] / src / thread_avisynth.cpp
blobb421e445294e3195a096f28081eafda61272b48b
1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2016 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 #include <QLibrary>
25 #include <QEventLoop>
26 #include <QTimer>
27 #include <QMutexLocker>
28 #include <QApplication>
29 #include <QProcess>
30 #include <QDir>
32 //Internal
33 #include "global.h"
34 #include "model_sysinfo.h"
36 //MUtils
37 #include <MUtils/Global.h>
38 #include <MUtils/OSSupport.h>
40 //Static
41 QMutex AvisynthCheckThread::m_avsLock;
42 QScopedPointer<QFile> AvisynthCheckThread::m_avsDllPath[2];
44 //Helper
45 #define BOOLIFY(X) ((X) ? '1' : '0')
47 //Utility function
48 QString AVS_CHECK_BINARY(const SysinfoModel *sysinfo, const bool& x64)
50 return QString("%1/toolset/%2/avs_check_%2.exe").arg(sysinfo->getAppPath(), (x64 ? "x64": "x86"));
53 class Wow64RedirectionDisabler
55 public:
56 Wow64RedirectionDisabler(void)
58 m_oldValue = NULL;
59 m_disabled = MUtils::OS::wow64fsredir_disable(m_oldValue);
61 ~Wow64RedirectionDisabler(void)
63 if(m_disabled)
65 if(!MUtils::OS::wow64fsredir_revert(m_oldValue))
67 qWarning("Failed to renable WOW64 filesystem redirection!");
71 private:
72 bool m_disabled;
73 void* m_oldValue;
76 //-------------------------------------
77 // External API
78 //-------------------------------------
80 bool AvisynthCheckThread::detect(SysinfoModel *sysinfo)
82 sysinfo->clearAvisynth();
83 double version = 0.0;
84 QMutexLocker lock(&m_avsLock);
86 QEventLoop loop;
87 AvisynthCheckThread thread(sysinfo);
89 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
91 connect(&thread, SIGNAL(finished()), &loop, SLOT(quit()));
92 connect(&thread, SIGNAL(terminated()), &loop, SLOT(quit()));
94 thread.start();
95 QTimer::singleShot(15000, &loop, SLOT(quit()));
97 qDebug("Avisynth thread has been created, please wait...");
98 loop.exec(QEventLoop::ExcludeUserInputEvents);
99 qDebug("Avisynth thread finished.");
101 QApplication::restoreOverrideCursor();
103 if(!thread.wait(1000))
105 qWarning("Avisynth thread encountered timeout -> probably deadlock!");
106 thread.terminate();
107 thread.wait();
108 return false;
111 if(thread.getException())
113 qWarning("Avisynth thread encountered an exception !!!");
114 return false;
117 if(thread.getSuccess())
119 sysinfo->setAvisynth(SysinfoModel::Avisynth_X86, thread.getSuccess() & AVISYNTH_X86);
120 sysinfo->setAvisynth(SysinfoModel::Avisynth_X64, thread.getSuccess() & AVISYNTH_X64);
121 qDebug("Avisynth support is officially enabled now! [x86=%c, x64=%c]", BOOLIFY(sysinfo->getAvisynth(SysinfoModel::Avisynth_X86)), BOOLIFY(sysinfo->getAvisynth(SysinfoModel::Avisynth_X64)));
123 else
125 qWarning("Avisynth could not be found -> Avisynth support disabled!");
128 return true;
131 //-------------------------------------
132 // Thread class
133 //-------------------------------------
135 AvisynthCheckThread::AvisynthCheckThread(const SysinfoModel *const sysinfo)
137 m_sysinfo(sysinfo)
139 m_success = false;
140 m_exception = false;
143 AvisynthCheckThread::~AvisynthCheckThread(void)
147 void AvisynthCheckThread::run(void)
149 m_exception = false;
150 m_success &= 0;
152 detectAvisynthVersion1(m_success, m_sysinfo, &m_exception);
155 void AvisynthCheckThread::detectAvisynthVersion1(int &success, const SysinfoModel *const sysinfo, volatile bool *exception)
157 __try
159 detectAvisynthVersion2(success, sysinfo, exception);
161 __except(1)
163 *exception = true;
164 qWarning("Unhandled exception error in Avisynth thread !!!");
168 void AvisynthCheckThread::detectAvisynthVersion2(int &success, const SysinfoModel *const sysinfo, volatile bool *exception)
172 return detectAvisynthVersion3(success, sysinfo);
174 catch(...)
176 *exception = true;
177 qWarning("Avisynth initializdation raised an C++ exception!");
181 void AvisynthCheckThread::detectAvisynthVersion3(int &success, const SysinfoModel *const sysinfo)
183 success &= 0;
185 QFile *avsPath32;
186 if(checkAvisynth(sysinfo, avsPath32, false))
188 m_avsDllPath[0].reset(avsPath32);
189 success |= AVISYNTH_X86;
190 qDebug("Avisynth 32-Bit edition found!");
192 else
194 qDebug("Avisynth 32-Bit edition *not* found!");
197 if(sysinfo->getCPUFeatures(SysinfoModel::CPUFeatures_X64))
199 QFile *avsPath64;
200 if(checkAvisynth(sysinfo, avsPath64, true))
202 m_avsDllPath[1].reset(avsPath64);
203 success |= AVISYNTH_X64;
204 qDebug("Avisynth 64-Bit edition found!");
206 else
208 qDebug("Avisynth 64-Bit edition *not* found!");
211 else
213 qWarning("Skipping 64-Bit Avisynth check on non-x64 system!");
217 bool AvisynthCheckThread::checkAvisynth(const SysinfoModel *const sysinfo, QFile *&path, const bool &x64)
219 qDebug("Avisynth %s-Bit support is being tested.", x64 ? "64" : "32");
221 QProcess process;
222 QStringList output;
224 //Setup process object
225 process.setWorkingDirectory(QDir::tempPath());
226 process.setProcessChannelMode(QProcess::MergedChannels);
227 process.setReadChannel(QProcess::StandardOutput);
229 //Try to start VSPIPE.EXE
230 process.start(AVS_CHECK_BINARY(sysinfo, x64), QStringList());
231 if(!process.waitForStarted())
233 qWarning("Failed to launch AVS_CHECK.EXE -> %s", process.errorString().toUtf8().constData());
234 return false;
237 //Wait for process to finish
238 while(process.state() != QProcess::NotRunning)
240 if(process.waitForReadyRead(12000))
242 while(process.canReadLine())
244 output << QString::fromUtf8(process.readLine()).simplified();
246 continue;
248 if(process.state() != QProcess::NotRunning)
250 qWarning("AVS_CHECK.EXE process encountered a deadlock -> aborting now!");
251 break;
255 //Make sure VSPIPE.EXE has terminated!
256 process.waitForFinished(2500);
257 if(process.state() != QProcess::NotRunning)
259 qWarning("AVS_CHECK.EXE process still running, going to kill it!");
260 process.kill();
261 process.waitForFinished(-1);
264 //Read pending lines
265 while(process.canReadLine())
267 output << QString::fromUtf8(process.readLine()).simplified();
270 //Check exit code
271 if(process.exitCode() != 0)
273 qWarning("AVS_CHECK.EXE failed with code 0x%08X -> disable Avisynth support!", process.exitCode());
274 return false;
277 //Init regular expressions
278 QRegExp avsLogo("Avisynth\\s+Checker\\s+(x86|x64)");
279 QRegExp avsPath("Avisynth_DLLPath=(.+)");
280 QRegExp avsVers("Avisynth_Version=(\\d+)\\.(\\d+)");
282 //Check for version info
283 bool avisynthLogo = false;
284 quint32 avisynthVersion[2] = { 0, 0 };
285 QString avisynthPath;
286 for(QStringList::ConstIterator iter = output.constBegin(); iter != output.constEnd(); iter++)
288 if(avisynthLogo)
290 if(avsPath.indexIn(*iter) >= 0)
292 avisynthPath = avsPath.cap(1).trimmed();
294 else if(avsVers.indexIn(*iter) >= 0)
296 quint32 temp[2];
297 if(MUtils::regexp_parse_uint32(avsVers, temp, 2))
299 avisynthVersion[0] = temp[0];
300 avisynthVersion[1] = temp[1];
304 else
306 if(avsLogo.lastIndexIn(*iter) >= 0)
308 avisynthLogo = true;
313 //Minimum required version found?
314 if((avisynthVersion[0] >= 2) && (avisynthVersion[1] >= 50) && (!avisynthPath.isEmpty()))
316 Wow64RedirectionDisabler disableWow64Redir;
317 path = new QFile(avisynthPath);
318 if(!path->open(QIODevice::ReadOnly))
320 MUTILS_DELETE(path);
323 qDebug("Avisynth was detected successfully (current version: %u.%02u).", avisynthVersion[0], avisynthVersion[1]);
324 qDebug("Avisynth DLL path: %s", MUTILS_UTF8(avisynthPath));
325 return true;
328 //Failed to determine version
329 qWarning("Failed to determine Avisynth version!");
330 return false;