Adapted MediaInfo parsing code for new MediaInfo XML output.
aka "...when MediaInfo changes its XML output format *one* day after we implemented parsing of XML-based MediaInfo output" ;-)
This commit is contained in:
parent
98fd505e68
commit
9b01f44804
@ -35,7 +35,7 @@
|
||||
#define VER_LAMEXP_MINOR_LO 6
|
||||
#define VER_LAMEXP_TYPE Alpha
|
||||
#define VER_LAMEXP_PATCH 8
|
||||
#define VER_LAMEXP_BUILD 2048
|
||||
#define VER_LAMEXP_BUILD 2050
|
||||
#define VER_LAMEXP_CONFG 2002
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -31,6 +31,7 @@
|
||||
//MUtils
|
||||
#include <MUtils/Global.h>
|
||||
#include <MUtils/OSSupport.h>
|
||||
#include <MUtils/Lazy.h>
|
||||
#include <MUtils/Exception.h>
|
||||
|
||||
//Qt
|
||||
@ -66,7 +67,7 @@ while(0)
|
||||
|
||||
#define ADD_PROPTERY_MAPPING_2(TYPE, MI_NAME, LX_NAME) do \
|
||||
{ \
|
||||
builder->insert(qMakePair(trackType_##TYPE, QString::fromLatin1(#MI_NAME)), propertyId_##LX_NAME); \
|
||||
builder->insert(qMakePair(AnalyzeTask::trackType_##TYPE, QString::fromLatin1(#MI_NAME)), AnalyzeTask::propertyId_##LX_NAME); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
@ -80,54 +81,15 @@ while(0)
|
||||
|
||||
#define STRICMP(A,B) ((A).compare((B), Qt::CaseInsensitive) == 0)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
AnalyzeTask::AnalyzeTask(const int taskId, const QString &inputFile, QAtomicInt &abortFlag)
|
||||
:
|
||||
m_taskId(taskId),
|
||||
m_inputFile(inputFile),
|
||||
m_mediaInfoBin(lamexp_tools_lookup("mediainfo.exe")),
|
||||
m_mediaInfoVer(lamexp_tools_version("mediainfo.exe")),
|
||||
m_avs2wavBin(lamexp_tools_lookup("avs2wav.exe")),
|
||||
m_abortFlag(abortFlag),
|
||||
m_mediaInfoIdx(initMediaInfoIdx()),
|
||||
m_avisynthIdx(initAvisynthIdx()),
|
||||
m_mimeTypes(initMimeTypes()),
|
||||
m_trackTypes(initTrackTypes())
|
||||
{
|
||||
if(m_mediaInfoBin.isEmpty() || m_avs2wavBin.isEmpty())
|
||||
{
|
||||
qFatal("Invalid path to MediaInfo binary. Tool not initialized properly.");
|
||||
}
|
||||
}
|
||||
|
||||
AnalyzeTask::~AnalyzeTask(void)
|
||||
{
|
||||
emit taskCompleted(m_taskId);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Static initialization
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
QReadWriteLock AnalyzeTask::s_lock;
|
||||
QScopedPointer<const QMap<QPair<AnalyzeTask::MI_trackType_t, QString>, AnalyzeTask::MI_propertyId_t>> AnalyzeTask::s_pMediaInfoIdx;
|
||||
QScopedPointer<const QMap<QString, AnalyzeTask::MI_propertyId_t>> AnalyzeTask::s_pAvisynthIdx;
|
||||
QScopedPointer<const QMap<QString, QString>> AnalyzeTask::s_pMimeTypes;
|
||||
QScopedPointer<const QMap<QString, AnalyzeTask::MI_trackType_t>> AnalyzeTask::s_pTrackTypes;
|
||||
|
||||
const QMap<QPair<AnalyzeTask::MI_trackType_t, QString>, AnalyzeTask::MI_propertyId_t> &AnalyzeTask::initMediaInfoIdx(void)
|
||||
class AnalyzeTask_StaticInit_MediaInfoIdx : public MUtils::Lazy<const QMap<QPair<AnalyzeTask::MI_trackType_t, QString>, AnalyzeTask::MI_propertyId_t>>
|
||||
{
|
||||
QReadLocker rdLocker(&s_lock);
|
||||
if (s_pMediaInfoIdx.isNull())
|
||||
virtual QMap<QPair<AnalyzeTask::MI_trackType_t, QString>, AnalyzeTask::MI_propertyId_t> *create()
|
||||
{
|
||||
rdLocker.unlock();
|
||||
QWriteLocker wrLocker(&s_lock);
|
||||
if (s_pMediaInfoIdx.isNull())
|
||||
{
|
||||
QMap<QPair<MI_trackType_t, QString>, MI_propertyId_t> *const builder = new QMap<QPair<MI_trackType_t, QString>, MI_propertyId_t>();
|
||||
QMap<QPair<AnalyzeTask::MI_trackType_t, QString>, AnalyzeTask::MI_propertyId_t> *const builder = new QMap<QPair<AnalyzeTask::MI_trackType_t, QString>, AnalyzeTask::MI_propertyId_t>();
|
||||
ADD_PROPTERY_MAPPING_2(gen, format, container);
|
||||
ADD_PROPTERY_MAPPING_2(gen, format_profile, container_profile);
|
||||
ADD_PROPTERY_MAPPING_1(gen, duration);
|
||||
@ -153,75 +115,77 @@ const QMap<QPair<AnalyzeTask::MI_trackType_t, QString>, AnalyzeTask::MI_property
|
||||
ADD_PROPTERY_MAPPING_1(aud, encoded_library);
|
||||
ADD_PROPTERY_MAPPING_2(gen, cover_mime, cover_mime);
|
||||
ADD_PROPTERY_MAPPING_2(gen, cover_data, cover_data);
|
||||
s_pMediaInfoIdx.reset(builder);
|
||||
return builder;
|
||||
}
|
||||
wrLocker.unlock();
|
||||
rdLocker.relock();
|
||||
}
|
||||
return (*s_pMediaInfoIdx);
|
||||
}
|
||||
s_mediaInfoIdx;
|
||||
|
||||
const QMap<QString, AnalyzeTask::MI_propertyId_t> &AnalyzeTask::initAvisynthIdx(void)
|
||||
class AnalyzeTask_StaticInit_AvisynthIdx : public MUtils::Lazy<const QMap<QString, AnalyzeTask::MI_propertyId_t>>
|
||||
{
|
||||
QReadLocker rdLocker(&s_lock);
|
||||
if (s_pAvisynthIdx.isNull())
|
||||
virtual QMap<QString, AnalyzeTask::MI_propertyId_t> *create()
|
||||
{
|
||||
rdLocker.unlock();
|
||||
QWriteLocker wrLocker(&s_lock);
|
||||
if (s_pAvisynthIdx.isNull())
|
||||
{
|
||||
QMap<QString, MI_propertyId_t> *const builder = new QMap<QString, MI_propertyId_t>();
|
||||
builder->insert(QLatin1String("totalseconds"), propertyId_duration);
|
||||
builder->insert(QLatin1String("samplespersec"), propertyId_samplingrate);
|
||||
builder->insert(QLatin1String("channels"), propertyId_channel_s_);
|
||||
builder->insert(QLatin1String("bitspersample"), propertyId_bitdepth);
|
||||
s_pAvisynthIdx.reset(builder);
|
||||
QMap<QString, AnalyzeTask::MI_propertyId_t> *const builder = new QMap<QString, AnalyzeTask::MI_propertyId_t>();
|
||||
builder->insert(QLatin1String("totalseconds"), AnalyzeTask::propertyId_duration);
|
||||
builder->insert(QLatin1String("samplespersec"), AnalyzeTask::propertyId_samplingrate);
|
||||
builder->insert(QLatin1String("channels"), AnalyzeTask::propertyId_channel_s_);
|
||||
builder->insert(QLatin1String("bitspersample"), AnalyzeTask::propertyId_bitdepth);
|
||||
return builder;
|
||||
}
|
||||
wrLocker.unlock();
|
||||
rdLocker.relock();
|
||||
}
|
||||
return (*s_pAvisynthIdx);
|
||||
}
|
||||
const QMap<QString, AnalyzeTask::MI_trackType_t> &AnalyzeTask::initTrackTypes(void)
|
||||
{
|
||||
QReadLocker rdLocker(&s_lock);
|
||||
if (s_pTrackTypes.isNull())
|
||||
{
|
||||
rdLocker.unlock();
|
||||
QWriteLocker wrLocker(&s_lock);
|
||||
if (s_pTrackTypes.isNull())
|
||||
{
|
||||
QMap<QString, MI_trackType_t> *const builder = new QMap<QString, MI_trackType_t>();
|
||||
builder->insert("general", trackType_gen);
|
||||
builder->insert("audio", trackType_aud);
|
||||
s_pTrackTypes.reset(builder);
|
||||
}
|
||||
wrLocker.unlock();
|
||||
rdLocker.relock();
|
||||
}
|
||||
return (*s_pTrackTypes);
|
||||
}
|
||||
s_avisynthIdx;
|
||||
|
||||
const QMap<QString, QString> &AnalyzeTask::initMimeTypes(void)
|
||||
class AnalyzeTask_StaticInit_MimiTypes : public MUtils::Lazy<const QMap<QString, QString>>
|
||||
{
|
||||
QReadLocker rdLocker(&s_lock);
|
||||
if (s_pMimeTypes.isNull())
|
||||
{
|
||||
rdLocker.unlock();
|
||||
QWriteLocker wrLocker(&s_lock);
|
||||
if (s_pMimeTypes.isNull())
|
||||
virtual QMap<QString, QString> *create()
|
||||
{
|
||||
QMap<QString, QString> *const builder = new QMap<QString, QString>();
|
||||
for (size_t i = 0U; MIME_TYPES[i].type; ++i)
|
||||
{
|
||||
builder->insert(QString::fromLatin1(MIME_TYPES[i].type), QString::fromLatin1(MIME_TYPES[i].ext[0]));
|
||||
}
|
||||
s_pMimeTypes.reset(builder);
|
||||
return builder;
|
||||
}
|
||||
wrLocker.unlock();
|
||||
rdLocker.relock();
|
||||
}
|
||||
s_mimeTypes;
|
||||
|
||||
class AnalyzeTask_StaticInit_TrackTypes : public MUtils::Lazy<const QMap<QString, AnalyzeTask::MI_trackType_t>>
|
||||
{
|
||||
virtual QMap<QString, AnalyzeTask::MI_trackType_t> *create()
|
||||
{
|
||||
QMap<QString, AnalyzeTask::MI_trackType_t> *const builder = new QMap<QString, AnalyzeTask::MI_trackType_t>();
|
||||
builder->insert("general", AnalyzeTask::trackType_gen);
|
||||
builder->insert("audio", AnalyzeTask::trackType_aud);
|
||||
return builder;
|
||||
}
|
||||
return (*s_pMimeTypes);
|
||||
}
|
||||
s_trackTypes;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
AnalyzeTask::AnalyzeTask(const int taskId, const QString &inputFile, QAtomicInt &abortFlag)
|
||||
:
|
||||
m_taskId(taskId),
|
||||
m_inputFile(inputFile),
|
||||
m_mediaInfoBin(lamexp_tools_lookup("mediainfo.exe")),
|
||||
m_mediaInfoVer(lamexp_tools_version("mediainfo.exe")),
|
||||
m_avs2wavBin(lamexp_tools_lookup("avs2wav.exe")),
|
||||
m_abortFlag(abortFlag),
|
||||
m_mediaInfoIdx(*s_mediaInfoIdx),
|
||||
m_avisynthIdx(*s_avisynthIdx),
|
||||
m_mimeTypes(*s_mimeTypes),
|
||||
m_trackTypes(*s_trackTypes)
|
||||
{
|
||||
if(m_mediaInfoBin.isEmpty() || m_avs2wavBin.isEmpty())
|
||||
{
|
||||
qFatal("Invalid path to MediaInfo binary. Tool not initialized properly.");
|
||||
}
|
||||
}
|
||||
|
||||
AnalyzeTask::~AnalyzeTask(void)
|
||||
{
|
||||
emit taskCompleted(m_taskId);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -412,21 +376,36 @@ const AudioFileModel& AnalyzeTask::analyzeMediaFile(const QString &filePath, Aud
|
||||
const AudioFileModel& AnalyzeTask::parseMediaInfo(const QByteArray &data, AudioFileModel &audioFile)
|
||||
{
|
||||
QXmlStreamReader xmlStream(data);
|
||||
bool firstFile = true;
|
||||
bool firstMediaFile = true;
|
||||
|
||||
if (findNextElement(QLatin1String("MediaInfo"), xmlStream))
|
||||
{
|
||||
const QString version = findAttribute(QLatin1String("Version"), xmlStream.attributes());
|
||||
if (version.isEmpty() || (!STRICMP(version, QString().sprintf("0.%u.%02u", m_mediaInfoVer / 100U, m_mediaInfoVer % 100))))
|
||||
const QString versionXml = findAttribute(QLatin1String("Version"), xmlStream.attributes());
|
||||
if (versionXml.isEmpty() || (!checkVersionStr(versionXml, 2U, 0U)))
|
||||
{
|
||||
qWarning("Invalid version property \"%s\" was detected!", MUTILS_UTF8(version));
|
||||
qWarning("Invalid file format version property: \"%s\"", MUTILS_UTF8(versionXml));
|
||||
return audioFile;
|
||||
}
|
||||
while (findNextElement(QLatin1String("File"), xmlStream))
|
||||
if (findNextElement(QLatin1String("CreatingLibrary"), xmlStream))
|
||||
{
|
||||
if (firstFile)
|
||||
const QString versionLib = findAttribute(QLatin1String("Version"), xmlStream.attributes());
|
||||
const QString identifier = xmlStream.readElementText(QXmlStreamReader::SkipChildElements).simplified();
|
||||
if (!STRICMP(identifier, QLatin1String("MediaInfoLib")))
|
||||
{
|
||||
firstFile = false;
|
||||
qWarning("Invalid library identiofier property: \"%s\"", MUTILS_UTF8(identifier));
|
||||
return audioFile;
|
||||
}
|
||||
if (versionLib.isEmpty() || (!checkVersionStr(versionLib, m_mediaInfoVer / 100U, m_mediaInfoVer % 100U)))
|
||||
{
|
||||
qWarning("Invalid library version property: \"%s\"", MUTILS_UTF8(versionLib));
|
||||
return audioFile;
|
||||
}
|
||||
while (findNextElement(QLatin1String("Media"), xmlStream))
|
||||
{
|
||||
qWarning("Found a media!");
|
||||
if (firstMediaFile || audioFile.techInfo().containerType().isEmpty() || audioFile.techInfo().audioType().isEmpty())
|
||||
{
|
||||
firstMediaFile = false;
|
||||
parseFileInfo(xmlStream, audioFile);
|
||||
}
|
||||
else
|
||||
@ -436,6 +415,7 @@ const AudioFileModel& AnalyzeTask::parseMediaInfo(const QByteArray &data, AudioF
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(audioFile.techInfo().containerType().isEmpty() || audioFile.techInfo().audioType().isEmpty()))
|
||||
{
|
||||
@ -473,6 +453,7 @@ void AnalyzeTask::parseFileInfo(QXmlStreamReader &xmlStream, AudioFileModel &aud
|
||||
MI_trackType_t trackType;
|
||||
while (findNextElement(QLatin1String("Track"), xmlStream))
|
||||
{
|
||||
qWarning("Found a track!");
|
||||
const QString typeString = findAttribute(QLatin1String("Type"), xmlStream.attributes());
|
||||
if ((trackType = m_trackTypes.value(typeString.toLower(), MI_trackType_t(-1))) != MI_trackType_t(-1))
|
||||
{
|
||||
@ -785,6 +766,23 @@ QString AnalyzeTask::findAttribute(const QString &name, const QXmlStreamAttribut
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool AnalyzeTask::checkVersionStr(const QString &str, const quint32 expectedMajor, const quint32 expectedMinor)
|
||||
{
|
||||
QRegExp version("^(\\d+)\\.(\\d+)($|\\.)");
|
||||
if (version.indexIn(str) >= 0)
|
||||
{
|
||||
quint32 actual[2];
|
||||
if (MUtils::regexp_parse_uint32(version, actual, 2))
|
||||
{
|
||||
if ((actual[0] == expectedMajor) && (actual[1] >= expectedMinor))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Public Functions
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -57,7 +57,6 @@ public:
|
||||
}
|
||||
fileType_t;
|
||||
|
||||
protected:
|
||||
typedef enum
|
||||
{
|
||||
trackType_non = 0,
|
||||
@ -111,11 +110,6 @@ private:
|
||||
bool checkFile_CDDA(QFile &file);
|
||||
bool analyzeAvisynthFile(const QString &filePath, AudioFileModel &info);
|
||||
|
||||
static const QMap<QPair<MI_trackType_t, QString>, MI_propertyId_t> &initMediaInfoIdx(void);
|
||||
static const QMap<QString, MI_propertyId_t> &initAvisynthIdx(void);
|
||||
static const QMap<QString, QString> &initMimeTypes(void);
|
||||
static const QMap<QString, MI_trackType_t> &initTrackTypes(void);
|
||||
|
||||
static QString decodeStr(const QString &str, const QString &encoding);
|
||||
static bool parseUnsigned(const QString &str, quint32 &value);
|
||||
static bool parseDuration(const QString &str, quint32 &value);
|
||||
@ -124,6 +118,7 @@ private:
|
||||
static QString cleanAsciiStr(const QString &str);
|
||||
static bool findNextElement(const QString &name, QXmlStreamReader &xmlStream);
|
||||
static QString findAttribute(const QString &name, const QXmlStreamAttributes &xmlAttributes);
|
||||
static bool checkVersionStr(const QString &str, const quint32 expectedMajor, const quint32 expectedMinor);
|
||||
|
||||
const QMap<QPair<MI_trackType_t, QString>, MI_propertyId_t> &m_mediaInfoIdx;
|
||||
const QMap<QString, MI_propertyId_t> &m_avisynthIdx;
|
||||
@ -137,10 +132,4 @@ private:
|
||||
const QString m_inputFile;
|
||||
|
||||
QAtomicInt &m_abortFlag;
|
||||
|
||||
static QReadWriteLock s_lock;
|
||||
static QScopedPointer<const QMap<QPair<MI_trackType_t, QString>, MI_propertyId_t>> s_pMediaInfoIdx;
|
||||
static QScopedPointer<const QMap<QString, MI_propertyId_t>> s_pAvisynthIdx;
|
||||
static QScopedPointer<const QMap<QString, QString>> s_pMimeTypes;
|
||||
static QScopedPointer<const QMap<QString, MI_trackType_t>> s_pTrackTypes;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user