OSDN Git Service

Explicitly pass MIME type to OpenEnc when adding cover artwork via "--picture" option.
authorLoRd_MuldeR <mulder2@gmx.de>
Thu, 27 Aug 2015 20:52:00 +0000 (22:52 +0200)
committerLoRd_MuldeR <mulder2@gmx.de>
Thu, 27 Aug 2015 20:52:00 +0000 (22:52 +0200)
LameXP_VS2013.vcxproj
LameXP_VS2013.vcxproj.filters
LameXP_VS2015.vcxproj
LameXP_VS2015.vcxproj.filters
src/Config.h
src/Encoder_Opus.cpp
src/Encoder_Opus.h
src/MimeTypes.h [new file with mode: 0644]
src/Thread_FileAnalyzer_Task.cpp
src/Thread_FileAnalyzer_Task.h

index 8da703a..3735619 100644 (file)
@@ -439,6 +439,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
     </CustomBuild>
+    <ClInclude Include="src\MimeTypes.h" />
     <ClInclude Include="tmp\LameXP\UIC_AboutDialog.h" />
     <ClInclude Include="tmp\LameXP\UIC_CueSheetImport.h" />
     <ClInclude Include="tmp\LameXP\UIC_DropBox.h" />
index 356678c..c175cdb 100644 (file)
     <ClInclude Include="src\IPCCommands.h">
       <Filter>Header Files\Misc</Filter>
     </ClInclude>
+    <ClInclude Include="src\MimeTypes.h">
+      <Filter>Header Files\Misc</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="gui\DropBox.ui">
index 09a0fb7..cbe358f 100644 (file)
@@ -439,6 +439,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
     </CustomBuild>
+    <ClInclude Include="src\MimeTypes.h" />
     <ClInclude Include="tmp\LameXP\UIC_AboutDialog.h" />
     <ClInclude Include="tmp\LameXP\UIC_CueSheetImport.h" />
     <ClInclude Include="tmp\LameXP\UIC_DropBox.h" />
index 356678c..c175cdb 100644 (file)
     <ClInclude Include="src\IPCCommands.h">
       <Filter>Header Files\Misc</Filter>
     </ClInclude>
+    <ClInclude Include="src\MimeTypes.h">
+      <Filter>Header Files\Misc</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <CustomBuild Include="gui\DropBox.ui">
index 1674866..6d5d28a 100644 (file)
@@ -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
 
 ///////////////////////////////////////////////////////////////////////////////
index ef9e863..d5788cd 100644 (file)
 
 #include "Encoder_Opus.h"
 
+//MUtils
+#include <MUtils/Global.h>
+
+//Internal
 #include "Global.h"
 #include "Model_Settings.h"
+#include "MimeTypes.h"
 
+//Qt
 #include <QProcess>
 #include <QDir>
 #include <QUUid>
@@ -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);
index f2ee35a..4c21c8e 100644 (file)
@@ -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 (file)
index 0000000..700a56a
--- /dev/null
@@ -0,0 +1,39 @@
+///////////////////////////////////////////////////////////////////////////////
+// LameXP - Audio Encoder Front-End
+// 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, 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 <cstdlib>
+
+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;
index cc1f7b5..003bff5 100644 (file)
@@ -26,6 +26,7 @@
 #include "Global.h"
 #include "LockedFile.h"
 #include "Model_AudioFile.h"
+#include "MimeTypes.h"
 
 //MUtils
 #include <MUtils/Global.h>
@@ -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<quint32, quint32> 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<quint32, quint32> &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);
index 3cc8678..cf60009 100644 (file)
@@ -28,6 +28,7 @@
 #include <QStringList>
 #include <QMutex>
 #include <QSemaphore>
+#include <QPair>
 
 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<quint32, quint32> &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;