1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2016 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 <QMutexLocker>
28 #include <QApplication>
34 #include "model_sysinfo.h"
37 #include <MUtils/Global.h>
38 #include <MUtils/OSSupport.h>
41 QMutex
AvisynthCheckThread::m_avsLock
;
42 QScopedPointer
<QFile
> AvisynthCheckThread::m_avsDllPath
[2];
45 #define BOOLIFY(X) ((X) ? '1' : '0')
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
56 Wow64RedirectionDisabler(void)
59 m_disabled
= MUtils::OS::wow64fsredir_disable(m_oldValue
);
61 ~Wow64RedirectionDisabler(void)
65 if(!MUtils::OS::wow64fsredir_revert(m_oldValue
))
67 qWarning("Failed to renable WOW64 filesystem redirection!");
76 //-------------------------------------
78 //-------------------------------------
80 bool AvisynthCheckThread::detect(SysinfoModel
*sysinfo
)
82 sysinfo
->clearAvisynth();
84 QMutexLocker
lock(&m_avsLock
);
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()));
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!");
111 if(thread
.getException())
113 qWarning("Avisynth thread encountered an exception !!!");
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
)));
125 qWarning("Avisynth could not be found -> Avisynth support disabled!");
131 //-------------------------------------
133 //-------------------------------------
135 AvisynthCheckThread::AvisynthCheckThread(const SysinfoModel
*const sysinfo
)
143 AvisynthCheckThread::~AvisynthCheckThread(void)
147 void AvisynthCheckThread::run(void)
152 detectAvisynthVersion1(m_success
, m_sysinfo
, &m_exception
);
155 void AvisynthCheckThread::detectAvisynthVersion1(int &success
, const SysinfoModel
*const sysinfo
, volatile bool *exception
)
159 detectAvisynthVersion2(success
, sysinfo
, exception
);
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
);
177 qWarning("Avisynth initializdation raised an C++ exception!");
181 void AvisynthCheckThread::detectAvisynthVersion3(int &success
, const SysinfoModel
*const sysinfo
)
186 if(checkAvisynth(sysinfo
, avsPath32
, false))
188 m_avsDllPath
[0].reset(avsPath32
);
189 success
|= AVISYNTH_X86
;
190 qDebug("Avisynth 32-Bit edition found!");
194 qDebug("Avisynth 32-Bit edition *not* found!");
197 if(sysinfo
->getCPUFeatures(SysinfoModel::CPUFeatures_X64
))
200 if(checkAvisynth(sysinfo
, avsPath64
, true))
202 m_avsDllPath
[1].reset(avsPath64
);
203 success
|= AVISYNTH_X64
;
204 qDebug("Avisynth 64-Bit edition found!");
208 qDebug("Avisynth 64-Bit edition *not* found!");
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");
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());
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();
248 if(process
.state() != QProcess::NotRunning
)
250 qWarning("AVS_CHECK.EXE process encountered a deadlock -> aborting now!");
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!");
261 process
.waitForFinished(-1);
265 while(process
.canReadLine())
267 output
<< QString::fromUtf8(process
.readLine()).simplified();
271 if(process
.exitCode() != 0)
273 qWarning("AVS_CHECK.EXE failed with code 0x%08X -> disable Avisynth support!", process
.exitCode());
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
++)
290 if(avsPath
.indexIn(*iter
) >= 0)
292 avisynthPath
= avsPath
.cap(1).trimmed();
294 else if(avsVers
.indexIn(*iter
) >= 0)
297 if(MUtils::regexp_parse_uint32(avsVers
, temp
, 2))
299 avisynthVersion
[0] = temp
[0];
300 avisynthVersion
[1] = temp
[1];
306 if(avsLogo
.lastIndexIn(*iter
) >= 0)
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
))
323 qDebug("Avisynth was detected successfully (current version: %u.%02u).", avisynthVersion
[0], avisynthVersion
[1]);
324 qDebug("Avisynth DLL path: %s", MUTILS_UTF8(avisynthPath
));
328 //Failed to determine version
329 qWarning("Failed to determine Avisynth version!");