OSDN Git Service

Fixed parsing of source properties for new Avs2YUV version.
[x264-launcher/x264-launcher.git] / src / source_avisynth.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2017 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 = 245;
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 QStringList getExtraPaths(const SysinfoModel *const sysinfo, const bool& x64) const
48         {
49                 const QString avsPath = sysinfo->getAVSPath();
50                 if (!avsPath.isEmpty())
51                 {
52                 
53                         return QStringList() << QString("%1/%2").arg(avsPath, x64 ? QLatin1String("x64") : QLatin1String("x86"));
54                 }
55                 return QStringList();
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, const 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(":\\s+(\\d+)\\s*x\\s*(\\d+)\\s*,\\s+\\w+\\s*,\\s+\\d+-bits\\s*,\\s+\\w+\\s*,\\s+(\\d+)\\s+fps\\s*,\\s+(\\d+)\\s+frames");
182         patterns << new QRegExp(":\\s+(\\d+)\\s*x\\s*(\\d+)\\s*,\\s+\\w+\\s*,\\s+\\d+-bits\\s*,\\s+\\w+\\s*,\\s+(\\d+)\\s*/\\s*(\\d+)\\s+fps\\s*,\\s+(\\d+)\\s+frames");
183 }
184
185 void AvisynthSource::checkSourceProperties_parseLine(const QString &line, const QList<QRegExp*> &patterns, ClipInfo &clipInfo)
186 {
187         int offset = -1;
188         quint32 temp[5];
189
190         if((offset = patterns[0]->lastIndexIn(line)) >= 0)
191         {
192                 if (MUtils::regexp_parse_uint32((*patterns[0]), temp, 4))
193                 {
194                         clipInfo.setFrameSize(temp[0], temp[1]);
195                         clipInfo.setFrameRate(temp[2], 0);
196                         clipInfo.setFrameCount(temp[3]);
197                 }
198         }
199         else if((offset = patterns[1]->lastIndexIn(line)) >= 0)
200         {
201                 if (MUtils::regexp_parse_uint32((*patterns[1]), temp, 5))
202                 {
203                         clipInfo.setFrameSize(temp[0], temp[1]);
204                         clipInfo.setFrameRate(temp[2], temp[3]);
205                         clipInfo.setFrameCount(temp[4]);
206                 }
207         }
208
209         if(!line.isEmpty())
210         {
211                 log(line);
212         }
213
214         if(line.contains("failed to load avisynth.dll", Qt::CaseInsensitive))
215         {
216                 log(tr("\nWarning: It seems that Avisynth is not currently installed/available !!!"));
217         }
218         if(line.contains(QRegExp("couldn't convert input clip to (YV16|YV24)", Qt::CaseInsensitive)))
219         {
220                 log(tr("\nWarning: YV16 (4:2:2) and YV24 (4:4:4) color-spaces only supported in Avisynth 2.6 !!!"));
221         }
222 }
223
224 // ------------------------------------------------------------
225 // Source Processing
226 // ------------------------------------------------------------
227
228 void AvisynthSource::buildCommandLine(QStringList &cmdLine)
229 {
230         if(!m_options->customAvs2YUV().isEmpty())
231         {
232                 cmdLine << splitParams(m_options->customAvs2YUV());
233         }
234
235         cmdLine << QDir::toNativeSeparators(x264_path2ansi(m_sourceFile, true));
236         cmdLine << "-";
237 }
238
239 void AvisynthSource::flushProcess(QProcess &processInput)
240 {
241         while(processInput.bytesAvailable() > 0)
242         {
243                 log(tr("av2y [info]: %1").arg(QString::fromUtf8(processInput.readLine()).simplified()));
244         }
245         
246         if(processInput.exitCode() != EXIT_SUCCESS)
247         {
248                 const int exitCode = processInput.exitCode();
249                 log(tr("\nWARNING: Input process exited with error (code: %1), your encode might be *incomplete* !!!").arg(QString::number(exitCode)));
250                 if((exitCode < 0) || (exitCode >= 32))
251                 {
252                         log(tr("\nIMPORTANT: The Avs2YUV process terminated abnormally. This means Avisynth or one of your Avisynth-Plugin's just crashed."));
253                         log(tr("IMPORTANT: Please fix your Avisynth script and try again! If you use Avisynth-MT, try using a *stable* Avisynth instead!"));
254                 }
255         }
256 }