OSDN Git Service

Added support for detecting "portable" Avisynth.
[x264-launcher/x264-launcher.git] / src / source_avisynth.cpp
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.
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 #pragma once
23
24 #include "source_avisynth.h"
25
26 #include "global.h"
27
28 #include <MUtils/Global.h>
29
30 #include <QDir>
31 #include <QProcess>
32
33 static const unsigned int VER_X264_AVS2YUV_VER = 243;
34
35 // ------------------------------------------------------------
36 // Encoder Info
37 // ------------------------------------------------------------
38
39 class AvisynthSourceInfo : public AbstractSourceInfo
40 {
41 public:
42         virtual QString getBinaryPath(const SysinfoModel *const sysinfo, const bool& x64) const
43         {
44                 return QString("%1/toolset/%2/avs2yuv_%2.exe").arg(sysinfo->getAppPath(), (x64 ? "x64": "x86"));
45         }
46
47         virtual QString getExtraPath(const SysinfoModel *const sysinfo, const bool& x64) const
48         {
49                 const QString avsPath = sysinfo->getAVSPath();
50                 if (!avsPath.isEmpty())
51                 {
52                 
53                         return QString("%1/%2").arg(avsPath, x64 ? QLatin1String("x64") : QLatin1String("x86"));
54                 }
55                 return QString();
56         }
57 };
58
59 static const AvisynthSourceInfo s_avisynthEncoderInfo;
60
61 const AbstractSourceInfo &AvisynthSource::getSourceInfo(void)
62 {
63         return s_avisynthEncoderInfo;
64 }
65
66
67 // ------------------------------------------------------------
68 // Constructor & Destructor
69 // ------------------------------------------------------------
70
71 AvisynthSource::AvisynthSource(JobObject *jobObject, const OptionsModel *options, const SysinfoModel *const sysinfo, const PreferencesModel *const preferences, JobStatus &jobStatus, volatile bool *abort, volatile bool *pause, QSemaphore *semaphorePause, const QString &sourceFile)
72 :
73         AbstractSource(jobObject, options, sysinfo, preferences, jobStatus, abort, pause, semaphorePause, sourceFile)
74 {
75         /*Nothing to do here*/
76 }
77
78 AvisynthSource::~AvisynthSource(void)
79 {
80         /*Nothing to do here*/
81 }
82
83 QString AvisynthSource::getName(void) const
84 {
85         return tr("Avisynth (avs)");
86 }
87
88 // ------------------------------------------------------------
89 // Check Version
90 // ------------------------------------------------------------
91
92 bool AvisynthSource::isSourceAvailable()
93 {
94         if(!(m_sysinfo->hasAvisynth()))
95         {
96                 log(tr("\nAVS INPUT REQUIRES AVISYNTH, BUT IT IS *NOT* AVAILABLE !!!"));
97                 return false;
98         }
99         return true;
100 }
101
102 void AvisynthSource::checkVersion_init(QList<QRegExp*> &patterns, QStringList &cmdLine)
103 {
104         patterns << new QRegExp("\\bAvs2YUV (\\d+).(\\d+)\\b", Qt::CaseInsensitive);
105         patterns << new QRegExp("\\bAvs2YUV (\\d+).(\\d+)bm(\\d)\\b", Qt::CaseInsensitive);
106 }
107
108 void AvisynthSource::checkVersion_parseLine(const QString &line, QList<QRegExp*> &patterns, unsigned int &core, unsigned int &build, bool &modified)
109 {
110         int offset = -1;
111
112         if((offset = patterns[0]->lastIndexIn(line)) >= 0)
113         {
114                 bool ok1 = false, ok2 = false;
115                 unsigned int temp1 = patterns[0]->cap(1).toUInt(&ok1);
116                 unsigned int temp2 = patterns[0]->cap(2).toUInt(&ok2);
117                 if(ok1 && ok2)
118                 {
119                         core  = temp1;
120                         build = temp2;
121                 }
122                 log(line);
123         }
124         else if((offset = patterns[1]->lastIndexIn(line)) >= 0)
125         {
126                 bool ok1 = false, ok2 = false, ok3 = false;
127                 unsigned int temp1 = patterns[1]->cap(1).toUInt(&ok1);
128                 unsigned int temp2 = patterns[1]->cap(2).toUInt(&ok2);
129                 unsigned int temp3 = patterns[1]->cap(3).toUInt(&ok3);
130                 if(ok1 && ok2 && ok3)
131                 {
132                         core  = temp1;
133                         build = (temp2 * 10) + (temp3 % 10);
134                 }
135                 modified = true;
136                 log(line);
137         }
138 }
139
140 bool AvisynthSource::checkVersion_succeeded(const int &exitCode)
141 {
142         return (exitCode == EXIT_SUCCESS) || (exitCode == 2);
143 }
144
145 QString AvisynthSource::printVersion(const unsigned int &revision, const bool &modified)
146 {
147         unsigned int core, build;
148         splitRevision(revision, core, build);
149
150         return tr("Avs2YUV version: %1.%2.%3").arg(QString::number(core), QString::number(build / 10),QString::number(build % 10));
151 }
152
153 bool AvisynthSource::isVersionSupported(const unsigned int &revision, const bool &modified)
154 {
155         unsigned int core, build;
156         splitRevision(revision, core, build);
157
158         if((revision != UINT_MAX) && (build < VER_X264_AVS2YUV_VER))
159         {
160                 log(tr("\nERROR: Your version of avs2yuv is unsupported (required version: v0.24 BugMaster's mod 2)"));
161                 log(tr("You can find the required version at: http://komisar.gin.by/tools/avs2yuv/"));
162                 return false;
163         }
164         return true;
165 }
166
167 // ------------------------------------------------------------
168 // Check Source Properties
169 // ------------------------------------------------------------
170
171 void AvisynthSource::checkSourceProperties_init(QList<QRegExp*> &patterns, QStringList &cmdLine)
172 {
173         if(!m_options->customAvs2YUV().isEmpty())
174         {
175                 cmdLine << splitParams(m_options->customAvs2YUV());
176         }
177
178         cmdLine << "-frames" << "1";
179         cmdLine << QDir::toNativeSeparators(x264_path2ansi(m_sourceFile, true)) << "NUL";
180
181         patterns << new QRegExp(": (\\d+)x(\\d+), (\\d+) fps, (\\d+) frames");
182         patterns << new QRegExp(": (\\d+)x(\\d+), (\\d+)/(\\d+) fps, (\\d+) frames");
183 }
184
185 void AvisynthSource::checkSourceProperties_parseLine(const QString &line, QList<QRegExp*> &patterns, ClipInfo &clipInfo)
186 {
187         int offset = -1;
188
189         if((offset = patterns[0]->lastIndexIn(line)) >= 0)
190         {
191                 bool ok[4] = { false, false, false, false };
192                 quint32 temp[4];
193                 temp[0] = patterns[0]->cap(1).toUInt(&ok[0]);
194                 temp[1] = patterns[0]->cap(2).toUInt(&ok[1]);
195                 temp[2] = patterns[0]->cap(3).toUInt(&ok[2]);
196                 temp[3] = patterns[0]->cap(4).toUInt(&ok[3]);
197                 if (ok[0] && ok[1])
198                 {
199                         clipInfo.setFrameSize(temp[0], temp[1]);
200                 }
201                 if (ok[2])
202                 {
203                         clipInfo.setFrameRate(temp[2], 0);
204                 }
205                 if (ok[3])
206                 {
207                         clipInfo.setFrameCount(temp[3]);
208                 }
209         }
210         else if((offset = patterns[1]->lastIndexIn(line)) >= 0)
211         {
212                 bool ok[5] = { false, false, false, false, false };
213                 quint32 temp[5];
214                 temp[0] = patterns[1]->cap(1).toUInt(&ok[0]);
215                 temp[1] = patterns[1]->cap(2).toUInt(&ok[1]);
216                 temp[2] = patterns[1]->cap(3).toUInt(&ok[2]);
217                 temp[3] = patterns[1]->cap(4).toUInt(&ok[3]);
218                 temp[4] = patterns[1]->cap(5).toUInt(&ok[4]);
219                 if (ok[0] && ok[1])
220                 {
221                         clipInfo.setFrameSize(temp[0], temp[1]);
222                 }
223                 if (ok[2] && ok[3])
224                 {
225                         clipInfo.setFrameRate(temp[2], temp[3]);
226                 }
227                 if (ok[4])
228                 {
229                         clipInfo.setFrameCount(temp[4]);
230                 }
231         }
232
233         if(!line.isEmpty())
234         {
235                 log(line);
236         }
237
238         if(line.contains("failed to load avisynth.dll", Qt::CaseInsensitive))
239         {
240                 log(tr("\nWarning: It seems that Avisynth is not currently installed/available !!!"));
241         }
242         if(line.contains(QRegExp("couldn't convert input clip to (YV16|YV24)", Qt::CaseInsensitive)))
243         {
244                 log(tr("\nWarning: YV16 (4:2:2) and YV24 (4:4:4) color-spaces only supported in Avisynth 2.6 !!!"));
245         }
246 }
247
248 // ------------------------------------------------------------
249 // Source Processing
250 // ------------------------------------------------------------
251
252 void AvisynthSource::buildCommandLine(QStringList &cmdLine)
253 {
254         if(!m_options->customAvs2YUV().isEmpty())
255         {
256                 cmdLine << splitParams(m_options->customAvs2YUV());
257         }
258
259         cmdLine << QDir::toNativeSeparators(x264_path2ansi(m_sourceFile, true));
260         cmdLine << "-";
261 }
262
263 void AvisynthSource::flushProcess(QProcess &processInput)
264 {
265         while(processInput.bytesAvailable() > 0)
266         {
267                 log(tr("av2y [info]: %1").arg(QString::fromUtf8(processInput.readLine()).simplified()));
268         }
269         
270         if(processInput.exitCode() != EXIT_SUCCESS)
271         {
272                 const int exitCode = processInput.exitCode();
273                 log(tr("\nWARNING: Input process exited with error (code: %1), your encode might be *incomplete* !!!").arg(QString::number(exitCode)));
274                 if((exitCode < 0) || (exitCode >= 32))
275                 {
276                         log(tr("\nIMPORTANT: The Avs2YUV process terminated abnormally. This means Avisynth or one of your Avisynth-Plugin's just crashed."));
277                         log(tr("IMPORTANT: Please fix your Avisynth script and try again! If you use Avisynth-MT, try using a *stable* Avisynth instead!"));
278                 }
279         }
280 }