From 9dbb317a5cf5eca4f130636397f41e41b7356c09 Mon Sep 17 00:00:00 2001 From: LoRd_MuldeR Date: Sun, 6 Oct 2013 19:26:08 +0200 Subject: [PATCH] Redesigned FileAnalyzer and Analyzer task. New design is much cleaner, resulting in simpler code and faster file import performance. Also, playlist files are now handled ahead of everything else, which makes sure the progress indicator increases monotonically. Preliminary tests show that file import performance has been more than doubled! For example, the time for importing ~1000 files decreased from 116 seconds to 46 seconds on the development machine, which corresponds to a 2.5x speed-up. --- src/Thread_FileAnalyzer.cpp | 259 +++++++++++++++++++++-------- src/Thread_FileAnalyzer.h | 39 ++++- src/Thread_FileAnalyzer_Task.cpp | 270 ++++--------------------------- src/Thread_FileAnalyzer_Task.h | 50 ++---- 4 files changed, 272 insertions(+), 346 deletions(-) diff --git a/src/Thread_FileAnalyzer.cpp b/src/Thread_FileAnalyzer.cpp index 81b6efd6..a10cbc84 100644 --- a/src/Thread_FileAnalyzer.cpp +++ b/src/Thread_FileAnalyzer.cpp @@ -25,6 +25,7 @@ #include "LockedFile.h" #include "Model_AudioFile.h" #include "Thread_FileAnalyzer_Task.h" +#include "PlaylistImporter.h" #include #include @@ -35,6 +36,8 @@ #include #include #include +#include +#include //////////////////////////////////////////////////////////// // Constructor @@ -42,12 +45,22 @@ FileAnalyzer::FileAnalyzer(const QStringList &inputFiles) : - m_abortFlag(false), + m_tasksCounterNext(0), + m_tasksCounterDone(0), m_inputFiles(inputFiles), - m_templateFile(NULL) + m_templateFile(NULL), + m_pool(NULL) { m_bSuccess = false; m_bAborted = false; + + m_filesAccepted = 0; + m_filesRejected = 0; + m_filesDenied = 0; + m_filesDummyCDDA = 0; + m_filesCueSheet = 0; + + m_timer = new QElapsedTimer; } FileAnalyzer::~FileAnalyzer(void) @@ -59,7 +72,13 @@ FileAnalyzer::~FileAnalyzer(void) if(QFile::exists(templatePath)) QFile::remove(templatePath); } - AnalyzeTask::reset(); + if(!m_pool->waitForDone(2500)) + { + qWarning("There are still running tasks in the thread pool!"); + } + + LAMEXP_DELETE(m_pool); + LAMEXP_DELETE(m_timer); } //////////////////////////////////////////////////////////// @@ -109,18 +128,29 @@ const char *FileAnalyzer::g_tags_aud[] = void FileAnalyzer::run() { - m_abortFlag = false; - - m_bAborted = false; m_bSuccess = false; - int nFiles = m_inputFiles.count(); + m_tasksCounterNext = 0; + m_tasksCounterDone = 0; + m_completedCounter = 0; - emit progressMaxChanged(nFiles); + m_completedFiles.clear(); + m_completedTaskIds.clear(); + m_runningTaskIds.clear(); + + m_filesAccepted = 0; + m_filesRejected = 0; + m_filesDenied = 0; + m_filesDummyCDDA = 0; + m_filesCueSheet = 0; + + m_timer->invalidate(); + + //Update progress + emit progressMaxChanged(m_inputFiles.count()); emit progressValChanged(0); - lamexp_natural_string_sort(m_inputFiles, true); //.sort(); - + //Create MediaInfo template file if(!m_templateFile) { if(!createTemplate()) @@ -130,75 +160,106 @@ void FileAnalyzer::run() } } - AnalyzeTask::reset(); - QThreadPool *pool = new QThreadPool(); - QThread::msleep(333); + //Handle playlist files + lamexp_natural_string_sort(m_inputFiles, true); + handlePlaylistFiles(); + lamexp_natural_string_sort(m_inputFiles, true); - pool->setMaxThreadCount(qBound(2, ((QThread::idealThreadCount() * 3) / 2), 12)); + const unsigned int nFiles = m_inputFiles.count(); - while(!(m_inputFiles.isEmpty() || m_bAborted)) - { - while(!(m_inputFiles.isEmpty() || m_bAborted)) - { - if(!AnalyzeTask::waitForFreeSlot(&m_abortFlag)) - { - qWarning("Timeout in AnalyzeTask::waitForFreeSlot() !!!"); - } + //Update progress + emit progressMaxChanged(nFiles); - if(m_abortFlag) - { - MessageBeep(MB_ICONERROR); - m_bAborted = true; - break; - } - - if(!m_bAborted) - { - const QString currentFile = QDir::fromNativeSeparators(m_inputFiles.takeFirst()); + //Create thread pool + if(!m_pool) m_pool = new QThreadPool(); + m_pool->setMaxThreadCount(qBound(2, ((QThread::idealThreadCount() * 3) / 2), 12)); - AnalyzeTask *task = new AnalyzeTask(currentFile, m_templateFile->filePath(), &m_abortFlag); - connect(task, SIGNAL(fileSelected(QString)), this, SIGNAL(fileSelected(QString)), Qt::DirectConnection); - connect(task, SIGNAL(progressValChanged(unsigned int)), this, SIGNAL(progressValChanged(unsigned int)), Qt::DirectConnection); - connect(task, SIGNAL(progressMaxChanged(unsigned int)), this, SIGNAL(progressMaxChanged(unsigned int)), Qt::DirectConnection); - connect(task, SIGNAL(fileAnalyzed(AudioFileModel)), this, SIGNAL(fileAnalyzed(AudioFileModel)), Qt::DirectConnection); + //Start first N threads + QTimer::singleShot(0, this, SLOT(initializeTasks())); - pool->start(task); + //Start event processing + this->exec(); - if(int count = AnalyzeTask::getAdditionalFiles(m_inputFiles)) - { - emit progressMaxChanged(nFiles += count); - } - } - } - - //One of the Analyze tasks may have gathered additional files from a playlist! - if(!m_bAborted) - { - pool->waitForDone(); - if(int count = AnalyzeTask::getAdditionalFiles(m_inputFiles)) - { - emit progressMaxChanged(nFiles += count); - } - } - } - - pool->waitForDone(); - LAMEXP_DELETE(pool); + //Wait for pending tasks to complete + m_pool->waitForDone(); + //Was opertaion aborted? if(m_bAborted) { qWarning("Operation cancelled by user!"); return; } + //Update progress + emit progressValChanged(nFiles); + + //Emit pending files (this should not be required though!) + if(!m_completedFiles.isEmpty()) + { + qWarning("FileAnalyzer: Pending file information found after last thread terminated!"); + QList keys = m_completedFiles.keys(); qSort(keys); + while(!keys.isEmpty()) + { + emit fileAnalyzed(m_completedFiles.take(keys.takeFirst())); + } + } + qDebug("All files added.\n"); m_bSuccess = true; + + QThread::msleep(333); } //////////////////////////////////////////////////////////// // Privtae Functions //////////////////////////////////////////////////////////// +bool FileAnalyzer::analyzeNextFile(void) +{ + if(!(m_inputFiles.isEmpty() || m_bAborted)) + { + const unsigned int taskId = m_tasksCounterNext++; + const QString currentFile = QDir::fromNativeSeparators(m_inputFiles.takeFirst()); + + if((!m_timer->isValid()) || (m_timer->elapsed() >= 250)) + { + emit fileSelected(QFileInfo(currentFile).fileName()); + m_timer->restart(); + } + + AnalyzeTask *task = new AnalyzeTask(taskId, currentFile, m_templateFile->filePath(), &m_bAborted); + connect(task, SIGNAL(fileAnalyzed(const unsigned int, const int, AudioFileModel)), this, SLOT(taskFileAnalyzed(unsigned int, const int, AudioFileModel)), Qt::QueuedConnection); + connect(task, SIGNAL(taskCompleted(const unsigned int)), this, SLOT(taskThreadFinish(const unsigned int)), Qt::QueuedConnection); + m_runningTaskIds.insert(taskId); m_pool->start(task); + + return true; + } + + return false; +} + +void FileAnalyzer::handlePlaylistFiles(void) +{ + QStringList importedFiles; + while(!m_inputFiles.isEmpty()) + { + const QString currentFile = m_inputFiles.takeFirst(); + if(!PlaylistImporter::importPlaylist(importedFiles, currentFile)) + { + importedFiles << currentFile; + } + } + + while(!importedFiles.isEmpty()) + { + const QString currentFile = importedFiles.takeFirst(); + if(!m_inputFiles.contains(currentFile, Qt::CaseInsensitive)) + { + m_inputFiles << currentFile; + } + } +} + bool FileAnalyzer::createTemplate(void) { if(m_templateFile) @@ -251,33 +312,105 @@ bool FileAnalyzer::createTemplate(void) return true; } +//////////////////////////////////////////////////////////// +// Slot Functions +//////////////////////////////////////////////////////////// + +void FileAnalyzer::initializeTasks(void) +{ + for(int i = 0; i < m_pool->maxThreadCount(); i++) + { + if(!analyzeNextFile()) break; + } +} + +void FileAnalyzer::taskFileAnalyzed(const unsigned int taskId, const int fileType, const AudioFileModel &file) +{ + m_completedTaskIds.insert(taskId); + + switch(fileType) + { + case AnalyzeTask::fileTypeNormal: + m_filesAccepted++; + if(m_tasksCounterDone == taskId) + { + emit fileAnalyzed(file); + m_tasksCounterDone++; + } + else + { + m_completedFiles.insert(taskId, file); + } + break; + case AnalyzeTask::fileTypeCDDA: + m_filesDummyCDDA++; + break; + case AnalyzeTask::fileTypeDenied: + m_filesDenied++; + break; + case AnalyzeTask::fileTypeCueSheet: + m_filesCueSheet++; + break; + case AnalyzeTask::fileTypeUnknown: + m_filesRejected++; + break; + default: + throw "Unknown file type identifier!"; + } + + //Emit all pending files + while(m_completedTaskIds.contains(m_tasksCounterDone)) + { + if(m_completedFiles.contains(m_tasksCounterDone)) + { + emit fileAnalyzed(m_completedFiles.take(m_tasksCounterDone)); + } + m_completedTaskIds.remove(m_tasksCounterDone); + m_tasksCounterDone++; + } +} + +void FileAnalyzer::taskThreadFinish(const unsigned int taskId) +{ + m_runningTaskIds.remove(taskId); + emit progressValChanged(++m_completedCounter); + + if(!analyzeNextFile()) + { + if(m_runningTaskIds.empty()) + { + QTimer::singleShot(0, this, SLOT(quit())); //Stop event processing, if all threads have completed! + } + } +} + //////////////////////////////////////////////////////////// // Public Functions //////////////////////////////////////////////////////////// unsigned int FileAnalyzer::filesAccepted(void) { - return AnalyzeTask::filesAccepted(); + return m_filesAccepted; } unsigned int FileAnalyzer::filesRejected(void) { - return AnalyzeTask::filesRejected(); + return m_filesRejected; } unsigned int FileAnalyzer::filesDenied(void) { - return AnalyzeTask::filesDenied(); + return m_filesDenied; } unsigned int FileAnalyzer::filesDummyCDDA(void) { - return AnalyzeTask::filesDummyCDDA(); + return m_filesDummyCDDA; } unsigned int FileAnalyzer::filesCueSheet(void) { - return AnalyzeTask::filesCueSheet(); + return m_filesCueSheet; } //////////////////////////////////////////////////////////// diff --git a/src/Thread_FileAnalyzer.h b/src/Thread_FileAnalyzer.h index d98c2cf6..ea47c4bd 100644 --- a/src/Thread_FileAnalyzer.h +++ b/src/Thread_FileAnalyzer.h @@ -25,12 +25,16 @@ #include #include +#include +#include class AudioFileModel; class QFile; class QDir; class QFileInfo; class LockedFile; +class QThreadPool; +class QElapsedTimer; //////////////////////////////////////////////////////////// // Splash Thread @@ -44,7 +48,7 @@ public: FileAnalyzer(const QStringList &inputFiles); ~FileAnalyzer(void); void run(); - bool getSuccess(void) { return !isRunning() && m_bSuccess; } + bool getSuccess(void) { return (!isRunning()) && (!m_bAborted) && m_bSuccess; } unsigned int filesAccepted(void); unsigned int filesRejected(void); @@ -59,20 +63,41 @@ signals: void progressMaxChanged(unsigned int); public slots: - void abortProcess(void) { m_abortFlag = true; } + void abortProcess(void) { m_bAborted = true; exit(-1); } + +private slots: + void initializeTasks(void); + void taskFileAnalyzed(const unsigned int taskId, const int fileType, const AudioFileModel &file); + void taskThreadFinish(const unsigned int); private: - const AudioFileModel analyzeFile(const QString &filePath, int *type); + bool analyzeNextFile(void); + void handlePlaylistFiles(void); bool createTemplate(void); + QThreadPool *m_pool; + QElapsedTimer *m_timer; + + unsigned int m_tasksCounterNext; + unsigned int m_tasksCounterDone; + unsigned int m_completedCounter; + + unsigned int m_filesAccepted; + unsigned int m_filesRejected; + unsigned int m_filesDenied; + unsigned int m_filesDummyCDDA; + unsigned int m_filesCueSheet; + QStringList m_inputFiles; LockedFile *m_templateFile; - - volatile bool m_abortFlag; + + QSet m_completedTaskIds; + QSet m_runningTaskIds; + QHash m_completedFiles; static const char *g_tags_gen[]; static const char *g_tags_aud[]; - bool m_bAborted; - bool m_bSuccess; + volatile bool m_bAborted; + volatile bool m_bSuccess; }; diff --git a/src/Thread_FileAnalyzer_Task.cpp b/src/Thread_FileAnalyzer_Task.cpp index 223e3ebe..e874e5e4 100644 --- a/src/Thread_FileAnalyzer_Task.cpp +++ b/src/Thread_FileAnalyzer_Task.cpp @@ -24,7 +24,6 @@ #include "Global.h" #include "LockedFile.h" #include "Model_AudioFile.h" -#include "PlaylistImporter.h" #include #include @@ -45,35 +44,13 @@ #define IS_SEC(SEC) (key.startsWith((SEC "_"), Qt::CaseInsensitive)) #define FIRST_TOK(STR) (STR.split(" ", QString::SkipEmptyParts).first()) -/* static vars */ -QMutex AnalyzeTask::s_waitMutex; -QWaitCondition AnalyzeTask::s_waitCond; -QSet AnalyzeTask::s_threadIdx_running; -unsigned int AnalyzeTask::s_threadIdx_next = 0; -QSemaphore AnalyzeTask::s_semaphore(0); - -/* more static vars */ -QReadWriteLock AnalyzeTask::s_lock; -unsigned int AnalyzeTask::s_filesAccepted = 0; -unsigned int AnalyzeTask::s_filesRejected = 0; -unsigned int AnalyzeTask::s_filesDenied = 0; -unsigned int AnalyzeTask::s_filesDummyCDDA = 0; -unsigned int AnalyzeTask::s_filesCueSheet = 0; -QStringList AnalyzeTask::s_additionalFiles; -QSet AnalyzeTask::s_recentlyAdded; - -/*constants*/ -const int WAITCOND_TIMEOUT = 2500; -const int MAX_RETRIES = 60000 / WAITCOND_TIMEOUT; -const int MAX_QUEUE_SLOTS = 32; - //////////////////////////////////////////////////////////// // Constructor //////////////////////////////////////////////////////////// -AnalyzeTask::AnalyzeTask(const QString &inputFile, const QString &templateFile, volatile bool *abortFlag) +AnalyzeTask::AnalyzeTask(const int taskId, const QString &inputFile, const QString &templateFile, volatile bool *abortFlag) : - m_threadIdx(makeThreadIdx()), + m_taskId(taskId), m_inputFile(inputFile), m_templateFile(templateFile), m_mediaInfoBin(lamexp_lookup_tool("mediainfo.exe")), @@ -88,13 +65,7 @@ AnalyzeTask::AnalyzeTask(const QString &inputFile, const QString &templateFile, AnalyzeTask::~AnalyzeTask(void) { - s_semaphore.release(); - - s_waitMutex.lock(); - s_threadIdx_running.remove(m_threadIdx); - s_waitMutex.unlock(); - - s_waitCond.wakeAll(); + emit taskCompleted(m_taskId); } //////////////////////////////////////////////////////////// @@ -111,12 +82,6 @@ void AnalyzeTask::run() { qWarning("WARNING: Caught an in exception AnalyzeTask thread!"); } - - s_waitMutex.lock(); - s_threadIdx_running.remove(m_threadIdx); - s_waitMutex.unlock(); - - s_waitCond.wakeAll(); } void AnalyzeTask::run_ex(void) @@ -125,9 +90,6 @@ void AnalyzeTask::run_ex(void) QString currentFile = QDir::fromNativeSeparators(m_inputFile); qDebug("Analyzing: %s", currentFile.toUtf8().constData()); - emit fileSelected(QFileInfo(currentFile).fileName()); - emit progressValChanged(m_threadIdx + 1); - AudioFileModel file = analyzeFile(currentFile, &fileType); if(*m_abortFlag) @@ -135,79 +97,46 @@ void AnalyzeTask::run_ex(void) qWarning("Operation cancelled by user!"); return; } - if(fileType == fileTypeSkip) - { - qWarning("File was recently added, skipping!"); - return; - } - if(fileType == fileTypeDenied) - { - QWriteLocker lock(&s_lock); - s_filesDenied++; - lock.unlock(); - qWarning("Cannot access file for reading, skipping!"); - return; - } - if(fileType == fileTypeCDDA) - { - QWriteLocker lock(&s_lock); - s_filesDummyCDDA++; - lock.unlock(); - qWarning("Dummy CDDA file detected, skipping!"); - return; - } - //Handle files with *incomplete* meida info - if(file.fileName().isEmpty() || file.formatContainerType().isEmpty() || file.formatAudioType().isEmpty()) + switch(fileType) { - QStringList fileList; - if(PlaylistImporter::importPlaylist(fileList, currentFile)) + case fileTypeDenied: + qWarning("Cannot access file for reading, skipping!"); + break; + case fileTypeCDDA: + qWarning("Dummy CDDA file detected, skipping!"); + break; + default: + if(file.fileName().isEmpty() || file.formatContainerType().isEmpty() || file.formatAudioType().isEmpty()) { - qDebug("Imported playlist file."); - QWriteLocker lock(&s_lock); - s_additionalFiles << fileList; - } - else if(!QFileInfo(currentFile).suffix().compare("cue", Qt::CaseInsensitive)) - { - QWriteLocker lock(&s_lock); - qWarning("Cue Sheet file detected, skipping!"); - s_filesCueSheet++; - } - else if(!QFileInfo(currentFile).suffix().compare("avs", Qt::CaseInsensitive)) - { - qDebug("Found a potential Avisynth script, investigating..."); - if(analyzeAvisynthFile(currentFile, file)) + fileType = fileTypeUnknown; + if(!QFileInfo(currentFile).suffix().compare("cue", Qt::CaseInsensitive)) { - QWriteLocker lock(&s_lock); - s_filesAccepted++; - s_recentlyAdded.insert(file.filePath().toLower()); - lock.unlock(); - waitForPreviousThreads(); - emit fileAnalyzed(file); + qWarning("Cue Sheet file detected, skipping!"); + fileType = fileTypeCueSheet; + } + else if(!QFileInfo(currentFile).suffix().compare("avs", Qt::CaseInsensitive)) + { + qDebug("Found a potential Avisynth script, investigating..."); + if(analyzeAvisynthFile(currentFile, file)) + { + fileType = fileTypeNormal; + } + else + { + qDebug("Rejected Avisynth file: %s", file.filePath().toUtf8().constData()); + } } else { - QWriteLocker lock(&s_lock); - qDebug("Rejected Avisynth file: %s", file.filePath().toUtf8().constData()); - s_filesRejected++; + qDebug("Rejected file of unknown type: %s", file.filePath().toUtf8().constData()); } } - else - { - QWriteLocker lock(&s_lock); - qDebug("Rejected file of unknown type: %s", file.filePath().toUtf8().constData()); - s_filesRejected++; - } - return; + break; } //Emit the file now! - QWriteLocker lock(&s_lock); - s_filesAccepted++; - s_recentlyAdded.insert(file.filePath().toLower()); - lock.unlock(); - waitForPreviousThreads(); - emit fileAnalyzed(file); + emit fileAnalyzed(m_taskId, fileType, file); } //////////////////////////////////////////////////////////// @@ -219,14 +148,6 @@ const AudioFileModel AnalyzeTask::analyzeFile(const QString &filePath, int *type *type = fileTypeNormal; AudioFileModel audioFile(filePath); - QReadLocker readLock(&s_lock); - if(s_recentlyAdded.contains(filePath.toLower())) - { - *type = fileTypeSkip; - return audioFile; - } - readLock.unlock(); - QFile readTest(filePath); if(!readTest.open(QIODevice::ReadOnly)) { @@ -733,139 +654,12 @@ unsigned int AnalyzeTask::parseDuration(const QString &str) return ok ? (value/1000) : 0; } -unsigned __int64 AnalyzeTask::makeThreadIdx(void) -{ - s_waitMutex.lock(); - unsigned int idx = s_threadIdx_next++; - s_threadIdx_running.insert(idx); - s_waitMutex.unlock(); - - return idx; -} - -void AnalyzeTask::waitForPreviousThreads(void) -{ - //This function will block until all threads with a *lower* index have terminated. - //Required to make sure that the files will be added in the "correct" order! - - s_waitMutex.lock(); - int retryCount = 0; - - forever - { - bool bWaitFlag = false; - QSet::const_iterator i; - - for(i = s_threadIdx_running.begin(); i != s_threadIdx_running.end(); ++i) - { - if(*i < m_threadIdx) { bWaitFlag = true; break; } - } - - if((!bWaitFlag) || *m_abortFlag) - { - s_waitMutex.unlock(); - return; - } - - if(!s_waitCond.wait(&s_waitMutex, WAITCOND_TIMEOUT)) - { - if(++retryCount > MAX_RETRIES) - { - qWarning("AnalyzeTask::waitForPreviousThreads encountered timeout !!!"); - s_threadIdx_running.clear(); - } - } - } -} //////////////////////////////////////////////////////////// // Public Functions //////////////////////////////////////////////////////////// -unsigned int AnalyzeTask::filesAccepted(void) -{ - QReadLocker lock(&s_lock); - return s_filesAccepted; -} - -unsigned int AnalyzeTask::filesRejected(void) -{ - QReadLocker lock(&s_lock); - return s_filesRejected; -} - -unsigned int AnalyzeTask::filesDenied(void) -{ - QReadLocker lock(&s_lock); - return s_filesDenied; -} - -unsigned int AnalyzeTask::filesDummyCDDA(void) -{ - QReadLocker lock(&s_lock); - return s_filesDummyCDDA; -} - -unsigned int AnalyzeTask::filesCueSheet(void) -{ - QReadLocker lock(&s_lock); - return s_filesCueSheet; -} - -int AnalyzeTask::getAdditionalFiles(QStringList &fileList) -{ - QReadLocker readLock(&s_lock); - int count = s_additionalFiles.count(); - readLock.unlock(); - - if(count > 0) - { - QWriteLocker lock(&s_lock); - count = s_additionalFiles.count(); - fileList << s_additionalFiles; - s_additionalFiles.clear(); - return count; - } - - return 0; -} - -bool AnalyzeTask::waitForFreeSlot(volatile bool *abortFlag) -{ - bool ret = false; - - for(int i = 0; i < MAX_RETRIES; i++) - { - ret = s_semaphore.tryAcquire(1, WAITCOND_TIMEOUT); - if(ret || (*abortFlag)) break; - } - - return ret; -} - -void AnalyzeTask::reset(void) -{ - QWriteLocker lock(&s_lock); - s_filesAccepted = 0; - s_filesRejected = 0; - s_filesDenied = 0; - s_filesDummyCDDA = 0; - s_filesCueSheet = 0; - s_additionalFiles.clear(); - s_recentlyAdded.clear(); - lock.unlock(); - - s_waitMutex.lock(); - s_threadIdx_next = 0; - s_threadIdx_running.clear(); - s_waitMutex.unlock(); - - int freeSlots = s_semaphore.available(); - if(freeSlots < MAX_QUEUE_SLOTS) - { - s_semaphore.release(MAX_QUEUE_SLOTS - freeSlots); - } -} +/*NONE*/ //////////////////////////////////////////////////////////// // EVENTS diff --git a/src/Thread_FileAnalyzer_Task.h b/src/Thread_FileAnalyzer_Task.h index 1fb9e4ea..bb606fa0 100644 --- a/src/Thread_FileAnalyzer_Task.h +++ b/src/Thread_FileAnalyzer_Task.h @@ -43,25 +43,24 @@ class AnalyzeTask: public QObject, public QRunnable Q_OBJECT public: - AnalyzeTask(const QString &inputFile, const QString &templateFile, volatile bool *abortFlag); + AnalyzeTask(const int taskId, const QString &inputFile, const QString &templateFile, volatile bool *abortFlag); ~AnalyzeTask(void); - static void reset(void); - static int getAdditionalFiles(QStringList &fileList); - static unsigned int filesAccepted(void); - static unsigned int filesRejected(void); - static unsigned int filesDenied(void); - static unsigned int filesDummyCDDA(void); - static unsigned int filesCueSheet(void); + enum fileType_t + { + fileTypeNormal = 0, + fileTypeCDDA = 1, + fileTypeDenied = 2, + fileTypeCueSheet = 3, + fileTypeUnknown = 4 + }; //Wait until there is a free slot in the queue static bool waitForFreeSlot(volatile bool *abortFlag); signals: - void fileSelected(const QString &fileName); - void fileAnalyzed(const AudioFileModel &file); - void progressValChanged(unsigned int); - void progressMaxChanged(unsigned int); + void fileAnalyzed(const unsigned int taskId, const int fileType, const AudioFileModel &file); + void taskCompleted(const unsigned int taskId); protected: void run(void); @@ -75,13 +74,6 @@ private: coverPng, coverGif }; - enum fileType_t - { - fileTypeNormal = 0, - fileTypeCDDA = 1, - fileTypeDenied = 2, - fileTypeSkip = 3 - }; const AudioFileModel analyzeFile(const QString &filePath, int *type); void updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned int *id_val, cover_t *coverType, QByteArray *coverData, const QString &key, const QString &value); @@ -92,7 +84,7 @@ private: bool analyzeAvisynthFile(const QString &filePath, AudioFileModel &info); void waitForPreviousThreads(void); - const unsigned __int64 m_threadIdx; + const unsigned int m_taskId; const QString m_mediaInfoBin; const QString m_avs2wavBin; @@ -100,22 +92,4 @@ private: const QString m_inputFile; volatile bool *m_abortFlag; - - static QMutex s_waitMutex; - static QWaitCondition s_waitCond; - static QSet s_threadIdx_running; - static unsigned int s_threadIdx_next; - - static QSemaphore s_semaphore; - - static QReadWriteLock s_lock; - static unsigned int s_filesAccepted; - static unsigned int s_filesRejected; - static unsigned int s_filesDenied; - static unsigned int s_filesDummyCDDA; - static unsigned int s_filesCueSheet; - static QSet s_recentlyAdded; - static QStringList s_additionalFiles; - - static unsigned __int64 makeThreadIdx(void); };