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.

This commit is contained in:
LoRd_MuldeR 2013-10-06 19:26:08 +02:00
parent a8cdb050fb
commit 9dbb317a5c
4 changed files with 272 additions and 346 deletions

View File

@ -25,6 +25,7 @@
#include "LockedFile.h"
#include "Model_AudioFile.h"
#include "Thread_FileAnalyzer_Task.h"
#include "PlaylistImporter.h"
#include <QDir>
#include <QFileInfo>
@ -35,6 +36,8 @@
#include <QImage>
#include <QThreadPool>
#include <QTime>
#include <QElapsedTimer>
#include <QTimer>
////////////////////////////////////////////////////////////
// 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<unsigned int> 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;
}
////////////////////////////////////////////////////////////

View File

@ -25,12 +25,16 @@
#include <QThread>
#include <QStringList>
#include <QHash>
#include <QSet>
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<unsigned int> m_completedTaskIds;
QSet<unsigned int> m_runningTaskIds;
QHash<unsigned int, AudioFileModel> 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;
};

View File

@ -24,7 +24,6 @@
#include "Global.h"
#include "LockedFile.h"
#include "Model_AudioFile.h"
#include "PlaylistImporter.h"
#include <QDir>
#include <QFileInfo>
@ -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<unsigned int> 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<QString> 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<unsigned int>::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

View File

@ -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<unsigned int> 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<QString> s_recentlyAdded;
static QStringList s_additionalFiles;
static unsigned __int64 makeThreadIdx(void);
};