OSDN Git Service

ceb99c06c9fead5de3bcb721d4cc0a420b0b57ab
[lamexp/LameXP.git] / src / Encoder_AAC.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2011 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 "Encoder_AAC.h"
23
24 #include "Global.h"
25 #include "Model_Settings.h"
26
27 #include <QProcess>
28 #include <QDir>
29
30 AACEncoder::AACEncoder(void)
31 :
32         m_binary_enc(lamexp_lookup_tool("neroAacEnc.exe")),
33         m_binary_tag(lamexp_lookup_tool("neroAacTag.exe"))
34 {
35         if(m_binary_enc.isEmpty() || m_binary_tag.isEmpty())
36         {
37                 throw "Error initializing AAC encoder. Tool 'neroAacEnc.exe' is not registred!";
38         }
39
40         m_configProfile = 0;
41         m_configEnable2Pass = true;
42 }
43
44 AACEncoder::~AACEncoder(void)
45 {
46 }
47
48 bool AACEncoder::encode(const QString &sourceFile, const AudioFileModel &metaInfo, const QString &outputFile, volatile bool *abortFlag)
49 {
50         QProcess process;
51         QStringList args;
52         const QString baseName = QFileInfo(outputFile).fileName();
53
54         switch(m_configRCMode)
55         {
56         case SettingsModel::VBRMode:
57                 args << "-q" << QString().sprintf("%.2f", qMin(1.0, qMax(0.0, static_cast<double>(m_configBitrate * 5) / 100.0)));
58                 break;
59         case SettingsModel::ABRMode:
60                 args << "-br" << QString::number(qMax(32, qMin(500, (m_configBitrate * 8))) * 1000);
61                 break;
62         case SettingsModel::CBRMode:
63                 args << "-cbr" << QString::number(qMax(32, qMin(500, (m_configBitrate * 8))) * 1000);
64                 break;
65         default:
66                 throw "Bad rate-control mode!";
67                 break;
68         }
69
70         if(m_configEnable2Pass && (m_configRCMode == SettingsModel::ABRMode))
71         {
72                 args << "-2pass";
73         }
74         
75         switch(m_configProfile)
76         {
77         case 1:
78                 args << "-lc"; //Forces use of LC AAC profile
79                 break;
80         case 2:
81                 args << "-he"; //Forces use of HE AAC profile
82                 break;
83         case 3:
84                 args << "-hev2"; //Forces use of HEv2 AAC profile
85                 break;
86         }
87
88         if(!m_configCustomParams.isEmpty()) args << m_configCustomParams.split(" ", QString::SkipEmptyParts);
89
90         args << "-if" << QDir::toNativeSeparators(sourceFile);
91         args << "-of" << QDir::toNativeSeparators(outputFile);
92
93         if(!startProcess(process, m_binary_enc, args))
94         {
95                 return false;
96         }
97
98         bool bTimeout = false;
99         bool bAborted = false;
100
101         QRegExp regExp("Processed\\s+(\\d+)\\s+seconds");
102         QRegExp regExp_pass1("First\\s+pass:\\s+processed\\s+(\\d+)\\s+seconds");
103         QRegExp regExp_pass2("Second\\s+pass:\\s+processed\\s+(\\d+)\\s+seconds");
104
105         while(process.state() != QProcess::NotRunning)
106         {
107                 if(*abortFlag)
108                 {
109                         process.kill();
110                         bAborted = true;
111                         emit messageLogged("\nABORTED BY USER !!!");
112                         break;
113                 }
114                 process.waitForReadyRead(m_processTimeoutInterval);
115                 if(!process.bytesAvailable() && process.state() == QProcess::Running)
116                 {
117                         process.kill();
118                         qWarning("NeroAacEnc process timed out <-- killing!");
119                         emit messageLogged("\nPROCESS TIMEOUT !!!");
120                         bTimeout = true;
121                         break;
122                 }
123                 while(process.bytesAvailable() > 0)
124                 {
125                         QByteArray line = process.readLine();
126                         QString text = QString::fromUtf8(line.constData()).simplified();
127                         if(regExp_pass1.lastIndexIn(text) >= 0)
128                         {
129                                 bool ok = false;
130                                 int progress = regExp_pass1.cap(1).toInt(&ok);
131                                 if(ok && metaInfo.fileDuration() > 0)
132                                 {
133                                         emit statusUpdated(static_cast<int>((static_cast<double>(progress) / static_cast<double>(metaInfo.fileDuration())) * 50.0));
134                                 }
135                         }
136                         else if(regExp_pass2.lastIndexIn(text) >= 0)
137                         {
138                                 bool ok = false;
139                                 int progress = regExp_pass2.cap(1).toInt(&ok);
140                                 if(ok && metaInfo.fileDuration() > 0)
141                                 {
142                                         emit statusUpdated(static_cast<int>((static_cast<double>(progress) / static_cast<double>(metaInfo.fileDuration())) * 50.0) + 50);
143                                 }
144                         }
145                         else if(regExp.lastIndexIn(text) >= 0)
146                         {
147                                 bool ok = false;
148                                 int progress = regExp.cap(1).toInt(&ok);
149                                 if(ok && metaInfo.fileDuration() > 0)
150                                 {
151                                         emit statusUpdated(static_cast<int>((static_cast<double>(progress) / static_cast<double>(metaInfo.fileDuration())) * 100.0));
152                                 }
153                         }
154                         else if(!text.isEmpty())
155                         {
156                                 emit messageLogged(text);
157                         }
158                 }
159         }
160
161         process.waitForFinished();
162         if(process.state() != QProcess::NotRunning)
163         {
164                 process.kill();
165                 process.waitForFinished(-1);
166         }
167         
168         emit statusUpdated(100);
169         emit messageLogged(QString().sprintf("\nExited with code: 0x%04X", process.exitCode()));
170
171         if(bTimeout || bAborted || process.exitStatus() != QProcess::NormalExit)
172         {
173                 return false;
174         }
175
176         emit messageLogged("\n-------------------------------\n");
177         
178         args.clear();
179         args << QDir::toNativeSeparators(outputFile);
180
181         if(!metaInfo.fileName().isEmpty()) args << QString("-meta:title=%1").arg(metaInfo.fileName());
182         if(!metaInfo.fileArtist().isEmpty()) args << QString("-meta:artist=%1").arg(metaInfo.fileArtist());
183         if(!metaInfo.fileAlbum().isEmpty()) args << QString("-meta:album=%1").arg(metaInfo.fileAlbum());
184         if(!metaInfo.fileGenre().isEmpty()) args << QString("-meta:genre=%1").arg(metaInfo.fileGenre());
185         if(!metaInfo.fileComment().isEmpty()) args << QString("-meta:comment=%1").arg(metaInfo.fileComment());
186         if(metaInfo.fileYear()) args << QString("-meta:year=%1").arg(QString::number(metaInfo.fileYear()));
187         if(metaInfo.filePosition()) args << QString("-meta:track=%1").arg(QString::number(metaInfo.filePosition()));
188         if(!metaInfo.fileCover().isEmpty()) args << QString("-add-cover:%1:%2").arg("front", metaInfo.fileCover());
189         
190         if(!startProcess(process, m_binary_tag, args))
191         {
192                 return false;
193         }
194
195         bTimeout = false;
196
197         while(process.state() != QProcess::NotRunning)
198         {
199                 if(*abortFlag)
200                 {
201                         process.kill();
202                         bAborted = true;
203                         emit messageLogged("\nABORTED BY USER !!!");
204                         break;
205                 }
206                 process.waitForReadyRead(m_processTimeoutInterval);
207                 if(!process.bytesAvailable() && process.state() == QProcess::Running)
208                 {
209                         process.kill();
210                         qWarning("NeroAacTag process timed out <-- killing!");
211                         emit messageLogged("\nPROCESS TIMEOUT !!!");
212                         bTimeout = true;
213                         break;
214                 }
215                 while(process.bytesAvailable() > 0)
216                 {
217                         QByteArray line = process.readLine();
218                         QString text = QString::fromUtf8(line.constData()).simplified();
219                         if(!text.isEmpty())
220                         {
221                                 emit messageLogged(text);
222                         }
223                 }
224         }
225
226         process.waitForFinished();
227         if(process.state() != QProcess::NotRunning)
228         {
229                 process.kill();
230                 process.waitForFinished(-1);
231         }
232                 
233         emit messageLogged(QString().sprintf("\nExited with code: 0x%04X", process.exitCode()));
234
235         if(bTimeout || bAborted || process.exitStatus() != QProcess::NormalExit)
236         {
237                 return false;
238         }
239
240         return true;
241 }
242
243 QString AACEncoder::extension(void)
244 {
245         return "mp4";
246 }
247
248 bool AACEncoder::isFormatSupported(const QString &containerType, const QString &containerProfile, const QString &formatType, const QString &formatProfile, const QString &formatVersion)
249 {
250         if(containerType.compare("Wave", Qt::CaseInsensitive) == 0)
251         {
252                 if(formatType.compare("PCM", Qt::CaseInsensitive) == 0)
253                 {
254                         return true;
255                 }
256         }
257
258         return false;
259 }
260
261
262 void AACEncoder::setProfile(int profile)
263 {
264         m_configProfile = profile;
265 }
266
267 void AACEncoder::setEnable2Pass(bool enabled)
268 {
269         m_configEnable2Pass = enabled;
270 }