Skip to content
This repository
Newer
Older
100644 357 lines (317 sloc) 9.99 kb
36ae27f5 »
2010-11-06 first commit
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2010 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_FileAnalyzer.h"
23
24 #include "Global.h"
25 #include "LockedFile.h"
26 #include "Model_AudioFile.h"
27
28 #include <QDir>
29 #include <QFileInfo>
30 #include <QProcess>
31 #include <QDate>
32 #include <QTime>
33
34 #include <math.h>
35
36 ////////////////////////////////////////////////////////////
37 // Constructor
38 ////////////////////////////////////////////////////////////
39
40 FileAnalyzer::FileAnalyzer(const QStringList &inputFiles)
41 : m_inputFiles(inputFiles)
42 {
43 m_bSuccess = false;
44 m_mediaInfoBin = lamexp_lookup_tool("mediainfo_icl11.exe");
45
46 if(m_mediaInfoBin.isEmpty())
47 {
48 qFatal("Invalid path to MediaInfo binary. Tool not initialized properly.");
49 }
88eae834 »
2010-11-11 Move about dialog into a separate class
50
51 m_filesAccepted = 0;
52 m_filesRejected = 0;
53 m_filesDenied = 0;
36ae27f5 »
2010-11-06 first commit
54 }
55
56 ////////////////////////////////////////////////////////////
57 // Thread Main
58 ////////////////////////////////////////////////////////////
59
60 void FileAnalyzer::run()
61 {
62 m_bSuccess = false;
88eae834 »
2010-11-11 Move about dialog into a separate class
63
64 m_filesAccepted = 0;
65 m_filesRejected = 0;
66 m_filesDenied = 0;
67
36ae27f5 »
2010-11-06 first commit
68 m_inputFiles.sort();
69
70 while(!m_inputFiles.isEmpty())
71 {
72 QString currentFile = QDir::fromNativeSeparators(m_inputFiles.takeFirst());
ce417616 »
2010-11-07 Improve about dialog + nicer method write version info to resource se…
73 qDebug("Analyzing: %s", currentFile.toUtf8().constData());
36ae27f5 »
2010-11-06 first commit
74 emit fileSelected(QFileInfo(currentFile).fileName());
75 AudioFileModel file = analyzeFile(currentFile);
f6259b24 »
2010-11-08 Implemented option to switch GUI style at runtime
76 if(file.fileName().isEmpty() || file.formatContainerType().isEmpty() || file.formatAudioType().isEmpty())
ce417616 »
2010-11-07 Improve about dialog + nicer method write version info to resource se…
77 {
88eae834 »
2010-11-11 Move about dialog into a separate class
78 m_filesRejected++;
ce417616 »
2010-11-07 Improve about dialog + nicer method write version info to resource se…
79 qDebug("Skipped: %s", file.filePath().toUtf8().constData());
80 continue;
81 }
88eae834 »
2010-11-11 Move about dialog into a separate class
82 m_filesAccepted++;
36ae27f5 »
2010-11-06 first commit
83 emit fileAnalyzed(file);
84 }
85
86 qDebug("All files added.\n");
87 m_bSuccess = true;
88 }
89
90 ////////////////////////////////////////////////////////////
91 // Public Functions
92 ////////////////////////////////////////////////////////////
93
94 const AudioFileModel FileAnalyzer::analyzeFile(const QString &filePath)
95 {
96 AudioFileModel audioFile(filePath);
97 m_currentSection = sectionOther;
98
f6259b24 »
2010-11-08 Implemented option to switch GUI style at runtime
99 QFile readTest(filePath);
100 if(!readTest.open(QIODevice::ReadOnly))
101 {
102 qWarning("Cannot access file for reading, skipping!");
88eae834 »
2010-11-11 Move about dialog into a separate class
103 m_filesDenied++;
f6259b24 »
2010-11-08 Implemented option to switch GUI style at runtime
104 return audioFile;
105 }
106 else
107 {
108 readTest.close();
109 }
110
36ae27f5 »
2010-11-06 first commit
111 QProcess process;
112 process.setProcessChannelMode(QProcess::MergedChannels);
113 process.setReadChannel(QProcess::StandardOutput);
ce417616 »
2010-11-07 Improve about dialog + nicer method write version info to resource se…
114 process.start(m_mediaInfoBin, QStringList() << QDir::toNativeSeparators(filePath));
115 process.waitForStarted();
36ae27f5 »
2010-11-06 first commit
116
117 while(process.state() != QProcess::NotRunning)
118 {
f6259b24 »
2010-11-08 Implemented option to switch GUI style at runtime
119 if(!process.waitForReadyRead())
120 {
121 if(process.state() == QProcess::Running)
122 {
123 qWarning("MediaInfo time out. Killing process and skipping file!");
124 process.kill();
125 process.waitForFinished(-1);
126 return audioFile;
127 }
128 }
129
36ae27f5 »
2010-11-06 first commit
130 QByteArray data = process.readLine().constData();
131 while(data.size() > 0)
132 {
133 QString line = QString::fromUtf8(data).simplified();
134 if(!line.isEmpty())
135 {
136 int index = line.indexOf(':');
137 if(index > 0)
138 {
139 QString key = line.left(index-1).trimmed();
140 QString val = line.mid(index+1).trimmed();
141 if(!key.isEmpty() && !val.isEmpty())
142 {
143 updateInfo(audioFile, key, val);
144 }
145 }
146 else
147 {
148 updateSection(line);
149 }
150 }
151 data = process.readLine().constData();
152 }
153 }
154
155 if(audioFile.fileName().isEmpty())
156 {
157 QString baseName = QFileInfo(filePath).fileName();
158 int index = baseName.lastIndexOf(".");
159
160 if(index >= 0)
161 {
162 baseName = baseName.left(index);
163 }
164
165 baseName = baseName.replace("_", " ").simplified();
166 index = baseName.lastIndexOf(" - ");
167
168 if(index >= 0)
169 {
170 baseName = baseName.mid(index + 3).trimmed();
171 }
172
173 audioFile.setFileName(baseName);
174 }
f6259b24 »
2010-11-08 Implemented option to switch GUI style at runtime
175
36ae27f5 »
2010-11-06 first commit
176 return audioFile;
177 }
178
179 void FileAnalyzer::updateSection(const QString &section)
180 {
181 if(section.startsWith("General", Qt::CaseInsensitive))
182 {
183 m_currentSection = sectionGeneral;
184 }
185 else if(!section.compare("Audio", Qt::CaseInsensitive) || section.startsWith("Audio #1", Qt::CaseInsensitive))
186 {
187 m_currentSection = sectionAudio;
188 }
189 else if(section.startsWith("Audio", Qt::CaseInsensitive) || section.startsWith("Video", Qt::CaseInsensitive) || section.startsWith("Text", Qt::CaseInsensitive) ||
190 section.startsWith("Menu", Qt::CaseInsensitive) || section.startsWith("Image", Qt::CaseInsensitive) || section.startsWith("Chapters", Qt::CaseInsensitive))
191 {
192 m_currentSection = sectionOther;
193 }
194 else
195 {
ce417616 »
2010-11-07 Improve about dialog + nicer method write version info to resource se…
196 qWarning("Unknown section: %s", section.toUtf8().constData());
36ae27f5 »
2010-11-06 first commit
197 }
198 }
199
200 void FileAnalyzer::updateInfo(AudioFileModel &audioFile, const QString &key, const QString &value)
201 {
202 switch(m_currentSection)
203 {
204 case sectionGeneral:
205 if(!key.compare("Title", Qt::CaseInsensitive) || !key.compare("Track", Qt::CaseInsensitive) || !key.compare("Track Name", Qt::CaseInsensitive))
206 {
207 if(audioFile.fileName().isEmpty()) audioFile.setFileName(value);
208 }
209 else if(!key.compare("Duration", Qt::CaseInsensitive))
210 {
211 if(!audioFile.fileDuration()) audioFile.setFileDuration(parseDuration(value));
212 }
213 else if(!key.compare("Artist", Qt::CaseInsensitive) || !key.compare("Performer", Qt::CaseInsensitive))
214 {
215 if(audioFile.fileArtist().isEmpty()) audioFile.setFileArtist(value);
216 }
217 else if(!key.compare("Album", Qt::CaseInsensitive))
218 {
219 if(audioFile.fileAlbum().isEmpty()) audioFile.setFileAlbum(value);
220 }
221 else if(!key.compare("Genre", Qt::CaseInsensitive))
222 {
223 if(audioFile.fileGenre().isEmpty()) audioFile.setFileGenre(value);
224 }
225 else if(!key.compare("Year", Qt::CaseInsensitive) || !key.compare("Recorded Date", Qt::CaseInsensitive) || !key.compare("Encoded Date", Qt::CaseInsensitive))
226 {
227 if(!audioFile.fileYear()) audioFile.setFileYear(parseYear(value));
228 }
229 else if(!key.compare("Comment", Qt::CaseInsensitive))
230 {
231 if(audioFile.fileComment().isEmpty()) audioFile.setFileComment(value);
232 }
233 else if(!key.compare("Track Name/Position", Qt::CaseInsensitive))
234 {
235 if(!audioFile.filePosition()) audioFile.setFilePosition(value.toInt());
236 }
237 else if(!key.compare("Format", Qt::CaseInsensitive))
238 {
239 if(audioFile.formatContainerType().isEmpty()) audioFile.setFormatContainerType(value);
240 }
241 else if(!key.compare("Format Profile", Qt::CaseInsensitive))
242 {
243 if(audioFile.formatContainerProfile().isEmpty()) audioFile.setFormatContainerProfile(value);
244 }
245 break;
246
247 case sectionAudio:
248 if(!key.compare("Year", Qt::CaseInsensitive) || !key.compare("Recorded Date", Qt::CaseInsensitive) || !key.compare("Encoded Date", Qt::CaseInsensitive))
249 {
250 if(!audioFile.fileYear()) audioFile.setFileYear(parseYear(value));
251 }
252 else if(!key.compare("Format", Qt::CaseInsensitive))
253 {
254 if(audioFile.formatAudioType().isEmpty()) audioFile.setFormatAudioType(value);
255 }
256 else if(!key.compare("Format Profile", Qt::CaseInsensitive))
257 {
258 if(audioFile.formatAudioProfile().isEmpty()) audioFile.setFormatAudioProfile(value);
259 }
260 else if(!key.compare("Format Version", Qt::CaseInsensitive))
261 {
262 if(audioFile.formatAudioVersion().isEmpty()) audioFile.setFormatAudioVersion(value);
263 }
264 else if(!key.compare("Channel(s)", Qt::CaseInsensitive))
265 {
266 if(!audioFile.formatAudioChannels()) audioFile.setFormatAudioChannels(value.split(" ", QString::SkipEmptyParts).first().toInt());
267 }
268 else if(!key.compare("Sampling rate", Qt::CaseInsensitive))
269 {
270 if(!audioFile.formatAudioSamplerate()) audioFile.setFormatAudioSamplerate(ceil(value.split(" ", QString::SkipEmptyParts).first().toFloat() * 1000.0f));
271 }
272 else if(!key.compare("Bit depth", Qt::CaseInsensitive))
273 {
274 if(!audioFile.formatAudioBitdepth()) audioFile.setFormatAudioBitdepth(value.split(" ", QString::SkipEmptyParts).first().toInt());
275 }
276 else if(!key.compare("Duration", Qt::CaseInsensitive))
277 {
278 if(!audioFile.fileDuration()) audioFile.setFileDuration(parseDuration(value));
279 }
280 break;
281 }
282 }
283
284 unsigned int FileAnalyzer::parseYear(const QString &str)
285 {
286 if(str.startsWith("UTC", Qt::CaseInsensitive))
287 {
288 QDate date = QDate::fromString(str.mid(3).trimmed().left(10), "yyyy-MM-dd");
289 if(date.isValid())
290 {
291 return date.year();
292 }
293 else
294 {
295 return 0;
296 }
297 }
298 else
299 {
300 bool ok = false;
301 int year = str.toInt(&ok);
302 if(ok && year > 0)
303 {
304 return year;
305 }
306 else
307 {
308 return 0;
309 }
310 }
311 }
312
313 unsigned int FileAnalyzer::parseDuration(const QString &str)
314 {
315 QTime time;
316
317 time = QTime::fromString(str, "s's 'z'ms'");
318 if(time.isValid())
319 {
320 return (time.hour() * 60 * 60) + (time.minute() * 60) + time.second();
321 }
322
323 time = QTime::fromString(str, "m'mn 's's'");
324 if(time.isValid())
325 {
326 return (time.hour() * 60 * 60) + (time.minute() * 60) + time.second();
327 }
328
329 time = QTime::fromString(str, "h'h 'm'mn'");
330 if(time.isValid())
331 {
332 return (time.hour() * 60 * 60) + (time.minute() * 60) + time.second();
333 }
334
335 return 0;
336 }
337
88eae834 »
2010-11-11 Move about dialog into a separate class
338 unsigned int FileAnalyzer::filesAccepted(void)
339 {
340 return m_filesAccepted;
341 }
342
343 unsigned int FileAnalyzer::filesRejected(void)
344 {
345 return m_filesRejected - m_filesDenied;
346 }
347
348 unsigned int FileAnalyzer::filesDenied(void)
349 {
350 return m_filesDenied;
351 }
36ae27f5 »
2010-11-06 first commit
352
353 ////////////////////////////////////////////////////////////
354 // EVENTS
355 ////////////////////////////////////////////////////////////
356
f6259b24 »
2010-11-08 Implemented option to switch GUI style at runtime
357 /*NONE*/
Something went wrong with that request. Please try again.