Moved the Avisynth detected code into a background thread.

This commit is contained in:
LoRd_MuldeR 2013-04-02 23:10:58 +02:00
parent 2d80a1d7a5
commit dd7a18abbb
7 changed files with 312 additions and 114 deletions

217
src/thread_avisynth.cpp Normal file
View File

@ -0,0 +1,217 @@
///////////////////////////////////////////////////////////////////////////////
// Simple x264 Launcher
// Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// http://www.gnu.org/licenses/gpl-2.0.txt
///////////////////////////////////////////////////////////////////////////////
#include "thread_avisynth.h"
#include <QLibrary>
#include <QEventLoop>
#include <QTimer>
#include <QMutexLocker>
#include <QApplication>
#include "global.h"
#include "avisynth_c.h"
QMutex AvisynthCheckThread::m_avsLock;
QLibrary *AvisynthCheckThread::m_avsLib = NULL;
AvisynthCheckThread::AvisynthCheckThread(void)
{
m_success = false;
m_exception = false;
m_version = 0.0;
}
AvisynthCheckThread::~AvisynthCheckThread(void)
{
}
int AvisynthCheckThread::detect(volatile double *version)
{
*version = 0.0;
QMutexLocker lock(&m_avsLock);
QEventLoop loop;
AvisynthCheckThread thread;
QTimer timer;
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
connect(&thread, SIGNAL(finished()), &loop, SLOT(quit()));
connect(&thread, SIGNAL(terminated()), &loop, SLOT(quit()));
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
thread.start();
timer.start(8000);
qDebug("Avisynth thread has been created, please wait...");
loop.exec(QEventLoop::ExcludeUserInputEvents);
qDebug("Avisynth thread finished.");
QApplication::restoreOverrideCursor();
if(!thread.wait(1000))
{
qWarning("Avisynth thread encountered timeout -> probably deadlock!");
thread.terminate();
thread.wait();
return -1;
}
if(thread.getException())
{
qWarning("Avisynth thread encountered an exception !!!");
return -1;
}
if(thread.getSuccess())
{
*version = thread.getVersion();
qDebug("Version check completed: %.2f", *version);
return 1;
}
qWarning("Avisynth thread failed to determine the version!");
return 0;
}
void AvisynthCheckThread::unload(void)
{
QMutexLocker lock(&m_avsLock);
if(m_avsLib)
{
if(m_avsLib->isLoaded())
{
m_avsLib->unload();
}
X264_DELETE(m_avsLib);
}
}
void AvisynthCheckThread::run(void)
{
m_success = detectAvisynthVersion1(&m_version, &m_exception);
}
bool AvisynthCheckThread::detectAvisynthVersion1(volatile double *version_number, volatile bool *exception)
{
__try
{
return detectAvisynthVersion2(version_number, exception);
}
__except(1)
{
*exception = true;
qWarning("Unhandled exception error in Avisynth thread !!!");
return false;
}
}
bool AvisynthCheckThread::detectAvisynthVersion2(volatile double *version_number, volatile bool *exception)
{
try
{
return detectAvisynthVersion3(version_number);
}
catch(...)
{
*exception = true;
qWarning("Avisynth initializdation raised an C++ exception!");
return false;
}
}
bool AvisynthCheckThread::detectAvisynthVersion3(volatile double *version_number)
{
bool success = false;
*version_number = 0.0;
if(!m_avsLib)
{
m_avsLib = new QLibrary("avisynth.dll");
}
if(m_avsLib->isLoaded() || m_avsLib->load())
{
avs_create_script_environment_func avs_create_script_environment_ptr = (avs_create_script_environment_func) m_avsLib->resolve("avs_create_script_environment");
avs_invoke_func avs_invoke_ptr = (avs_invoke_func) m_avsLib->resolve("avs_invoke");
avs_function_exists_func avs_function_exists_ptr = (avs_function_exists_func) m_avsLib->resolve("avs_function_exists");
avs_delete_script_environment_func avs_delete_script_environment_ptr = (avs_delete_script_environment_func) m_avsLib->resolve("avs_delete_script_environment");
avs_release_value_func avs_release_value_ptr = (avs_release_value_func) m_avsLib->resolve("avs_release_value");
if((avs_create_script_environment_ptr != NULL) && (avs_invoke_ptr != NULL) && (avs_function_exists_ptr != NULL))
{
qDebug("avs_create_script_environment_ptr(AVS_INTERFACE_25)");
AVS_ScriptEnvironment* avs_env = avs_create_script_environment_ptr(AVS_INTERFACE_25);
if(avs_env != NULL)
{
qDebug("avs_function_exists_ptr(avs_env, \"VersionNumber\")");
if(avs_function_exists_ptr(avs_env, "VersionNumber"))
{
qDebug("avs_invoke_ptr(avs_env, \"VersionNumber\", avs_new_value_array(NULL, 0), NULL)");
AVS_Value avs_version = avs_invoke_ptr(avs_env, "VersionNumber", avs_new_value_array(NULL, 0), NULL);
if(!avs_is_error(avs_version))
{
if(avs_is_float(avs_version))
{
qDebug("Avisynth version: v%.2f", avs_as_float(avs_version));
*version_number = avs_as_float(avs_version);
if(avs_release_value_ptr) avs_release_value_ptr(avs_version);
success = true;
}
else
{
qWarning("Failed to determine version number, Avisynth didn't return a float!");
}
}
else
{
qWarning("Failed to determine version number, Avisynth returned an error!");
}
}
else
{
qWarning("The 'VersionNumber' function does not exist in your Avisynth DLL, can't determine version!");
}
if(avs_delete_script_environment_ptr != NULL)
{
avs_delete_script_environment_ptr(avs_env);
avs_env = NULL;
}
}
else
{
qWarning("The Avisynth DLL failed to create the script environment!");
}
}
else
{
qWarning("It seems the Avisynth DLL is missing required API functions!");
}
}
else
{
qWarning("Failed to load Avisynth.dll library!");
}
return success;
}

62
src/thread_avisynth.h Normal file
View File

@ -0,0 +1,62 @@
///////////////////////////////////////////////////////////////////////////////
// Simple x264 Launcher
// Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// http://www.gnu.org/licenses/gpl-2.0.txt
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include <QThread>
#include <QMutex>
class QLibrary;
class AvisynthCheckThread : public QThread
{
Q_OBJECT
public:
AvisynthCheckThread(void);
~AvisynthCheckThread(void);
static int detect(volatile double *version);
static void unload(void);
bool getSuccess(void) { return m_success; }
bool getException(void) { return m_exception; }
double getVersion(void) { return m_version; }
private slots:
void start(Priority priority = InheritPriority) { QThread::start(priority); }
private:
volatile bool m_exception;
volatile bool m_success;
volatile double m_version;
static QMutex m_avsLock;
static QLibrary *m_avsLib;
//Entry point
virtual void run(void);
//Functions
static bool detectAvisynthVersion1(volatile double *version_number, volatile bool *exception);
static bool detectAvisynthVersion2(volatile double *version_number, volatile bool *exception);
static bool detectAvisynthVersion3(volatile double *version_number);
};

View File

@ -20,9 +20,9 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define VER_X264_MAJOR 2 #define VER_X264_MAJOR 2
#define VER_X264_MINOR 0 #define VER_X264_MINOR 1
#define VER_X264_PATCH 9 #define VER_X264_PATCH 0
#define VER_X264_BUILD 408 #define VER_X264_BUILD 419
#define VER_X264_MINIMUM_REV 2250 #define VER_X264_MINIMUM_REV 2250
#define VER_X264_CURRENT_API 130 #define VER_X264_CURRENT_API 130

View File

@ -25,9 +25,9 @@
#include "model_options.h" #include "model_options.h"
#include "win_addJob.h" #include "win_addJob.h"
#include "win_preferences.h" #include "win_preferences.h"
#include "thread_avisynth.h"
#include "taskbar7.h" #include "taskbar7.h"
#include "resource.h" #include "resource.h"
#include "avisynth_c.h"
#include <QDate> #include <QDate>
#include <QTimer> #include <QTimer>
@ -66,7 +66,6 @@ MainWindow::MainWindow(const x264_cpu_t *const cpuFeatures)
m_appDir(QApplication::applicationDirPath()), m_appDir(QApplication::applicationDirPath()),
m_options(NULL), m_options(NULL),
m_jobList(NULL), m_jobList(NULL),
m_avsLib(NULL),
m_droppedFiles(NULL), m_droppedFiles(NULL),
m_firstShow(true) m_firstShow(true)
{ {
@ -198,12 +197,7 @@ MainWindow::~MainWindow(void)
} }
X264_DELETE(m_ipcThread); X264_DELETE(m_ipcThread);
AvisynthCheckThread::unload();
if(m_avsLib)
{
m_avsLib->unload();
X264_DELETE(m_avsLib);
}
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -770,32 +764,19 @@ void MainWindow::init(void)
if(!qApp->arguments().contains("--skip-avisynth-check", Qt::CaseInsensitive)) if(!qApp->arguments().contains("--skip-avisynth-check", Qt::CaseInsensitive))
{ {
qDebug("[Check for Avisynth support]"); qDebug("[Check for Avisynth support]");
double avisynthVersion = 0.0; volatile double avisynthVersion = 0.0;
if(!m_avsLib) const int result = AvisynthCheckThread::detect(&avisynthVersion);
if(result < 0)
{ {
m_avsLib = new QLibrary("avisynth.dll"); QString text = tr("A critical error was encountered while checking your Avisynth version.").append("<br>");
text += tr("This is most likely caused by an erroneous Avisynth Plugin, please try to clean your Plugins folder!").append("<br>");
text += tr("We suggest to move all .dll and .avsi files out of your Avisynth Plugins folder and try again.");
int val = QMessageBox::critical(this, tr("Avisynth Error"), QString("<nobr>%1</nobr>").arg(text).replace("-", "&minus;"), tr("Quit"), tr("Ignore"));
if(val != 1) { close(); qApp->exit(-1); return; }
} }
if(m_avsLib->load()) if((!result) || (avisynthVersion < 2.5))
{
DWORD errorCode = 0;
avisynthVersion = detectAvisynthVersion(m_avsLib, &errorCode);
if((avisynthVersion < 0.0) || errorCode)
{
QString text = tr("A critical error (code: 0x%1) was encountered while checking your Avisynth version.").arg(QString().sprintf("%08X", errorCode)).append("<br>");
text += tr("This is most likely caused by an erroneous Avisynth Plugin, please try to clean your Plugins foler!").append("<br>");
text += tr("We suggest to move all .dll and .avsi files out of your Avisynth Plugins folder and try again.");
int val = QMessageBox::critical(this, tr("Avisynth Error"), QString("<nobr>%1</nobr>").arg(text).replace("-", "&minus;"), tr("Quit"), tr("Ignore"));
if(val != 1) { close(); qApp->exit(-1); return; }
}
}
else
{
qWarning("Failed to load avisynth.dll libraray!");
}
if(avisynthVersion < 2.5)
{ {
int val = QMessageBox::warning(this, tr("Avisynth Missing"), tr("<nobr>It appears that Avisynth is <b>not</b> currently installed on your computer.<br>Therefore Avisynth (.avs) input will <b>not</b> be working at all!<br><br>Please download and install Avisynth:<br><a href=\"http://sourceforge.net/projects/avisynth2/files/AviSynth%202.5/\">http://sourceforge.net/projects/avisynth2/files/AviSynth 2.5/</a></nobr>").replace("-", "&minus;"), tr("Quit"), tr("Ignore")); int val = QMessageBox::warning(this, tr("Avisynth Missing"), tr("<nobr>It appears that Avisynth is <b>not</b> currently installed on your computer.<br>Therefore Avisynth (.avs) input will <b>not</b> be working at all!<br><br>Please download and install Avisynth:<br><a href=\"http://sourceforge.net/projects/avisynth2/files/AviSynth%202.5/\">http://sourceforge.net/projects/avisynth2/files/AviSynth 2.5/</a></nobr>").replace("-", "&minus;"), tr("Quit"), tr("Ignore"));
m_avsLib->unload(); X264_DELETE(m_avsLib);
if(val != 1) { close(); qApp->exit(-1); return; } if(val != 1) { close(); qApp->exit(-1); return; }
} }
qDebug(""); qDebug("");
@ -1159,82 +1140,3 @@ void MainWindow::updateTaskbar(EncodeThread::JobStatus status, const QIcon &icon
WinSevenTaskbar::setOverlayIcon(this, icon.isNull() ? NULL : &icon); WinSevenTaskbar::setOverlayIcon(this, icon.isNull() ? NULL : &icon);
} }
/*
* Detect Avisynth version
*/
double MainWindow::detectAvisynthVersion(QLibrary *avsLib, DWORD *errorCode)
{
qDebug("detectAvisynthVersion(QLibrary *avsLib)");
if(errorCode) *errorCode = 0;
double version_number = 0.0;
EXCEPTION_RECORD exceptionRecord;
__try
{
avs_create_script_environment_func avs_create_script_environment_ptr = (avs_create_script_environment_func) avsLib->resolve("avs_create_script_environment");
avs_invoke_func avs_invoke_ptr = (avs_invoke_func) avsLib->resolve("avs_invoke");
avs_function_exists_func avs_function_exists_ptr = (avs_function_exists_func) avsLib->resolve("avs_function_exists");
avs_delete_script_environment_func avs_delete_script_environment_ptr = (avs_delete_script_environment_func) avsLib->resolve("avs_delete_script_environment");
avs_release_value_func avs_release_value_ptr = (avs_release_value_func) avsLib->resolve("avs_release_value");
//volatile int x = 0, y = 0; x = 42 / y;
if((avs_create_script_environment_ptr != NULL) && (avs_invoke_ptr != NULL) && (avs_function_exists_ptr != NULL))
{
qDebug("avs_create_script_environment_ptr(AVS_INTERFACE_25)");
AVS_ScriptEnvironment* avs_env = avs_create_script_environment_ptr(AVS_INTERFACE_25);
if(avs_env != NULL)
{
qDebug("avs_function_exists_ptr(avs_env, \"VersionNumber\")");
if(avs_function_exists_ptr(avs_env, "VersionNumber"))
{
qDebug("avs_invoke_ptr(avs_env, \"VersionNumber\", avs_new_value_array(NULL, 0), NULL)");
AVS_Value avs_version = avs_invoke_ptr(avs_env, "VersionNumber", avs_new_value_array(NULL, 0), NULL);
if(!avs_is_error(avs_version))
{
if(avs_is_float(avs_version))
{
qDebug("Avisynth version: v%.2f", avs_as_float(avs_version));
version_number = avs_as_float(avs_version);
if(avs_release_value_ptr) avs_release_value_ptr(avs_version);
}
else
{
qWarning("Failed to determine version number, Avisynth didn't return a float!");
}
}
else
{
qWarning("Failed to determine version number, Avisynth returned an error!");
}
}
else
{
qWarning("The 'VersionNumber' function does not exist in your Avisynth DLL, can't determine version!");
}
if(avs_delete_script_environment_ptr != NULL)
{
avs_delete_script_environment_ptr(avs_env);
avs_env = NULL;
}
}
else
{
qWarning("The Avisynth DLL failed to create the script environment!");
}
}
else
{
qWarning("It seems the Avisynth DLL is missing required API functions!");
}
}
__except(exceptionFilter(&exceptionRecord, GetExceptionInformation()))
{
if(errorCode) *errorCode = exceptionRecord.ExceptionCode;
qWarning("Exception in Avisynth initialization code! (Address: %p, Code: 0x%08x)", exceptionRecord.ExceptionAddress, exceptionRecord.ExceptionCode);
version_number = -1.0;
}
return version_number;
}

View File

@ -53,7 +53,6 @@ private:
bool m_firstShow; bool m_firstShow;
QLabel *m_label; QLabel *m_label;
IPCThread *m_ipcThread; IPCThread *m_ipcThread;
QLibrary *m_avsLib;
JobListModel *m_jobList; JobListModel *m_jobList;
OptionsModel *m_options; OptionsModel *m_options;
@ -69,7 +68,6 @@ private:
void updateTaskbar(EncodeThread::JobStatus status, const QIcon &icon); void updateTaskbar(EncodeThread::JobStatus status, const QIcon &icon);
unsigned int countPendingJobs(void); unsigned int countPendingJobs(void);
unsigned int countRunningJobs(void); unsigned int countRunningJobs(void);
double detectAvisynthVersion(QLibrary *avsLib, DWORD *errorCode = NULL);
private slots: private slots:
void addButtonPressed(const QString &filePathIn = QString(), const QString &filePathOut = QString(), OptionsModel *options = NULL, int fileNo = -1, int fileTotal = 0, bool *ok = NULL); void addButtonPressed(const QString &filePathIn = QString(), const QString &filePathOut = QString(), OptionsModel *options = NULL, int fileNo = -1, int fileTotal = 0, bool *ok = NULL);

View File

@ -287,6 +287,14 @@ copy /Y "$(QTDIR)\plugins\imageformats\qgif4.dll" "$(TargetDir)\imageformats"
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild> </CustomBuild>
<CustomBuild Include="src\thread_avisynth.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MOC "$(SolutionDir)tmp\moc\moc_%(Filename).cpp"</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MOC "$(SolutionDir)tmp\moc\moc_%(Filename).cpp"</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild>
<ClInclude Include="src\version.h" /> <ClInclude Include="src\version.h" />
<CustomBuild Include="src\win_main.h"> <CustomBuild Include="src\win_main.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)"</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)"</Command>
@ -306,6 +314,7 @@ copy /Y "$(QTDIR)\plugins\imageformats\qgif4.dll" "$(TargetDir)\imageformats"
<TreatWChar_tAsBuiltInType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</TreatWChar_tAsBuiltInType> <TreatWChar_tAsBuiltInType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</TreatWChar_tAsBuiltInType>
</ClCompile> </ClCompile>
<ClCompile Include="src\taskbar7.cpp" /> <ClCompile Include="src\taskbar7.cpp" />
<ClCompile Include="src\thread_avisynth.cpp" />
<ClCompile Include="src\thread_encode.cpp" /> <ClCompile Include="src\thread_encode.cpp" />
<ClCompile Include="src\global.cpp" /> <ClCompile Include="src\global.cpp" />
<ClCompile Include="src\main.cpp" /> <ClCompile Include="src\main.cpp" />
@ -317,6 +326,7 @@ copy /Y "$(QTDIR)\plugins\imageformats\qgif4.dll" "$(TargetDir)\imageformats"
<ClCompile Include="src\win_preferences.cpp" /> <ClCompile Include="src\win_preferences.cpp" />
<ClCompile Include="tmp\moc\moc_model_jobList.cpp" /> <ClCompile Include="tmp\moc\moc_model_jobList.cpp" />
<ClCompile Include="tmp\moc\moc_model_logFile.cpp" /> <ClCompile Include="tmp\moc\moc_model_logFile.cpp" />
<ClCompile Include="tmp\moc\moc_thread_avisynth.cpp" />
<ClCompile Include="tmp\moc\moc_thread_encode.cpp" /> <ClCompile Include="tmp\moc\moc_thread_encode.cpp" />
<ClCompile Include="tmp\moc\moc_thread_ipc.cpp" /> <ClCompile Include="tmp\moc\moc_thread_ipc.cpp" />
<ClCompile Include="tmp\moc\moc_win_addJob.cpp" /> <ClCompile Include="tmp\moc\moc_win_addJob.cpp" />

View File

@ -48,6 +48,9 @@
<ClInclude Include="src\taskbar7.h"> <ClInclude Include="src\taskbar7.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\thread_avisynth.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\main.cpp"> <ClCompile Include="src\main.cpp">
@ -122,6 +125,12 @@
<ClCompile Include="src\qtmain_win.cpp"> <ClCompile Include="src\qtmain_win.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\thread_avisynth.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tmp\moc\moc_thread_avisynth.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="src\win_main.h"> <CustomBuild Include="src\win_main.h">