Changed the method to synchronize the analyzer threads: We now use QSet to maintain a list of the thread id's of all threads that are still running - instead of only recording the highest thread id that has finished. This way a thread can now actually check if there still is any running thread with a lower thread id. Before thread n could only check if thread n-1 has finished yet or not. As a result we can relax the waiting now. Only threads that want to emit a file will wait for the "previous" threads to finish.

This commit is contained in:
LoRd_MuldeR 2012-05-14 00:50:16 +02:00
parent 5f91fc8749
commit c18785ce1e
13 changed files with 1702 additions and 700 deletions

View File

@ -448,6 +448,7 @@ del "$(TargetDir)imageformats\q???d4.dll"
<ClCompile Include="src\Thread_CueSplitter.cpp" />
<ClCompile Include="src\Thread_DiskObserver.cpp" />
<ClCompile Include="src\Thread_FileAnalyzer.cpp" />
<ClCompile Include="src\Thread_FileAnalyzer_ST.cpp" />
<ClCompile Include="src\Thread_FileAnalyzer_Task.cpp" />
<ClCompile Include="src\Thread_Initialization.cpp" />
<ClCompile Include="src\Thread_MessageHandler.cpp" />
@ -490,6 +491,7 @@ del "$(TargetDir)imageformats\q???d4.dll"
<ClCompile Include="tmp\MOC_Thread_CueSplitter.cpp" />
<ClCompile Include="tmp\MOC_Thread_DiskObserver.cpp" />
<ClCompile Include="tmp\MOC_Thread_FileAnalyzer.cpp" />
<ClCompile Include="tmp\MOC_Thread_FileAnalyzer_ST.cpp" />
<ClCompile Include="tmp\MOC_Thread_FileAnalyzer_Task.cpp" />
<ClCompile Include="tmp\MOC_Thread_Initialization.cpp" />
<ClCompile Include="tmp\MOC_Thread_MessageHandler.cpp" />
@ -681,6 +683,23 @@ del "$(TargetDir)imageformats\q???d4.dll"
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild>
<CustomBuild Include="src\Thread_FileAnalyzer_ST.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug_Qt5|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release_Static_Qt5|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug_Qt5|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Release_Static_Qt5|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug_Qt5|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static_Qt5|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild>
<ClInclude Include="src\Tools.h" />
<CustomBuild Include="src\Tool_WaveProperties.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
@ -1234,41 +1253,35 @@ del "$(TargetDir)imageformats\q???d4.dll"
<CustomBuild Include="src\Thread_Initialization.h">
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug_Qt5|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"
</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug_Qt5|Win32'">"$(QTDIR5)\qtbase\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug_Qt5|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug_Qt5|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Release_Static_Qt5|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"
</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release_Static_Qt5|Win32'">"$(QTDIR5)\qtbase\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release_Static_Qt5|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static_Qt5|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"
</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild>
<CustomBuild Include="src\Thread_MessageHandler.h">
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug_Qt5|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"
</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug_Qt5|Win32'">"$(QTDIR5)\qtbase\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug_Qt5|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug_Qt5|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Release_Static_Qt5|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"
</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release_Static_Qt5|Win32'">"$(QTDIR5)\qtbase\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release_Static_Qt5|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static_Qt5|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MOC "$(SolutionDir)tmp\MOC_%(Filename).cpp"</Message>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"
</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\MOC_%(Filename).cpp" "%(FullPath)"</Command>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\MOC_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild>
<CustomBuild Include="src\Thread_MessageProducer.h">

View File

@ -358,6 +358,12 @@
<ClCompile Include="tmp\MOC_Thread_FileAnalyzer_Task.cpp">
<Filter>Generated Files\MOC</Filter>
</ClCompile>
<ClCompile Include="src\Thread_FileAnalyzer_ST.cpp">
<Filter>Source Files\Threads</Filter>
</ClCompile>
<ClCompile Include="tmp\MOC_Thread_FileAnalyzer_ST.cpp">
<Filter>Generated Files\MOC</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Config.h">
@ -662,6 +668,9 @@
<CustomBuild Include="src\Thread_FileAnalyzer_Task.h">
<Filter>Header Files\Threads</Filter>
</CustomBuild>
<CustomBuild Include="src\Thread_FileAnalyzer_ST.h">
<Filter>Header Files\Threads</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<None Include="res\MainIcon.ico" />

View File

@ -20,7 +20,7 @@ a:visited { color: #0000EE; }
<li>Added Swedish translation, thanks to Åke Engelbrektson &lt;eson57@gmail.com&gt;
<li>Updated mpg123 decoder to v1.14.2 (2012-05-12), compiled with GCC 4.6.1
<li>Updated MediaInfo to v0.7.57 (2012-05-02), compiled with ICL 12.1.7 and MSVC 10.0
<li>Implemented multi-threading in file analyzer for faster file import
<li>Implemented multi-threading in file analyzer for faster file import (about 2.5x to 6.0x faster!)
<li>Implemented multi-threading in initialization code for faster application startup
<li>Fixed a potential crash (stack overflow) when adding a huge number of files
</ul><br>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@
#define VER_LAMEXP_MINOR_LO 5
#define VER_LAMEXP_TYPE Alpha
#define VER_LAMEXP_PATCH 2
#define VER_LAMEXP_BUILD 1023
#define VER_LAMEXP_BUILD 1026
///////////////////////////////////////////////////////////////////////////////
// Tool versions (minimum expected versions!)

View File

@ -31,6 +31,7 @@
#include "Dialog_DropBox.h"
#include "Dialog_CueImport.h"
#include "Thread_FileAnalyzer.h"
#include "Thread_FileAnalyzer_ST.h"
#include "Thread_MessageHandler.h"
#include "Model_MetaInfo.h"
#include "Model_Settings.h"
@ -515,6 +516,10 @@ void MainWindow::addFiles(const QStringList &files)
tabWidget->setCurrentIndex(0);
int timeMT = 0, timeST = 0;
//--MT--
FileAnalyzer *analyzer = new FileAnalyzer(files);
connect(analyzer, SIGNAL(fileSelected(QString)), m_banner, SLOT(setText(QString)), Qt::QueuedConnection);
connect(analyzer, SIGNAL(progressValChanged(unsigned int)), m_banner, SLOT(setProgressVal(unsigned int)), Qt::QueuedConnection);
@ -525,13 +530,44 @@ void MainWindow::addFiles(const QStringList &files)
try
{
m_fileListModel->setBlockUpdates(true);
QTime startTime = QTime::currentTime();
m_banner->show(tr("Adding file(s), please wait..."), analyzer);
timeMT = startTime.secsTo(QTime::currentTime());
}
catch(...)
{
/* ignore any exceptions that may occur */
}
//--ST--
FileAnalyzer_ST *analyzerST = new FileAnalyzer_ST(files);
connect(analyzerST, SIGNAL(fileSelected(QString)), m_banner, SLOT(setText(QString)), Qt::QueuedConnection);
connect(analyzerST, SIGNAL(progressValChanged(unsigned int)), m_banner, SLOT(setProgressVal(unsigned int)), Qt::QueuedConnection);
connect(analyzerST, SIGNAL(progressMaxChanged(unsigned int)), m_banner, SLOT(setProgressMax(unsigned int)), Qt::QueuedConnection);
connect(analyzerST, SIGNAL(fileAnalyzed(AudioFileModel)), m_fileListModel, SLOT(addFile(AudioFileModel)), Qt::QueuedConnection);
connect(m_banner, SIGNAL(userAbort()), analyzerST, SLOT(abortProcess()), Qt::DirectConnection);
try
{
m_fileListModel->setBlockUpdates(true);
QTime startTime = QTime::currentTime();
m_banner->show(tr("Adding file(s), please wait..."), analyzerST);
timeST = startTime.secsTo(QTime::currentTime());
}
catch(...)
{
/* ignore any exceptions that may occur */
}
//------
double speedUp = static_cast<double>(timeST) / static_cast<double>(timeMT);
QMessageBox::information(this, "Speed Up", QString().sprintf("Announcement: The new multi-threaded file analyzer is %.1fx faster !!!", speedUp), QMessageBox::Ok);
qWarning("ST: %d, MT: %d", timeST, timeMT);
//------
m_fileListModel->setBlockUpdates(false);
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
sourceFileView->update();
@ -557,6 +593,7 @@ void MainWindow::addFiles(const QStringList &files)
}
LAMEXP_DELETE(analyzer);
LAMEXP_DELETE(analyzerST);
m_banner->close();
}

View File

@ -100,6 +100,8 @@ WorkingBanner::~WorkingBanner(void)
void WorkingBanner::show(const QString &text)
{
m_canClose = false;
m_progressInt = -1;
QDialog::show();
setFixedSize(size());
setText(text);

View File

@ -0,0 +1,825 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// http://www.gnu.org/licenses/gpl-2.0.txt
///////////////////////////////////////////////////////////////////////////////
// --------------------------------------------------------------------
// !!! THIS IS THE OLD SINGLE-THREADED VERSION OF THE FILE ANALYZER !!!
// --------------------------------------------------------------------
#include "Thread_FileAnalyzer_ST.h"
#include "Global.h"
#include "LockedFile.h"
#include "Model_AudioFile.h"
#include "PlaylistImporter.h"
#include <QDir>
#include <QFileInfo>
#include <QProcess>
#include <QDate>
#include <QTime>
#include <QDebug>
#include <QImage>
#include <math.h>
#define IS_KEY(KEY) (key.compare(KEY, Qt::CaseInsensitive) == 0)
#define IS_SEC(SEC) (key.startsWith((SEC "_"), Qt::CaseInsensitive))
#define FIRST_TOK(STR) (STR.split(" ", QString::SkipEmptyParts).first())
////////////////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////////////////
FileAnalyzer_ST::FileAnalyzer_ST(const QStringList &inputFiles)
:
m_inputFiles(inputFiles),
m_mediaInfoBin(lamexp_lookup_tool("mediainfo.exe")),
m_avs2wavBin(lamexp_lookup_tool("avs2wav.exe")),
m_templateFile(NULL),
m_abortFlag(false)
{
m_bSuccess = false;
m_bAborted = false;
if(m_mediaInfoBin.isEmpty())
{
qFatal("Invalid path to MediaInfo binary. Tool not initialized properly.");
}
m_filesAccepted = 0;
m_filesRejected = 0;
m_filesDenied = 0;
m_filesDummyCDDA = 0;
m_filesCueSheet = 0;
}
FileAnalyzer_ST::~FileAnalyzer_ST(void)
{
if(m_templateFile)
{
QString templatePath = m_templateFile->filePath();
LAMEXP_DELETE(m_templateFile);
if(QFile::exists(templatePath)) QFile::remove(templatePath);
}
}
////////////////////////////////////////////////////////////
// Static data
////////////////////////////////////////////////////////////
const char *FileAnalyzer_ST::g_tags_gen[] =
{
"ID",
"Format",
"Format_Profile",
"Format_Version",
"Duration",
"Title", "Track",
"Track/Position",
"Artist", "Performer",
"Album",
"Genre",
"Released_Date", "Recorded_Date",
"Comment",
"Cover",
"Cover_Type",
"Cover_Mime",
"Cover_Data",
NULL
};
const char *FileAnalyzer_ST::g_tags_aud[] =
{
"ID",
"Source",
"Format",
"Format_Profile",
"Format_Version",
"Channel(s)",
"SamplingRate",
"BitDepth",
"BitRate",
"BitRate_Mode",
NULL
};
////////////////////////////////////////////////////////////
// Thread Main
////////////////////////////////////////////////////////////
void FileAnalyzer_ST::run()
{
m_bSuccess = false;
m_bAborted = false;
m_filesAccepted = 0;
m_filesRejected = 0;
m_filesDenied = 0;
m_filesDummyCDDA = 0;
m_filesCueSheet = 0;
m_inputFiles.sort();
m_recentlyAdded.clear();
m_abortFlag = false;
if(!m_templateFile)
{
if(!createTemplate())
{
qWarning("Failed to create template file!");
return;
}
}
while(!m_inputFiles.isEmpty())
{
int fileType = fileTypeNormal;
QString currentFile = QDir::fromNativeSeparators(m_inputFiles.takeFirst());
qDebug("Analyzing: %s", currentFile.toUtf8().constData());
emit fileSelected(QFileInfo(currentFile).fileName());
AudioFileModel file = analyzeFile(currentFile, &fileType);
if(m_abortFlag)
{
MessageBeep(MB_ICONERROR);
m_bAborted = true;
qWarning("Operation cancelled by user!");
return;
}
if(fileType == fileTypeSkip)
{
qWarning("File was recently added, skipping!");
continue;
}
if(fileType == fileTypeDenied)
{
m_filesDenied++;
qWarning("Cannot access file for reading, skipping!");
continue;
}
if(fileType == fileTypeCDDA)
{
m_filesDummyCDDA++;
qWarning("Dummy CDDA file detected, skipping!");
continue;
}
if(file.fileName().isEmpty() || file.formatContainerType().isEmpty() || file.formatAudioType().isEmpty())
{
if(PlaylistImporter::importPlaylist(m_inputFiles, currentFile))
{
qDebug("Imported playlist file.");
}
else if(!QFileInfo(currentFile).suffix().compare("cue", Qt::CaseInsensitive))
{
qWarning("Cue Sheet file detected, skipping!");
m_filesCueSheet++;
}
else if(!QFileInfo(currentFile).suffix().compare("avs", Qt::CaseInsensitive))
{
qDebug("Found a potential Avisynth script, investigating...");
if(analyzeAvisynthFile(currentFile, file))
{
m_filesAccepted++;
emit fileAnalyzed(file);
}
else
{
qDebug("Rejected Avisynth file: %s", file.filePath().toUtf8().constData());
m_filesRejected++;
}
}
else
{
qDebug("Rejected file of unknown type: %s", file.filePath().toUtf8().constData());
m_filesRejected++;
}
continue;
}
m_filesAccepted++;
m_recentlyAdded.append(file.filePath());
emit fileAnalyzed(file);
}
qDebug("All files added.\n");
m_bSuccess = true;
}
////////////////////////////////////////////////////////////
// Privtae Functions
////////////////////////////////////////////////////////////
const AudioFileModel FileAnalyzer_ST::analyzeFile(const QString &filePath, int *type)
{
*type = fileTypeNormal;
AudioFileModel audioFile(filePath);
if(m_recentlyAdded.contains(filePath, Qt::CaseInsensitive))
{
*type = fileTypeSkip;
return audioFile;
}
QFile readTest(filePath);
if(!readTest.open(QIODevice::ReadOnly))
{
*type = fileTypeDenied;
return audioFile;
}
if(checkFile_CDDA(readTest))
{
*type = fileTypeCDDA;
return audioFile;
}
readTest.close();
bool skipNext = false;
unsigned int id_val[2] = {UINT_MAX, UINT_MAX};
cover_t coverType = coverNone;
QByteArray coverData;
QStringList params;
params << QString("--Inform=file://%1").arg(QDir::toNativeSeparators(m_templateFile->filePath()));
params << QDir::toNativeSeparators(filePath);
QProcess process;
process.setProcessChannelMode(QProcess::MergedChannels);
process.setReadChannel(QProcess::StandardOutput);
process.start(m_mediaInfoBin, params);
if(!process.waitForStarted())
{
qWarning("MediaInfo process failed to create!");
qWarning("Error message: \"%s\"\n", process.errorString().toLatin1().constData());
process.kill();
process.waitForFinished(-1);
return audioFile;
}
while(process.state() != QProcess::NotRunning)
{
if(m_abortFlag)
{
process.kill();
qWarning("Process was aborted on user request!");
break;
}
if(!process.waitForReadyRead())
{
if(process.state() == QProcess::Running)
{
qWarning("MediaInfo time out. Killing process and skipping file!");
process.kill();
process.waitForFinished(-1);
return audioFile;
}
}
QByteArray data;
while(process.canReadLine())
{
QString line = QString::fromUtf8(process.readLine().constData()).simplified();
if(!line.isEmpty())
{
//qDebug("Line:%s", line.toUtf8().constData());
int index = line.indexOf('=');
if(index > 0)
{
QString key = line.left(index).trimmed();
QString val = line.mid(index+1).trimmed();
if(!key.isEmpty())
{
updateInfo(audioFile, &skipNext, id_val, &coverType, &coverData, key, val);
}
}
}
}
}
if(audioFile.fileName().isEmpty())
{
QString baseName = QFileInfo(filePath).fileName();
int index = baseName.lastIndexOf(".");
if(index >= 0)
{
baseName = baseName.left(index);
}
baseName = baseName.replace("_", " ").simplified();
index = baseName.lastIndexOf(" - ");
if(index >= 0)
{
baseName = baseName.mid(index + 3).trimmed();
}
audioFile.setFileName(baseName);
}
process.waitForFinished();
if(process.state() != QProcess::NotRunning)
{
process.kill();
process.waitForFinished(-1);
}
if((coverType != coverNone) && (!coverData.isEmpty()))
{
retrieveCover(audioFile, coverType, coverData);
}
return audioFile;
}
void FileAnalyzer_ST::updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned int *id_val, cover_t *coverType, QByteArray *coverData, const QString &key, const QString &value)
{
//qWarning("'%s' -> '%s'", key.toUtf8().constData(), value.toUtf8().constData());
/*New Stream*/
if(IS_KEY("Gen_ID") || IS_KEY("Aud_ID"))
{
if(value.isEmpty())
{
*skipNext = false;
}
else
{
//We ignore all ID's, except for the lowest one!
bool ok = false;
unsigned int id = value.toUInt(&ok);
if(ok)
{
if(IS_KEY("Gen_ID")) { id_val[0] = qMin(id_val[0], id); *skipNext = (id > id_val[0]); }
if(IS_KEY("Aud_ID")) { id_val[1] = qMin(id_val[1], id); *skipNext = (id > id_val[1]); }
}
else
{
*skipNext = true;
}
}
if(*skipNext)
{
qWarning("Skipping info for non-primary stream!");
}
return;
}
/*Skip or empty?*/
if((*skipNext) || value.isEmpty())
{
return;
}
/*Playlist file?*/
if(IS_KEY("Aud_Source"))
{
*skipNext = true;
audioFile.setFormatContainerType(QString());
audioFile.setFormatAudioType(QString());
qWarning("Skipping info for playlist file!");
return;
}
/*General Section*/
if(IS_SEC("Gen"))
{
if(IS_KEY("Gen_Format"))
{
audioFile.setFormatContainerType(value);
}
else if(IS_KEY("Gen_Format_Profile"))
{
audioFile.setFormatContainerProfile(value);
}
else if(IS_KEY("Gen_Title") || IS_KEY("Gen_Track"))
{
audioFile.setFileName(value);
}
else if(IS_KEY("Gen_Duration"))
{
unsigned int tmp = parseDuration(value);
if(tmp > 0) audioFile.setFileDuration(tmp);
}
else if(IS_KEY("Gen_Artist") || IS_KEY("Gen_Performer"))
{
audioFile.setFileArtist(value);
}
else if(IS_KEY("Gen_Album"))
{
audioFile.setFileAlbum(value);
}
else if(IS_KEY("Gen_Genre"))
{
audioFile.setFileGenre(value);
}
else if(IS_KEY("Gen_Released_Date") || IS_KEY("Gen_Recorded_Date"))
{
unsigned int tmp = parseYear(value);
if(tmp > 0) audioFile.setFileYear(tmp);
}
else if(IS_KEY("Gen_Comment"))
{
audioFile.setFileComment(value);
}
else if(IS_KEY("Gen_Track/Position"))
{
bool ok = false;
unsigned int tmp = value.toUInt(&ok);
if(ok) audioFile.setFilePosition(tmp);
}
else if(IS_KEY("Gen_Cover") || IS_KEY("Gen_Cover_Type"))
{
if(*coverType == coverNone)
{
*coverType = coverJpeg;
}
}
else if(IS_KEY("Gen_Cover_Mime"))
{
QString temp = FIRST_TOK(value);
if(!temp.compare("image/jpeg", Qt::CaseInsensitive)) *coverType = coverJpeg;
else if(!temp.compare("image/png", Qt::CaseInsensitive)) *coverType = coverPng;
else if(!temp.compare("image/gif", Qt::CaseInsensitive)) *coverType = coverGif;
}
else if(IS_KEY("Gen_Cover_Data"))
{
if(!coverData->isEmpty()) coverData->clear();
coverData->append(QByteArray::fromBase64(FIRST_TOK(value).toLatin1()));
}
else
{
qWarning("Unknown key '%s' with value '%s' found!", key.toUtf8().constData(), value.toUtf8().constData());
}
return;
}
/*Audio Section*/
if(IS_SEC("Aud"))
{
if(IS_KEY("Aud_Format"))
{
audioFile.setFormatAudioType(value);
}
else if(IS_KEY("Aud_Format_Profile"))
{
audioFile.setFormatAudioProfile(value);
}
else if(IS_KEY("Aud_Format_Version"))
{
audioFile.setFormatAudioVersion(value);
}
else if(IS_KEY("Aud_Channel(s)"))
{
bool ok = false;
unsigned int tmp = value.toUInt(&ok);
if(ok) audioFile.setFormatAudioChannels(tmp);
}
else if(IS_KEY("Aud_SamplingRate"))
{
bool ok = false;
unsigned int tmp = value.toUInt(&ok);
if(ok) audioFile.setFormatAudioSamplerate(tmp);
}
else if(IS_KEY("Aud_BitDepth"))
{
bool ok = false;
unsigned int tmp = value.toUInt(&ok);
if(ok) audioFile.setFormatAudioBitdepth(tmp);
}
else if(IS_KEY("Aud_Duration"))
{
unsigned int tmp = parseDuration(value);
if(tmp > 0) audioFile.setFileDuration(tmp);
}
else if(IS_KEY("Aud_BitRate"))
{
bool ok = false;
unsigned int tmp = value.toUInt(&ok);
if(ok) audioFile.setFormatAudioBitrate(tmp/1000);
}
else if(IS_KEY("Aud_BitRate_Mode"))
{
if(!value.compare("CBR", Qt::CaseInsensitive)) audioFile.setFormatAudioBitrateMode(AudioFileModel::BitrateModeConstant);
if(!value.compare("VBR", Qt::CaseInsensitive)) audioFile.setFormatAudioBitrateMode(AudioFileModel::BitrateModeVariable);
}
else
{
qWarning("Unknown key '%s' with value '%s' found!", key.toUtf8().constData(), value.toUtf8().constData());
}
return;
}
/*Section not recognized*/
qWarning("Unknown section: %s", key.toUtf8().constData());
}
bool FileAnalyzer_ST::checkFile_CDDA(QFile &file)
{
file.reset();
QByteArray data = file.read(128);
int i = data.indexOf("RIFF");
int j = data.indexOf("CDDA");
int k = data.indexOf("fmt ");
return ((i >= 0) && (j >= 0) && (k >= 0) && (k > j) && (j > i));
}
void FileAnalyzer_ST::retrieveCover(AudioFileModel &audioFile, cover_t coverType, const QByteArray &coverData)
{
qDebug("Retrieving cover!");
QString extension;
switch(coverType)
{
case coverPng:
extension = QString::fromLatin1("png");
break;
case coverGif:
extension = QString::fromLatin1("gif");
break;
default:
extension = QString::fromLatin1("jpg");
break;
}
if(!(QImage::fromData(coverData, extension.toUpper().toLatin1().constData()).isNull()))
{
QFile coverFile(QString("%1/%2.%3").arg(lamexp_temp_folder2(), lamexp_rand_str(), extension));
if(coverFile.open(QIODevice::WriteOnly))
{
coverFile.write(coverData);
coverFile.close();
audioFile.setFileCover(coverFile.fileName(), true);
}
}
else
{
qWarning("Image data seems to be invalid :-(");
}
}
bool FileAnalyzer_ST::analyzeAvisynthFile(const QString &filePath, AudioFileModel &info)
{
QProcess process;
process.setProcessChannelMode(QProcess::MergedChannels);
process.setReadChannel(QProcess::StandardOutput);
process.start(m_avs2wavBin, QStringList() << QDir::toNativeSeparators(filePath) << "?");
if(!process.waitForStarted())
{
qWarning("AVS2WAV process failed to create!");
qWarning("Error message: \"%s\"\n", process.errorString().toLatin1().constData());
process.kill();
process.waitForFinished(-1);
return false;
}
bool bInfoHeaderFound = false;
while(process.state() != QProcess::NotRunning)
{
if(m_abortFlag)
{
process.kill();
qWarning("Process was aborted on user request!");
break;
}
if(!process.waitForReadyRead())
{
if(process.state() == QProcess::Running)
{
qWarning("AVS2WAV time out. Killing process and skipping file!");
process.kill();
process.waitForFinished(-1);
return false;
}
}
QByteArray data;
while(process.canReadLine())
{
QString line = QString::fromUtf8(process.readLine().constData()).simplified();
if(!line.isEmpty())
{
int index = line.indexOf(':');
if(index > 0)
{
QString key = line.left(index).trimmed();
QString val = line.mid(index+1).trimmed();
if(bInfoHeaderFound && !key.isEmpty() && !val.isEmpty())
{
if(key.compare("TotalSeconds", Qt::CaseInsensitive) == 0)
{
bool ok = false;
unsigned int duration = val.toUInt(&ok);
if(ok) info.setFileDuration(duration);
}
if(key.compare("SamplesPerSec", Qt::CaseInsensitive) == 0)
{
bool ok = false;
unsigned int samplerate = val.toUInt(&ok);
if(ok) info.setFormatAudioSamplerate (samplerate);
}
if(key.compare("Channels", Qt::CaseInsensitive) == 0)
{
bool ok = false;
unsigned int channels = val.toUInt(&ok);
if(ok) info.setFormatAudioChannels(channels);
}
if(key.compare("BitsPerSample", Qt::CaseInsensitive) == 0)
{
bool ok = false;
unsigned int bitdepth = val.toUInt(&ok);
if(ok) info.setFormatAudioBitdepth(bitdepth);
}
}
}
else
{
if(line.contains("[Audio Info]", Qt::CaseInsensitive))
{
info.setFormatAudioType("Avisynth");
info.setFormatContainerType("Avisynth");
bInfoHeaderFound = true;
}
}
}
}
}
process.waitForFinished();
if(process.state() != QProcess::NotRunning)
{
process.kill();
process.waitForFinished(-1);
}
//Check exit code
switch(process.exitCode())
{
case 0:
qDebug("Avisynth script was analyzed successfully.");
return true;
break;
case -5:
qWarning("It appears that Avisynth is not installed on the system!");
return false;
break;
default:
qWarning("Failed to open the Avisynth script, bad AVS file?");
return false;
break;
}
}
bool FileAnalyzer_ST::createTemplate(void)
{
if(m_templateFile)
{
qWarning("Template file already exists!");
return true;
}
QString templatePath = QString("%1/%2.txt").arg(lamexp_temp_folder2(), lamexp_rand_str());
QFile templateFile(templatePath);
if(!templateFile.open(QIODevice::WriteOnly))
{
return false;
}
templateFile.write("General;");
for(size_t i = 0; g_tags_gen[i]; i++)
{
templateFile.write(QString("Gen_%1=%%1%\\n").arg(g_tags_gen[i]).toLatin1().constData());
}
templateFile.write("\\n\r\n");
templateFile.write("Audio;");
for(size_t i = 0; g_tags_aud[i]; i++)
{
templateFile.write(QString("Aud_%1=%%1%\\n").arg(g_tags_aud[i]).toLatin1().constData());
}
templateFile.write("\\n\r\n");
bool success = (templateFile.error() == QFile::NoError);
templateFile.close();
if(!success)
{
QFile::remove(templatePath);
return false;
}
try
{
m_templateFile = new LockedFile(templatePath);
}
catch(...)
{
qWarning("Failed to lock template file!");
return false;
}
return true;
}
unsigned int FileAnalyzer_ST::parseYear(const QString &str)
{
if(str.startsWith("UTC", Qt::CaseInsensitive))
{
QDate date = QDate::fromString(str.mid(3).trimmed().left(10), "yyyy-MM-dd");
if(date.isValid())
{
return date.year();
}
else
{
return 0;
}
}
else
{
bool ok = false;
int year = str.toInt(&ok);
if(ok && year > 0)
{
return year;
}
else
{
return 0;
}
}
}
unsigned int FileAnalyzer_ST::parseDuration(const QString &str)
{
bool ok = false;
unsigned int value = str.toUInt(&ok);
return ok ? (value/1000) : 0;
}
////////////////////////////////////////////////////////////
// Public Functions
////////////////////////////////////////////////////////////
unsigned int FileAnalyzer_ST::filesAccepted(void)
{
return m_filesAccepted;
}
unsigned int FileAnalyzer_ST::filesRejected(void)
{
return m_filesRejected;
}
unsigned int FileAnalyzer_ST::filesDenied(void)
{
return m_filesDenied;
}
unsigned int FileAnalyzer_ST::filesDummyCDDA(void)
{
return m_filesDummyCDDA;
}
unsigned int FileAnalyzer_ST::filesCueSheet(void)
{
return m_filesCueSheet;
}
////////////////////////////////////////////////////////////
// EVENTS
////////////////////////////////////////////////////////////
/*NONE*/

View File

@ -0,0 +1,107 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// http://www.gnu.org/licenses/gpl-2.0.txt
///////////////////////////////////////////////////////////////////////////////
// --------------------------------------------------------------------
// !!! THIS IS THE OLD SINGLE-THREADED VERSION OF THE FILE ANALYZER !!!
// --------------------------------------------------------------------
#pragma once
#include <QThread>
#include <QStringList>
class AudioFileModel;
class QFile;
class QDir;
class QFileInfo;
class LockedFile;
////////////////////////////////////////////////////////////
// Splash Thread
////////////////////////////////////////////////////////////
class FileAnalyzer_ST: public QThread
{
Q_OBJECT
public:
FileAnalyzer_ST(const QStringList &inputFiles);
~FileAnalyzer_ST(void);
void run();
bool getSuccess(void) { return !isRunning() && m_bSuccess; }
unsigned int filesAccepted(void);
unsigned int filesRejected(void);
unsigned int filesDenied(void);
unsigned int filesDummyCDDA(void);
unsigned int filesCueSheet(void);
signals:
void fileSelected(const QString &fileName);
void fileAnalyzed(const AudioFileModel &file);
public slots:
void abortProcess(void) { m_abortFlag = true; }
private:
enum cover_t
{
coverNone,
coverJpeg,
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);
unsigned int parseYear(const QString &str);
unsigned int parseDuration(const QString &str);
bool checkFile_CDDA(QFile &file);
void retrieveCover(AudioFileModel &audioFile, cover_t coverType, const QByteArray &coverData);
bool analyzeAvisynthFile(const QString &filePath, AudioFileModel &info);
bool createTemplate(void);
const QString m_mediaInfoBin;
const QString m_avs2wavBin;
QStringList m_inputFiles;
QStringList m_recentlyAdded;
unsigned int m_filesAccepted;
unsigned int m_filesRejected;
unsigned int m_filesDenied;
unsigned int m_filesDummyCDDA;
unsigned int m_filesCueSheet;
LockedFile *m_templateFile;
volatile bool m_abortFlag;
static const char *g_tags_gen[];
static const char *g_tags_aud[];
bool m_bAborted;
bool m_bSuccess;
};

View File

@ -39,22 +39,25 @@
#include <math.h>
#include <time.h>
#include <assert.h>
#define IS_KEY(KEY) (key.compare(KEY, Qt::CaseInsensitive) == 0)
#define IS_SEC(SEC) (key.startsWith((SEC "_"), Qt::CaseInsensitive))
#define FIRST_TOK(STR) (STR.split(" ", QString::SkipEmptyParts).first())
/* static vars */
QReadWriteLock AnalyzeTask::s_lock;
QMutex AnalyzeTask::s_waitMutex;
QWaitCondition AnalyzeTask::s_waitCond;
unsigned __int64 AnalyzeTask::s_threadIdx_created;
unsigned __int64 AnalyzeTask::s_threadIdx_finished;
unsigned int AnalyzeTask::s_filesAccepted;
unsigned int AnalyzeTask::s_filesRejected;
unsigned int AnalyzeTask::s_filesDenied;
unsigned int AnalyzeTask::s_filesDummyCDDA;
unsigned int AnalyzeTask::s_filesCueSheet;
QSet<unsigned int> AnalyzeTask::s_threadIdx_running;
unsigned int AnalyzeTask::s_threadIdx_next = 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;
@ -84,7 +87,7 @@ AnalyzeTask::AnalyzeTask(const QString &inputFile, const QString &templateFile,
AnalyzeTask::~AnalyzeTask(void)
{
s_waitMutex.lock();
s_threadIdx_finished = qMax(s_threadIdx_finished, m_threadIdx + 1ui64);
s_threadIdx_running.remove(m_threadIdx);
s_waitMutex.unlock();
s_waitCond.wakeAll();
@ -106,7 +109,7 @@ void AnalyzeTask::run()
}
s_waitMutex.lock();
s_threadIdx_finished = qMax(s_threadIdx_finished, m_threadIdx + 1ui64);
s_threadIdx_running.remove(m_threadIdx);
s_waitMutex.unlock();
s_waitCond.wakeAll();
@ -130,7 +133,6 @@ void AnalyzeTask::run_ex(void)
}
if(fileType == fileTypeSkip)
{
waitForPreviousThreads();
qWarning("File was recently added, skipping!");
return;
}
@ -139,7 +141,6 @@ void AnalyzeTask::run_ex(void)
QWriteLocker lock(&s_lock);
s_filesDenied++;
lock.unlock();
waitForPreviousThreads();
qWarning("Cannot access file for reading, skipping!");
return;
}
@ -148,7 +149,6 @@ void AnalyzeTask::run_ex(void)
QWriteLocker lock(&s_lock);
s_filesDummyCDDA++;
lock.unlock();
waitForPreviousThreads();
qWarning("Dummy CDDA file detected, skipping!");
return;
}
@ -159,7 +159,6 @@ void AnalyzeTask::run_ex(void)
QStringList fileList;
if(PlaylistImporter::importPlaylist(fileList, currentFile))
{
waitForPreviousThreads();
qDebug("Imported playlist file.");
QWriteLocker lock(&s_lock);
s_additionalFiles << fileList;
@ -195,7 +194,6 @@ void AnalyzeTask::run_ex(void)
qDebug("Rejected file of unknown type: %s", file.filePath().toUtf8().constData());
s_filesRejected++;
}
waitForPreviousThreads();
return;
}
@ -725,7 +723,8 @@ unsigned int AnalyzeTask::parseDuration(const QString &str)
unsigned __int64 AnalyzeTask::makeThreadIdx(void)
{
s_waitMutex.lock();
unsigned __int64 idx = s_threadIdx_created++;
unsigned int idx = s_threadIdx_next++;
s_threadIdx_running.insert(idx);
s_waitMutex.unlock();
return idx;
@ -736,13 +735,20 @@ 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;
while(retryCount < MAX_RETRIES)
forever
{
s_waitMutex.lock();
bool bWaitFlag = false;
QSet<unsigned int>::const_iterator i;
if((s_threadIdx_finished >= m_threadIdx) || *m_abortFlag)
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;
@ -750,13 +756,13 @@ void AnalyzeTask::waitForPreviousThreads(void)
if(!s_waitCond.wait(&s_waitMutex, WAITCOND_TIMEOUT))
{
retryCount++;
if(++retryCount > MAX_RETRIES)
{
qWarning("AnalyzeTask::waitForPreviousThreads encountered timeout !!!");
s_threadIdx_running.clear();
}
}
s_waitMutex.unlock();
}
qWarning("AnalyzeTask Timeout, will proceed anyway !!!");
}
////////////////////////////////////////////////////////////
@ -835,8 +841,8 @@ void AnalyzeTask::reset(void)
lock.unlock();
s_waitMutex.lock();
s_threadIdx_created = 0;
s_threadIdx_finished = 0;
s_threadIdx_next = 0;
s_threadIdx_running.clear();
s_waitMutex.unlock();
}

View File

@ -102,8 +102,8 @@ private:
static QMutex s_waitMutex;
static QWaitCondition s_waitCond;
static unsigned __int64 s_threadIdx_created;
static unsigned __int64 s_threadIdx_finished;
static QSet<unsigned int> s_threadIdx_running;
static unsigned int s_threadIdx_next;
static QReadWriteLock s_lock;
static unsigned int s_filesAccepted;