diff --git a/LameXP_VS2013.vcxproj b/LameXP_VS2013.vcxproj
index 8da703a3..3735619b 100644
--- a/LameXP_VS2013.vcxproj
+++ b/LameXP_VS2013.vcxproj
@@ -439,6 +439,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)
$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)
+
diff --git a/LameXP_VS2013.vcxproj.filters b/LameXP_VS2013.vcxproj.filters
index 356678c4..c175cdb1 100644
--- a/LameXP_VS2013.vcxproj.filters
+++ b/LameXP_VS2013.vcxproj.filters
@@ -552,6 +552,9 @@
Header Files\Misc
+
+ Header Files\Misc
+
diff --git a/LameXP_VS2015.vcxproj b/LameXP_VS2015.vcxproj
index 09a0fb7b..cbe358fd 100644
--- a/LameXP_VS2015.vcxproj
+++ b/LameXP_VS2015.vcxproj
@@ -439,6 +439,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)
$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)
+
diff --git a/LameXP_VS2015.vcxproj.filters b/LameXP_VS2015.vcxproj.filters
index 356678c4..c175cdb1 100644
--- a/LameXP_VS2015.vcxproj.filters
+++ b/LameXP_VS2015.vcxproj.filters
@@ -552,6 +552,9 @@
Header Files\Misc
+
+ Header Files\Misc
+
diff --git a/src/Config.h b/src/Config.h
index 16748667..6d5d28ad 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -35,7 +35,7 @@
#define VER_LAMEXP_MINOR_LO 2
#define VER_LAMEXP_TYPE Beta
#define VER_LAMEXP_PATCH 5
-#define VER_LAMEXP_BUILD 1794
+#define VER_LAMEXP_BUILD 1795
#define VER_LAMEXP_CONFG 1700
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/Encoder_Opus.cpp b/src/Encoder_Opus.cpp
index ef9e863b..d5788cd8 100644
--- a/src/Encoder_Opus.cpp
+++ b/src/Encoder_Opus.cpp
@@ -22,9 +22,15 @@
#include "Encoder_Opus.h"
+//MUtils
+#include
+
+//Internal
#include "Global.h"
#include "Model_Settings.h"
+#include "MimeTypes.h"
+//Qt
#include
#include
#include
@@ -183,9 +189,8 @@ bool OpusEncoder::encode(const QString &sourceFile, const AudioFileModel_MetaInf
if(metaInfo.year()) args << "--date" << QString::number(metaInfo.year());
if(metaInfo.position()) args << "--comment" << QString("tracknumber=%1").arg(QString::number(metaInfo.position()));
if(!metaInfo.comment().isEmpty()) args << "--comment" << QString("comment=%1").arg(cleanTag(metaInfo.comment()));
- if(!metaInfo.cover().isEmpty()) args << "--picture" << QDir::toNativeSeparators(metaInfo.cover());
+ if(!metaInfo.cover().isEmpty()) args << "--picture" << makeCoverParam(metaInfo.cover());
-
if(!m_configCustomParams.isEmpty()) args << m_configCustomParams.split(" ", QString::SkipEmptyParts);
args << QDir::toNativeSeparators(sourceFile);
@@ -259,6 +264,29 @@ bool OpusEncoder::encode(const QString &sourceFile, const AudioFileModel_MetaInf
return true;
}
+QString OpusEncoder::detectMimeType(const QString &coverFile)
+{
+ const QString suffix = QFileInfo(coverFile).suffix();
+ for (size_t i = 0; MIME_TYPES[i].type; i++)
+ {
+ for (size_t k = 0; MIME_TYPES[i].ext[k]; k++)
+ {
+ if (suffix.compare(QString::fromLatin1(MIME_TYPES[i].ext[k]), Qt::CaseInsensitive) == 0)
+ {
+ return QString::fromLatin1(MIME_TYPES[i].type);
+ }
+ }
+ }
+
+ qWarning("Unknown MIME type for extension '%s' -> using default!", MUTILS_UTF8(coverFile));
+ return QString::fromLatin1(MIME_TYPES[0].type);
+}
+
+QString OpusEncoder::makeCoverParam(const QString &coverFile)
+{
+ return QString("3|%1|||%2").arg(detectMimeType(coverFile), QDir::toNativeSeparators(coverFile));
+}
+
void OpusEncoder::setOptimizeFor(int optimizeFor)
{
m_configOptimizeFor = qBound(0, optimizeFor, 2);
diff --git a/src/Encoder_Opus.h b/src/Encoder_Opus.h
index f2ee35a5..4c21c8e6 100644
--- a/src/Encoder_Opus.h
+++ b/src/Encoder_Opus.h
@@ -55,4 +55,7 @@ private:
int m_configOptimizeFor;
int m_configEncodeComplexity;
int m_configFrameSize;
+
+ static inline QString detectMimeType(const QString &coverFile);
+ static inline QString makeCoverParam(const QString &coverFile);
};
diff --git a/src/MimeTypes.h b/src/MimeTypes.h
new file mode 100644
index 00000000..700a56af
--- /dev/null
+++ b/src/MimeTypes.h
@@ -0,0 +1,39 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// Copyright (C) 2004-2015 LoRd_MuldeR
+//
+// 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, 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
+// 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
+///////////////////////////////////////////////////////////////////////////////
+
+#include
+
+static const struct
+{
+ const char *type;
+ const char *ext[8];
+}
+MIME_TYPES[] =
+{
+ { "image/jpeg", { "jpg", "jpeg", "jpe", NULL } },
+ { "image/png", { "png", NULL } },
+ { "image/gif", { "gif", NULL } },
+ { "image/tiff", { "tif", "tiff", NULL } },
+ { NULL, { NULL } }
+};
+
+static const size_t MIME_TYPES_MAX = (sizeof(MIME_TYPES) / sizeof(MIME_TYPES[0])) - 2;
diff --git a/src/Thread_FileAnalyzer_Task.cpp b/src/Thread_FileAnalyzer_Task.cpp
index cc1f7b5a..003bff5b 100644
--- a/src/Thread_FileAnalyzer_Task.cpp
+++ b/src/Thread_FileAnalyzer_Task.cpp
@@ -26,6 +26,7 @@
#include "Global.h"
#include "LockedFile.h"
#include "Model_AudioFile.h"
+#include "MimeTypes.h"
//MUtils
#include
@@ -178,8 +179,8 @@ const AudioFileModel AnalyzeTask::analyzeFile(const QString &filePath, int *type
readTest.close();
bool skipNext = false;
- unsigned int id_val[2] = {UINT_MAX, UINT_MAX};
- cover_t coverType = coverNone;
+ QPair id_val(UINT_MAX, UINT_MAX);
+ quint32 coverType = UINT_MAX;
QByteArray coverData;
QStringList params;
@@ -236,7 +237,7 @@ const AudioFileModel AnalyzeTask::analyzeFile(const QString &filePath, int *type
QString val = line.mid(index+1).trimmed();
if(!key.isEmpty())
{
- updateInfo(audioFile, &skipNext, id_val, &coverType, &coverData, key, val);
+ updateInfo(audioFile, skipNext, id_val, coverType, coverData, key, val);
}
}
}
@@ -271,7 +272,7 @@ const AudioFileModel AnalyzeTask::analyzeFile(const QString &filePath, int *type
process.waitForFinished(-1);
}
- if((coverType != coverNone) && (!coverData.isEmpty()))
+ if((coverType != UINT_MAX) && (!coverData.isEmpty()))
{
retrieveCover(audioFile, coverType, coverData);
}
@@ -284,7 +285,7 @@ const AudioFileModel AnalyzeTask::analyzeFile(const QString &filePath, int *type
return audioFile;
}
-void AnalyzeTask::updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned int *id_val, cover_t *coverType, QByteArray *coverData, const QString &key, const QString &value)
+void AnalyzeTask::updateInfo(AudioFileModel &audioFile, bool &skipNext, QPair &id_val, quint32 &coverType, QByteArray &coverData, const QString &key, const QString &value)
{
//qWarning("'%s' -> '%s'", MUTILS_UTF8(key), MUTILS_UTF8(value));
@@ -293,7 +294,7 @@ void AnalyzeTask::updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned
{
if(value.isEmpty())
{
- *skipNext = false;
+ skipNext = false;
}
else
{
@@ -302,15 +303,15 @@ void AnalyzeTask::updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned
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]); }
+ if(IS_KEY("Gen_ID")) { id_val.first = qMin(id_val.first, id); skipNext = (id > id_val.first); }
+ if(IS_KEY("Aud_ID")) { id_val.second = qMin(id_val.second, id); skipNext = (id > id_val.second); }
}
else
{
- *skipNext = true;
+ skipNext = true;
}
}
- if(*skipNext)
+ if(skipNext)
{
qWarning("Skipping info for non-primary stream!");
}
@@ -318,7 +319,7 @@ void AnalyzeTask::updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned
}
/*Skip or empty?*/
- if((*skipNext) || value.isEmpty())
+ if((skipNext) || value.isEmpty())
{
return;
}
@@ -326,7 +327,7 @@ void AnalyzeTask::updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned
/*Playlist file?*/
if(IS_KEY("Aud_Source"))
{
- *skipNext = true;
+ skipNext = true;
audioFile.techInfo().setContainerType(QString());
audioFile.techInfo().setAudioType(QString());
qWarning("Skipping info for playlist file!");
@@ -382,22 +383,27 @@ void AnalyzeTask::updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned
}
else if(IS_KEY("Gen_Cover") || IS_KEY("Gen_Cover_Type"))
{
- if(*coverType == coverNone)
+ if(coverType == UINT_MAX)
{
- *coverType = coverJpeg;
+ coverType = 0;
}
}
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;
+ for (quint32 i = 0; MIME_TYPES[i].type; i++)
+ {
+ if (temp.compare(QString::fromLatin1(MIME_TYPES[i].type), Qt::CaseInsensitive) == 0)
+ {
+ coverType = i;
+ break;
+ }
+ }
}
else if(IS_KEY("Gen_Cover_Data"))
{
- if(!coverData->isEmpty()) coverData->clear();
- coverData->append(QByteArray::fromBase64(FIRST_TOK(value).toLatin1()));
+ if(!coverData.isEmpty()) coverData.clear();
+ coverData.append(QByteArray::fromBase64(FIRST_TOK(value).toLatin1()));
}
else
{
@@ -483,27 +489,14 @@ bool AnalyzeTask::checkFile_CDDA(QFile &file)
return ((i >= 0) && (j >= 0) && (k >= 0) && (k > j) && (j > i));
}
-void AnalyzeTask::retrieveCover(AudioFileModel &audioFile, cover_t coverType, const QByteArray &coverData)
+void AnalyzeTask::retrieveCover(AudioFileModel &audioFile, const quint32 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;
- }
+ qDebug("Retrieving cover! (MIME_TYPES_MAX=%u)", MIME_TYPES_MAX);
- if(!(QImage::fromData(coverData, extension.toUpper().toLatin1().constData()).isNull()))
+ static const QString ext = QString::fromLatin1(MIME_TYPES[qBound(0U, coverType, MIME_TYPES_MAX)].ext[0]);
+ if(!(QImage::fromData(coverData, ext.toUpper().toLatin1().constData()).isNull()))
{
- QFile coverFile(QString("%1/%2.%3").arg(MUtils::temp_folder(), MUtils::rand_str(), extension));
+ QFile coverFile(QString("%1/%2.%3").arg(MUtils::temp_folder(), MUtils::rand_str(), ext));
if(coverFile.open(QIODevice::WriteOnly))
{
coverFile.write(coverData);
diff --git a/src/Thread_FileAnalyzer_Task.h b/src/Thread_FileAnalyzer_Task.h
index 3cc86784..cf600090 100644
--- a/src/Thread_FileAnalyzer_Task.h
+++ b/src/Thread_FileAnalyzer_Task.h
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
class AudioFileModel;
class QFile;
@@ -49,16 +50,13 @@ public:
enum fileType_t
{
- fileTypeNormal = 0,
- fileTypeCDDA = 1,
- fileTypeDenied = 2,
+ fileTypeNormal = 0,
+ fileTypeCDDA = 1,
+ fileTypeDenied = 2,
fileTypeCueSheet = 3,
- fileTypeUnknown = 4
+ fileTypeUnknown = 4
};
- //Wait until there is a free slot in the queue
- static bool waitForFreeSlot(volatile bool *abortFlag);
-
signals:
void fileAnalyzed(const unsigned int taskId, const int fileType, const AudioFileModel &file);
void taskCompleted(const unsigned int taskId);
@@ -68,20 +66,12 @@ protected:
void run_ex(void);
private:
- enum cover_t
- {
- coverNone,
- coverJpeg,
- coverPng,
- coverGif
- };
-
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);
+ void updateInfo(AudioFileModel &audioFile, bool &skipNext, QPair &id_val, quint32 &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);
+ void retrieveCover(AudioFileModel &audioFile, const quint32 coverType, const QByteArray &coverData);
bool analyzeAvisynthFile(const QString &filePath, AudioFileModel &info);
const unsigned int m_taskId;