///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
-// Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
+// Copyright (C) 2004-2015 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.
+// (at your option) any later version, but always including the *additional*
+// restrictions defined in the "License.txt" file.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "Thread_FileAnalyzer_Task.h"
+//Internal
#include "Global.h"
#include "LockedFile.h"
#include "Model_AudioFile.h"
-#include "PlaylistImporter.h"
+//MUtils
+#include <MUtils/Global.h>
+#include <MUtils/OSSupport.h>
+#include <MUtils/Exception.h>
+
+//Qt
#include <QDir>
#include <QFileInfo>
#include <QProcess>
#include <QWriteLocker>
#include <QThread>
+
+//CRT
#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;
-QStringList AnalyzeTask::s_additionalFiles;
-QStringList AnalyzeTask::s_recentlyAdded;
-
////////////////////////////////////////////////////////////
// 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")),
- m_avs2wavBin(lamexp_lookup_tool("avs2wav.exe")),
+ m_mediaInfoBin(lamexp_tools_lookup("mediainfo.exe")),
+ m_avs2wavBin(lamexp_tools_lookup("avs2wav.exe")),
m_abortFlag(abortFlag)
{
if(m_mediaInfoBin.isEmpty() || m_avs2wavBin.isEmpty())
AnalyzeTask::~AnalyzeTask(void)
{
- s_waitMutex.lock();
- s_threadIdx_finished = qMax(s_threadIdx_finished, m_threadIdx + 1ui64);
- s_waitMutex.unlock();
-
- s_waitCond.wakeAll();
+ emit taskCompleted(m_taskId);
}
////////////////////////////////////////////////////////////
{
run_ex();
}
+ catch(const std::exception &error)
+ {
+ MUTILS_PRINT_ERROR("\nGURU MEDITATION !!!\n\nException error:\n%s\n", error.what());
+ MUtils::OS::fatal_exit(L"Unhandeled C++ exception error, application will exit!");
+ }
catch(...)
{
- qWarning("WARNING: Caught an in exception AnalyzeTask thread!");
+ MUTILS_PRINT_ERROR("\nGURU MEDITATION !!!\n\nUnknown exception error!\n");
+ MUtils::OS::fatal_exit(L"Unhandeled C++ exception error, application will exit!");
}
-
- s_waitMutex.lock();
- s_threadIdx_finished = qMax(s_threadIdx_finished, m_threadIdx + 1ui64);
- s_waitMutex.unlock();
-
- s_waitCond.wakeAll();
}
void AnalyzeTask::run_ex(void)
{
int fileType = fileTypeNormal;
QString currentFile = QDir::fromNativeSeparators(m_inputFile);
- qDebug("Analyzing: %s", currentFile.toUtf8().constData());
-
- emit fileSelected(QFileInfo(currentFile).fileName());
- emit progressValChanged(m_threadIdx + 1);
+ qDebug("Analyzing: %s", MUTILS_UTF8(currentFile));
AudioFileModel file = analyzeFile(currentFile, &fileType);
qWarning("Operation cancelled by user!");
return;
}
- if(fileType == fileTypeSkip)
- {
- qWarning("File was recently added, skipping!");
- return;
- }
- if(fileType == fileTypeDenied)
+
+ switch(fileType)
{
- QWriteLocker lock(&s_lock);
- s_filesDenied++;
+ case fileTypeDenied:
qWarning("Cannot access file for reading, skipping!");
- return;
- }
- if(fileType == fileTypeCDDA)
- {
- QWriteLocker lock(&s_lock);
- s_filesDummyCDDA++;
+ break;
+ case fileTypeCDDA:
qWarning("Dummy CDDA file detected, skipping!");
- return;
- }
-
- if(file.fileName().isEmpty() || file.formatContainerType().isEmpty() || file.formatAudioType().isEmpty())
- {
- QStringList fileList;
- if(PlaylistImporter::importPlaylist(fileList, currentFile))
- {
- waitForPreviousThreads();
- 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))
+ break;
+ default:
+ if(file.metaInfo().title().isEmpty() || file.techInfo().containerType().isEmpty() || file.techInfo().audioType().isEmpty())
{
- 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.append(file.filePath());
- 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", MUTILS_UTF8(file.filePath()));
+ }
}
else
{
- QWriteLocker lock(&s_lock);
- qDebug("Rejected Avisynth file: %s", file.filePath().toUtf8().constData());
- s_filesRejected++;
+ qDebug("Rejected file of unknown type: %s", MUTILS_UTF8(file.filePath()));
}
}
- else
- {
- QWriteLocker lock(&s_lock);
- qDebug("Rejected file of unknown type: %s", file.filePath().toUtf8().constData());
- s_filesRejected++;
- }
- return;
+ break;
}
- QWriteLocker lock(&s_lock);
- s_filesAccepted++;
- s_recentlyAdded.append(file.filePath());
- lock.unlock();
-
- waitForPreviousThreads();
- emit fileAnalyzed(file);
+ //Emit the file now!
+ emit fileAnalyzed(m_taskId, fileType, file);
}
////////////////////////////////////////////////////////////
*type = fileTypeNormal;
AudioFileModel audioFile(filePath);
- QReadLocker readLock(&s_lock);
- if(s_recentlyAdded.contains(filePath, Qt::CaseInsensitive))
- {
- *type = fileTypeSkip;
- return audioFile;
- }
- readLock.unlock();
-
QFile readTest(filePath);
if(!readTest.open(QIODevice::ReadOnly))
{
params << QDir::toNativeSeparators(filePath);
QProcess process;
- process.setProcessChannelMode(QProcess::MergedChannels);
- process.setReadChannel(QProcess::StandardOutput);
+ MUtils::init_process(process, QFileInfo(m_mediaInfoBin).absolutePath());
+
process.start(m_mediaInfoBin, params);
if(!process.waitForStarted())
QString line = QString::fromUtf8(process.readLine().constData()).simplified();
if(!line.isEmpty())
{
- //qDebug("Line:%s", line.toUtf8().constData());
+ //qDebug("Line:%s", MUTILS_UTF8(line));
int index = line.indexOf('=');
if(index > 0)
}
}
- if(audioFile.fileName().isEmpty())
+ if(audioFile.metaInfo().title().isEmpty())
{
QString baseName = QFileInfo(filePath).fileName();
int index = baseName.lastIndexOf(".");
baseName = baseName.mid(index + 3).trimmed();
}
- audioFile.setFileName(baseName);
+ audioFile.metaInfo().setTitle(baseName);
}
process.waitForFinished();
retrieveCover(audioFile, coverType, coverData);
}
+ if((audioFile.techInfo().audioType().compare("PCM", Qt::CaseInsensitive) == 0) && (audioFile.techInfo().audioProfile().compare("Float", Qt::CaseInsensitive) == 0))
+ {
+ if(audioFile.techInfo().audioBitdepth() == 32) audioFile.techInfo().setAudioBitdepth(AudioFileModel::BITDEPTH_IEEE_FLOAT32);
+ }
+
return audioFile;
}
void AnalyzeTask::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());
+ //qWarning("'%s' -> '%s'", MUTILS_UTF8(key), MUTILS_UTF8(value));
/*New Stream*/
if(IS_KEY("Gen_ID") || IS_KEY("Aud_ID"))
if(IS_KEY("Aud_Source"))
{
*skipNext = true;
- audioFile.setFormatContainerType(QString());
- audioFile.setFormatAudioType(QString());
+ audioFile.techInfo().setContainerType(QString());
+ audioFile.techInfo().setAudioType(QString());
qWarning("Skipping info for playlist file!");
return;
}
{
if(IS_KEY("Gen_Format"))
{
- audioFile.setFormatContainerType(value);
+ audioFile.techInfo().setContainerType(value);
}
else if(IS_KEY("Gen_Format_Profile"))
{
- audioFile.setFormatContainerProfile(value);
+ audioFile.techInfo().setContainerProfile(value);
}
else if(IS_KEY("Gen_Title") || IS_KEY("Gen_Track"))
{
- audioFile.setFileName(value);
+ audioFile.metaInfo().setTitle(value);
}
else if(IS_KEY("Gen_Duration"))
{
unsigned int tmp = parseDuration(value);
- if(tmp > 0) audioFile.setFileDuration(tmp);
+ if(tmp > 0) audioFile.techInfo().setDuration(tmp);
}
else if(IS_KEY("Gen_Artist") || IS_KEY("Gen_Performer"))
{
- audioFile.setFileArtist(value);
+ audioFile.metaInfo().setArtist(value);
}
else if(IS_KEY("Gen_Album"))
{
- audioFile.setFileAlbum(value);
+ audioFile.metaInfo().setAlbum(value);
}
else if(IS_KEY("Gen_Genre"))
{
- audioFile.setFileGenre(value);
+ audioFile.metaInfo().setGenre(value);
}
else if(IS_KEY("Gen_Released_Date") || IS_KEY("Gen_Recorded_Date"))
{
unsigned int tmp = parseYear(value);
- if(tmp > 0) audioFile.setFileYear(tmp);
+ if(tmp > 0) audioFile.metaInfo().setYear(tmp);
}
else if(IS_KEY("Gen_Comment"))
{
- audioFile.setFileComment(value);
+ audioFile.metaInfo().setComment(value);
}
else if(IS_KEY("Gen_Track/Position"))
{
bool ok = false;
unsigned int tmp = value.toUInt(&ok);
- if(ok) audioFile.setFilePosition(tmp);
+ if(ok) audioFile.metaInfo().setPosition(tmp);
}
else if(IS_KEY("Gen_Cover") || IS_KEY("Gen_Cover_Type"))
{
}
else
{
- qWarning("Unknown key '%s' with value '%s' found!", key.toUtf8().constData(), value.toUtf8().constData());
+ qWarning("Unknown key '%s' with value '%s' found!", MUTILS_UTF8(key), MUTILS_UTF8(value));
}
return;
}
if(IS_KEY("Aud_Format"))
{
- audioFile.setFormatAudioType(value);
+ audioFile.techInfo().setAudioType(value);
}
else if(IS_KEY("Aud_Format_Profile"))
{
- audioFile.setFormatAudioProfile(value);
+ audioFile.techInfo().setAudioProfile(value);
}
else if(IS_KEY("Aud_Format_Version"))
{
- audioFile.setFormatAudioVersion(value);
+ audioFile.techInfo().setAudioVersion(value);
}
else if(IS_KEY("Aud_Channel(s)"))
{
bool ok = false;
unsigned int tmp = value.toUInt(&ok);
- if(ok) audioFile.setFormatAudioChannels(tmp);
+ if(ok) audioFile.techInfo().setAudioChannels(tmp);
}
else if(IS_KEY("Aud_SamplingRate"))
{
bool ok = false;
unsigned int tmp = value.toUInt(&ok);
- if(ok) audioFile.setFormatAudioSamplerate(tmp);
+ if(ok) audioFile.techInfo().setAudioSamplerate(tmp);
}
else if(IS_KEY("Aud_BitDepth"))
{
bool ok = false;
unsigned int tmp = value.toUInt(&ok);
- if(ok) audioFile.setFormatAudioBitdepth(tmp);
+ if(ok) audioFile.techInfo().setAudioBitdepth(tmp);
}
else if(IS_KEY("Aud_Duration"))
{
unsigned int tmp = parseDuration(value);
- if(tmp > 0) audioFile.setFileDuration(tmp);
+ if(tmp > 0) audioFile.techInfo().setDuration(tmp);
}
else if(IS_KEY("Aud_BitRate"))
{
bool ok = false;
unsigned int tmp = value.toUInt(&ok);
- if(ok) audioFile.setFormatAudioBitrate(tmp/1000);
+ if(ok) audioFile.techInfo().setAudioBitrate(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);
+ if(!value.compare("CBR", Qt::CaseInsensitive)) audioFile.techInfo().setAudioBitrateMode(AudioFileModel::BitrateModeConstant);
+ if(!value.compare("VBR", Qt::CaseInsensitive)) audioFile.techInfo().setAudioBitrateMode(AudioFileModel::BitrateModeVariable);
+ }
+ else if(IS_KEY("Aud_Encoded_Library"))
+ {
+ audioFile.techInfo().setAudioEncodeLib(value);
}
else
{
- qWarning("Unknown key '%s' with value '%s' found!", key.toUtf8().constData(), value.toUtf8().constData());
+ qWarning("Unknown key '%s' with value '%s' found!", MUTILS_UTF8(key), MUTILS_UTF8(value));
}
return;
}
/*Section not recognized*/
- qWarning("Unknown section: %s", key.toUtf8().constData());
+ qWarning("Unknown section: %s", MUTILS_UTF8(key));
}
bool AnalyzeTask::checkFile_CDDA(QFile &file)
if(!(QImage::fromData(coverData, extension.toUpper().toLatin1().constData()).isNull()))
{
- QFile coverFile(QString("%1/%2.%3").arg(lamexp_temp_folder2(), lamexp_rand_str(), extension));
+ QFile coverFile(QString("%1/%2.%3").arg(MUtils::temp_folder(), MUtils::rand_str(), extension));
if(coverFile.open(QIODevice::WriteOnly))
{
coverFile.write(coverData);
coverFile.close();
- audioFile.setFileCover(coverFile.fileName(), true);
+ audioFile.metaInfo().setCover(coverFile.fileName(), true);
}
}
else
bool AnalyzeTask::analyzeAvisynthFile(const QString &filePath, AudioFileModel &info)
{
QProcess process;
- process.setProcessChannelMode(QProcess::MergedChannels);
- process.setReadChannel(QProcess::StandardOutput);
+ MUtils::init_process(process, QFileInfo(m_avs2wavBin).absolutePath());
+
process.start(m_avs2wavBin, QStringList() << QDir::toNativeSeparators(filePath) << "?");
if(!process.waitForStarted())
{
bool ok = false;
unsigned int duration = val.toUInt(&ok);
- if(ok) info.setFileDuration(duration);
+ if(ok) info.techInfo().setDuration(duration);
}
if(key.compare("SamplesPerSec", Qt::CaseInsensitive) == 0)
{
bool ok = false;
unsigned int samplerate = val.toUInt(&ok);
- if(ok) info.setFormatAudioSamplerate (samplerate);
+ if(ok) info.techInfo().setAudioSamplerate (samplerate);
}
if(key.compare("Channels", Qt::CaseInsensitive) == 0)
{
bool ok = false;
unsigned int channels = val.toUInt(&ok);
- if(ok) info.setFormatAudioChannels(channels);
+ if(ok) info.techInfo().setAudioChannels(channels);
}
if(key.compare("BitsPerSample", Qt::CaseInsensitive) == 0)
{
bool ok = false;
unsigned int bitdepth = val.toUInt(&ok);
- if(ok) info.setFormatAudioBitdepth(bitdepth);
- }
+ if(ok) info.techInfo().setAudioBitdepth(bitdepth);
+ }
}
}
else
{
if(line.contains("[Audio Info]", Qt::CaseInsensitive))
{
- info.setFormatAudioType("Avisynth");
- info.setFormatContainerType("Avisynth");
+ info.techInfo().setAudioType("Avisynth");
+ info.techInfo().setContainerType("Avisynth");
bInfoHeaderFound = true;
}
}
return ok ? (value/1000) : 0;
}
-unsigned __int64 AnalyzeTask::makeThreadIdx(void)
-{
- s_waitMutex.lock();
- unsigned __int64 idx = s_threadIdx_created++;
- 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!
-
- for(int i = 0; i < 64; i++)
- {
- s_waitMutex.lock();
-
- if((s_threadIdx_finished >= m_threadIdx) || *m_abortFlag)
- {
- s_waitMutex.unlock();
- break;
- }
-
- if(!s_waitCond.wait(&s_waitMutex, 1250))
- {
- qWarning("FileAnalyzerTask: Timeout, retrying!");
- }
-
- s_waitMutex.unlock();
- }
-}
////////////////////////////////////////////////////////////
// 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::waitForOneThread(unsigned long timeout)
-{
- bool ret = false;
-
- s_waitMutex.lock();
- ret = s_waitCond.wait(&s_waitMutex, timeout);
- s_waitMutex.unlock();
-
- return ret;
-}
+/*NONE*/
-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_created = 0;
- s_threadIdx_finished = 0;
- s_waitMutex.unlock();
-}
////////////////////////////////////////////////////////////
// EVENTS
////////////////////////////////////////////////////////////