OSDN Git Service

Happy new year 2014!
[x264-launcher/x264-launcher.git] / src / thread_avisynth.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2014 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.
14 //
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.
18 //
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
21
22 #include "thread_avisynth.h"
23
24 #include <QLibrary>
25 #include <QEventLoop>
26 #include <QTimer>
27 #include <QMutexLocker>
28 #include <QApplication>
29
30 #include "global.h"
31 #include "3rd_party/avisynth_c.h"
32
33 QMutex AvisynthCheckThread::m_avsLock;
34 QLibrary *AvisynthCheckThread::m_avsLib = NULL;
35
36 //-------------------------------------
37 // External API
38 //-------------------------------------
39
40 int AvisynthCheckThread::detect(volatile double *version)
41 {
42         *version = 0.0;
43         QMutexLocker lock(&m_avsLock);
44
45         QEventLoop loop;
46         AvisynthCheckThread thread;
47
48         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
49
50         connect(&thread, SIGNAL(finished()), &loop, SLOT(quit()));
51         connect(&thread, SIGNAL(terminated()), &loop, SLOT(quit()));
52         
53         thread.start();
54         QTimer::singleShot(15000, &loop, SLOT(quit()));
55         
56         qDebug("Avisynth thread has been created, please wait...");
57         loop.exec(QEventLoop::ExcludeUserInputEvents);
58         qDebug("Avisynth thread finished.");
59
60         QApplication::restoreOverrideCursor();
61
62         if(!thread.wait(1000))
63         {
64                 qWarning("Avisynth thread encountered timeout -> probably deadlock!");
65                 thread.terminate();
66                 thread.wait();
67                 return -1;
68         }
69
70         if(thread.getException())
71         {
72                 qWarning("Avisynth thread encountered an exception !!!");
73                 return -1;
74         }
75         
76         if(thread.getSuccess())
77         {
78                 *version = thread.getVersion();
79                 qDebug("Version check completed: %.2f", *version);
80                 return 1;
81         }
82
83         qWarning("Avisynth thread failed to determine the version!");
84         return 0;
85 }
86
87 void AvisynthCheckThread::unload(void)
88 {
89         QMutexLocker lock(&m_avsLock);
90
91         if(m_avsLib)
92         {
93                 if(m_avsLib->isLoaded())
94                 {
95                         m_avsLib->unload();
96                 }
97         }
98
99         X264_DELETE(m_avsLib);
100 }
101
102 //-------------------------------------
103 // Thread class
104 //-------------------------------------
105
106 AvisynthCheckThread::AvisynthCheckThread(void)
107 {
108         m_success = false;
109         m_exception = false;
110         m_version = 0.0;
111 }
112
113 AvisynthCheckThread::~AvisynthCheckThread(void)
114 {
115 }
116
117 void AvisynthCheckThread::run(void)
118 {
119         m_exception = m_success = false;
120         m_success = detectAvisynthVersion1(&m_version, &m_exception);
121 }
122
123 bool AvisynthCheckThread::detectAvisynthVersion1(volatile double *version_number, volatile bool *exception)
124 {
125         __try
126         {
127                 return detectAvisynthVersion2(version_number, exception);
128         }
129         __except(1)
130         {
131                 *exception = true;
132                 qWarning("Unhandled exception error in Avisynth thread !!!");
133                 return false;
134         }
135 }
136
137 bool AvisynthCheckThread::detectAvisynthVersion2(volatile double *version_number, volatile bool *exception)
138 {
139         try
140         {
141                 return detectAvisynthVersion3(version_number);
142         }
143         catch(...)
144         {
145                 *exception = true;
146                 qWarning("Avisynth initializdation raised an C++ exception!");
147                 return false;
148         }
149 }
150
151 bool AvisynthCheckThread::detectAvisynthVersion3(volatile double *version_number)
152 {
153         bool success = false;
154         *version_number = 0.0;
155
156         if(!m_avsLib)
157         {
158                 m_avsLib = new QLibrary("avisynth.dll");
159         }
160
161         if(m_avsLib->isLoaded() || m_avsLib->load())
162         {
163                 avs_create_script_environment_func avs_create_script_environment_ptr = (avs_create_script_environment_func) m_avsLib->resolve("avs_create_script_environment");
164                 avs_invoke_func avs_invoke_ptr = (avs_invoke_func) m_avsLib->resolve("avs_invoke");
165                 avs_function_exists_func avs_function_exists_ptr = (avs_function_exists_func) m_avsLib->resolve("avs_function_exists");
166                 avs_delete_script_environment_func avs_delete_script_environment_ptr = (avs_delete_script_environment_func) m_avsLib->resolve("avs_delete_script_environment");
167                 avs_release_value_func avs_release_value_ptr = (avs_release_value_func) m_avsLib->resolve("avs_release_value");
168         
169                 if((avs_create_script_environment_ptr != NULL) && (avs_invoke_ptr != NULL) && (avs_function_exists_ptr != NULL))
170                 {
171                         qDebug("avs_create_script_environment_ptr(AVS_INTERFACE_25)");
172                         AVS_ScriptEnvironment* avs_env = avs_create_script_environment_ptr(AVS_INTERFACE_25);
173                         if(avs_env != NULL)
174                         {
175                                 qDebug("avs_function_exists_ptr(avs_env, \"VersionNumber\")");
176                                 if(avs_function_exists_ptr(avs_env, "VersionNumber"))
177                                 {
178                                         qDebug("avs_invoke_ptr(avs_env, \"VersionNumber\", avs_new_value_array(NULL, 0), NULL)");
179                                         AVS_Value avs_version = avs_invoke_ptr(avs_env, "VersionNumber", avs_new_value_array(NULL, 0), NULL);
180                                         if(!avs_is_error(avs_version))
181                                         {
182                                                 if(avs_is_float(avs_version))
183                                                 {
184                                                         qDebug("Avisynth version: v%.2f", avs_as_float(avs_version));
185                                                         *version_number = avs_as_float(avs_version);
186                                                         if(avs_release_value_ptr) avs_release_value_ptr(avs_version);
187                                                         success = true;
188                                                 }
189                                                 else
190                                                 {
191                                                         qWarning("Failed to determine version number, Avisynth didn't return a float!");
192                                                 }
193                                         }
194                                         else
195                                         {
196                                                 qWarning("Failed to determine version number, Avisynth returned an error!");
197                                         }
198                                 }
199                                 else
200                                 {
201                                         qWarning("The 'VersionNumber' function does not exist in your Avisynth DLL, can't determine version!");
202                                 }
203                                 if(avs_delete_script_environment_ptr != NULL)
204                                 {
205                                         avs_delete_script_environment_ptr(avs_env);
206                                         avs_env = NULL;
207                                 }
208                         }
209                         else
210                         {
211                                 qWarning("The Avisynth DLL failed to create the script environment!");
212                         }
213                 }
214                 else
215                 {
216                         qWarning("It seems the Avisynth DLL is missing required API functions!");
217                 }
218         }
219         else
220         {
221                 qWarning("Failed to load Avisynth.dll library!");
222         }
223
224         return success;
225 }