OSDN Git Service

Some code refactoring regarding the QWaitCondition/QMutex in FileAnalyzer_Task.
[lamexp/LameXP.git] / src / Thread_FileAnalyzer.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2012 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 #include "Thread_FileAnalyzer_Task.h"
28
29 #include <QDir>
30 #include <QFileInfo>
31 #include <QProcess>
32 #include <QDate>
33 #include <QTime>
34 #include <QDebug>
35 #include <QImage>
36 #include <QThreadPool>
37 #include <QTime>
38
39 ////////////////////////////////////////////////////////////
40 // Constructor
41 ////////////////////////////////////////////////////////////
42
43 FileAnalyzer::FileAnalyzer(const QStringList &inputFiles)
44 :
45         m_abortFlag(false),
46         m_inputFiles(inputFiles),
47         m_templateFile(NULL)
48 {
49         m_bSuccess = false;
50         m_bAborted = false;
51 }
52
53 FileAnalyzer::~FileAnalyzer(void)
54 {
55         if(m_templateFile)
56         {
57                 QString templatePath = m_templateFile->filePath();
58                 LAMEXP_DELETE(m_templateFile);
59                 if(QFile::exists(templatePath)) QFile::remove(templatePath);
60         }
61         
62         AnalyzeTask::reset();
63 }
64
65 ////////////////////////////////////////////////////////////
66 // Static data
67 ////////////////////////////////////////////////////////////
68
69 const char *FileAnalyzer::g_tags_gen[] =
70 {
71         "ID",
72         "Format",
73         "Format_Profile",
74         "Format_Version",
75         "Duration",
76         "Title", "Track",
77         "Track/Position",
78         "Artist", "Performer",
79         "Album",
80         "Genre",
81         "Released_Date", "Recorded_Date",
82         "Comment",
83         "Cover",
84         "Cover_Type",
85         "Cover_Mime",
86         "Cover_Data",
87         NULL
88 };
89
90 const char *FileAnalyzer::g_tags_aud[] =
91 {
92         "ID",
93         "Source",
94         "Format",
95         "Format_Profile",
96         "Format_Version",
97         "Channel(s)",
98         "SamplingRate",
99         "BitDepth",
100         "BitRate",
101         "BitRate_Mode",
102         NULL
103 };
104
105 ////////////////////////////////////////////////////////////
106 // Thread Main
107 ////////////////////////////////////////////////////////////
108
109 void FileAnalyzer::run()
110 {
111         m_abortFlag = false;
112
113         m_bAborted = false;
114         m_bSuccess = false;
115
116         int nFiles = m_inputFiles.count();
117
118         emit progressMaxChanged(nFiles);
119         emit progressValChanged(0);
120
121         m_inputFiles.sort();
122
123         if(!m_templateFile)
124         {
125                 if(!createTemplate())
126                 {
127                         qWarning("Failed to create template file!");
128                         return;
129                 }
130         }
131
132         AnalyzeTask::reset();
133         QThreadPool *pool = new QThreadPool();
134         QThread::msleep(333);
135
136         if(QThread::idealThreadCount() > 1)
137         {
138                 pool->setMaxThreadCount((QThread::idealThreadCount() * 3) / 2);
139         }
140         else
141         {
142                 pool->setMaxThreadCount(2);
143         }
144
145         while(!(m_inputFiles.isEmpty() || m_bAborted))
146         {
147                 while(!(m_inputFiles.isEmpty() || m_bAborted))
148                 {
149                         const QString currentFile = QDir::fromNativeSeparators(m_inputFiles.takeFirst());
150
151                         AnalyzeTask *task = new AnalyzeTask(currentFile, m_templateFile->filePath(), &m_abortFlag);
152                         connect(task, SIGNAL(fileSelected(QString)), this, SIGNAL(fileSelected(QString)), Qt::DirectConnection);
153                         connect(task, SIGNAL(progressValChanged(unsigned int)), this, SIGNAL(progressValChanged(unsigned int)), Qt::DirectConnection);
154                         connect(task, SIGNAL(progressMaxChanged(unsigned int)), this, SIGNAL(progressMaxChanged(unsigned int)), Qt::DirectConnection);
155                         connect(task, SIGNAL(fileAnalyzed(AudioFileModel)), this, SIGNAL(fileAnalyzed(AudioFileModel)), Qt::DirectConnection);
156
157                         while(!pool->tryStart(task))
158                         {
159                                 if(!AnalyzeTask::waitForOneThread(1250))
160                                 {
161                                         qWarning("FileAnalyzer: Timeout, retrying!");
162                                 }
163                                 
164                                 if(m_abortFlag)
165                                 {
166                                         LAMEXP_DELETE(task);
167                                         break;
168                                 }
169
170                                 QThread::yieldCurrentThread();
171                         }
172
173                         if(m_abortFlag)
174                         {
175                                 MessageBeep(MB_ICONERROR);
176                                 m_bAborted = true;
177                         }
178                         else
179                         {
180                                 if(int count = AnalyzeTask::getAdditionalFiles(m_inputFiles))
181                                 {
182                                         emit progressMaxChanged(nFiles += count);
183                                 }
184                                 QThread::msleep(8);
185                         }
186                 }
187
188                 //One of the Analyze tasks may have gathered additional files from a playlist!
189                 if(!m_bAborted)
190                 {
191                         pool->waitForDone();
192                         if(int count = AnalyzeTask::getAdditionalFiles(m_inputFiles))
193                         {
194                                 emit progressMaxChanged(nFiles += count);
195                         }
196                 }
197         }
198         
199         pool->waitForDone();
200         LAMEXP_DELETE(pool);
201
202         if(m_bAborted)
203         {
204                 qWarning("Operation cancelled by user!");
205                 return;
206         }
207         
208         qDebug("All files added.\n");
209         m_bSuccess = true;
210 }
211
212 ////////////////////////////////////////////////////////////
213 // Privtae Functions
214 ////////////////////////////////////////////////////////////
215
216 bool FileAnalyzer::createTemplate(void)
217 {
218         if(m_templateFile)
219         {
220                 qWarning("Template file already exists!");
221                 return true;
222         }
223         
224         QString templatePath = QString("%1/%2.txt").arg(lamexp_temp_folder2(), lamexp_rand_str());
225
226         QFile templateFile(templatePath);
227         if(!templateFile.open(QIODevice::WriteOnly))
228         {
229                 return false;
230         }
231
232         templateFile.write("General;");
233         for(size_t i = 0; g_tags_gen[i]; i++)
234         {
235                 templateFile.write(QString("Gen_%1=%%1%\\n").arg(g_tags_gen[i]).toLatin1().constData());
236         }
237         templateFile.write("\\n\r\n");
238
239         templateFile.write("Audio;");
240         for(size_t i = 0; g_tags_aud[i]; i++)
241         {
242                 templateFile.write(QString("Aud_%1=%%1%\\n").arg(g_tags_aud[i]).toLatin1().constData());
243         }
244         templateFile.write("\\n\r\n");
245
246         bool success = (templateFile.error() == QFile::NoError);
247         templateFile.close();
248         
249         if(!success)
250         {
251                 QFile::remove(templatePath);
252                 return false;
253         }
254
255         try
256         {
257                 m_templateFile = new LockedFile(templatePath);
258         }
259         catch(...)
260         {
261                 qWarning("Failed to lock template file!");
262                 return false;
263         }
264
265         return true;
266 }
267
268 ////////////////////////////////////////////////////////////
269 // Public Functions
270 ////////////////////////////////////////////////////////////
271
272 unsigned int FileAnalyzer::filesAccepted(void)
273 {
274         return AnalyzeTask::filesAccepted();
275 }
276
277 unsigned int FileAnalyzer::filesRejected(void)
278 {
279         return AnalyzeTask::filesRejected();
280 }
281
282 unsigned int FileAnalyzer::filesDenied(void)
283 {
284         return AnalyzeTask::filesDenied();
285 }
286
287 unsigned int FileAnalyzer::filesDummyCDDA(void)
288 {
289         return AnalyzeTask::filesDummyCDDA();
290 }
291
292 unsigned int FileAnalyzer::filesCueSheet(void)
293 {
294         return AnalyzeTask::filesCueSheet();
295 }
296
297 ////////////////////////////////////////////////////////////
298 // EVENTS
299 ////////////////////////////////////////////////////////////
300
301 /*NONE*/