Explicitly pass MIME type to OpenEnc when adding cover artwork via "--picture" option.

This commit is contained in:
LoRd_MuldeR 2015-08-27 22:52:00 +02:00
parent 6bc9126295
commit 281c94026d
10 changed files with 118 additions and 57 deletions

View 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_Static|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild> </CustomBuild>
<ClInclude Include="src\MimeTypes.h" />
<ClInclude Include="tmp\LameXP\UIC_AboutDialog.h" /> <ClInclude Include="tmp\LameXP\UIC_AboutDialog.h" />
<ClInclude Include="tmp\LameXP\UIC_CueSheetImport.h" /> <ClInclude Include="tmp\LameXP\UIC_CueSheetImport.h" />
<ClInclude Include="tmp\LameXP\UIC_DropBox.h" /> <ClInclude Include="tmp\LameXP\UIC_DropBox.h" />

View File

@ -552,6 +552,9 @@
<ClInclude Include="src\IPCCommands.h"> <ClInclude Include="src\IPCCommands.h">
<Filter>Header Files\Misc</Filter> <Filter>Header Files\Misc</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\MimeTypes.h">
<Filter>Header Files\Misc</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="gui\DropBox.ui"> <CustomBuild Include="gui\DropBox.ui">

View 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_Static|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild> </CustomBuild>
<ClInclude Include="src\MimeTypes.h" />
<ClInclude Include="tmp\LameXP\UIC_AboutDialog.h" /> <ClInclude Include="tmp\LameXP\UIC_AboutDialog.h" />
<ClInclude Include="tmp\LameXP\UIC_CueSheetImport.h" /> <ClInclude Include="tmp\LameXP\UIC_CueSheetImport.h" />
<ClInclude Include="tmp\LameXP\UIC_DropBox.h" /> <ClInclude Include="tmp\LameXP\UIC_DropBox.h" />

View File

@ -552,6 +552,9 @@
<ClInclude Include="src\IPCCommands.h"> <ClInclude Include="src\IPCCommands.h">
<Filter>Header Files\Misc</Filter> <Filter>Header Files\Misc</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\MimeTypes.h">
<Filter>Header Files\Misc</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="gui\DropBox.ui"> <CustomBuild Include="gui\DropBox.ui">

View File

@ -35,7 +35,7 @@
#define VER_LAMEXP_MINOR_LO 2 #define VER_LAMEXP_MINOR_LO 2
#define VER_LAMEXP_TYPE Beta #define VER_LAMEXP_TYPE Beta
#define VER_LAMEXP_PATCH 5 #define VER_LAMEXP_PATCH 5
#define VER_LAMEXP_BUILD 1794 #define VER_LAMEXP_BUILD 1795
#define VER_LAMEXP_CONFG 1700 #define VER_LAMEXP_CONFG 1700
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -22,9 +22,15 @@
#include "Encoder_Opus.h" #include "Encoder_Opus.h"
//MUtils
#include <MUtils/Global.h>
//Internal
#include "Global.h" #include "Global.h"
#include "Model_Settings.h" #include "Model_Settings.h"
#include "MimeTypes.h"
//Qt
#include <QProcess> #include <QProcess>
#include <QDir> #include <QDir>
#include <QUUid> #include <QUUid>
@ -183,8 +189,7 @@ bool OpusEncoder::encode(const QString &sourceFile, const AudioFileModel_MetaInf
if(metaInfo.year()) args << "--date" << QString::number(metaInfo.year()); if(metaInfo.year()) args << "--date" << QString::number(metaInfo.year());
if(metaInfo.position()) args << "--comment" << QString("tracknumber=%1").arg(QString::number(metaInfo.position())); 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.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); if(!m_configCustomParams.isEmpty()) args << m_configCustomParams.split(" ", QString::SkipEmptyParts);
@ -259,6 +264,29 @@ bool OpusEncoder::encode(const QString &sourceFile, const AudioFileModel_MetaInf
return true; 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) void OpusEncoder::setOptimizeFor(int optimizeFor)
{ {
m_configOptimizeFor = qBound(0, optimizeFor, 2); m_configOptimizeFor = qBound(0, optimizeFor, 2);

View File

@ -55,4 +55,7 @@ private:
int m_configOptimizeFor; int m_configOptimizeFor;
int m_configEncodeComplexity; int m_configEncodeComplexity;
int m_configFrameSize; int m_configFrameSize;
static inline QString detectMimeType(const QString &coverFile);
static inline QString makeCoverParam(const QString &coverFile);
}; };

39
src/MimeTypes.h Normal file
View File

@ -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;

View File

@ -26,6 +26,7 @@
#include "Global.h" #include "Global.h"
#include "LockedFile.h" #include "LockedFile.h"
#include "Model_AudioFile.h" #include "Model_AudioFile.h"
#include "MimeTypes.h"
//MUtils //MUtils
#include <MUtils/Global.h> #include <MUtils/Global.h>
@ -178,8 +179,8 @@ const AudioFileModel AnalyzeTask::analyzeFile(const QString &filePath, int *type
readTest.close(); readTest.close();
bool skipNext = false; bool skipNext = false;
unsigned int id_val[2] = {UINT_MAX, UINT_MAX}; QPair<quint32, quint32> id_val(UINT_MAX, UINT_MAX);
cover_t coverType = coverNone; quint32 coverType = UINT_MAX;
QByteArray coverData; QByteArray coverData;
QStringList params; QStringList params;
@ -236,7 +237,7 @@ const AudioFileModel AnalyzeTask::analyzeFile(const QString &filePath, int *type
QString val = line.mid(index+1).trimmed(); QString val = line.mid(index+1).trimmed();
if(!key.isEmpty()) 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); process.waitForFinished(-1);
} }
if((coverType != coverNone) && (!coverData.isEmpty())) if((coverType != UINT_MAX) && (!coverData.isEmpty()))
{ {
retrieveCover(audioFile, coverType, coverData); retrieveCover(audioFile, coverType, coverData);
} }
@ -284,7 +285,7 @@ const AudioFileModel AnalyzeTask::analyzeFile(const QString &filePath, int *type
return audioFile; 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)); //qWarning("'%s' -> '%s'", MUTILS_UTF8(key), MUTILS_UTF8(value));
@ -293,7 +294,7 @@ void AnalyzeTask::updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned
{ {
if(value.isEmpty()) if(value.isEmpty())
{ {
*skipNext = false; skipNext = false;
} }
else else
{ {
@ -302,15 +303,15 @@ void AnalyzeTask::updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned
unsigned int id = value.toUInt(&ok); unsigned int id = value.toUInt(&ok);
if(ok) if(ok)
{ {
if(IS_KEY("Gen_ID")) { id_val[0] = qMin(id_val[0], id); *skipNext = (id > id_val[0]); } 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[1] = qMin(id_val[1], id); *skipNext = (id > id_val[1]); } if(IS_KEY("Aud_ID")) { id_val.second = qMin(id_val.second, id); skipNext = (id > id_val.second); }
} }
else else
{ {
*skipNext = true; skipNext = true;
} }
} }
if(*skipNext) if(skipNext)
{ {
qWarning("Skipping info for non-primary stream!"); qWarning("Skipping info for non-primary stream!");
} }
@ -318,7 +319,7 @@ void AnalyzeTask::updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned
} }
/*Skip or empty?*/ /*Skip or empty?*/
if((*skipNext) || value.isEmpty()) if((skipNext) || value.isEmpty())
{ {
return; return;
} }
@ -326,7 +327,7 @@ void AnalyzeTask::updateInfo(AudioFileModel &audioFile, bool *skipNext, unsigned
/*Playlist file?*/ /*Playlist file?*/
if(IS_KEY("Aud_Source")) if(IS_KEY("Aud_Source"))
{ {
*skipNext = true; skipNext = true;
audioFile.techInfo().setContainerType(QString()); audioFile.techInfo().setContainerType(QString());
audioFile.techInfo().setAudioType(QString()); audioFile.techInfo().setAudioType(QString());
qWarning("Skipping info for playlist file!"); 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")) 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")) else if(IS_KEY("Gen_Cover_Mime"))
{ {
QString temp = FIRST_TOK(value); QString temp = FIRST_TOK(value);
if(!temp.compare("image/jpeg", Qt::CaseInsensitive)) *coverType = coverJpeg; for (quint32 i = 0; MIME_TYPES[i].type; i++)
else if(!temp.compare("image/png", Qt::CaseInsensitive)) *coverType = coverPng; {
else if(!temp.compare("image/gif", Qt::CaseInsensitive)) *coverType = coverGif; if (temp.compare(QString::fromLatin1(MIME_TYPES[i].type), Qt::CaseInsensitive) == 0)
{
coverType = i;
break;
}
}
} }
else if(IS_KEY("Gen_Cover_Data")) else if(IS_KEY("Gen_Cover_Data"))
{ {
if(!coverData->isEmpty()) coverData->clear(); if(!coverData.isEmpty()) coverData.clear();
coverData->append(QByteArray::fromBase64(FIRST_TOK(value).toLatin1())); coverData.append(QByteArray::fromBase64(FIRST_TOK(value).toLatin1()));
} }
else else
{ {
@ -483,27 +489,14 @@ bool AnalyzeTask::checkFile_CDDA(QFile &file)
return ((i >= 0) && (j >= 0) && (k >= 0) && (k > j) && (j > i)); 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!"); qDebug("Retrieving cover! (MIME_TYPES_MAX=%u)", MIME_TYPES_MAX);
QString extension;
switch(coverType) 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()))
{ {
case coverPng: QFile coverFile(QString("%1/%2.%3").arg(MUtils::temp_folder(), MUtils::rand_str(), ext));
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(MUtils::temp_folder(), MUtils::rand_str(), extension));
if(coverFile.open(QIODevice::WriteOnly)) if(coverFile.open(QIODevice::WriteOnly))
{ {
coverFile.write(coverData); coverFile.write(coverData);

View File

@ -28,6 +28,7 @@
#include <QStringList> #include <QStringList>
#include <QMutex> #include <QMutex>
#include <QSemaphore> #include <QSemaphore>
#include <QPair>
class AudioFileModel; class AudioFileModel;
class QFile; class QFile;
@ -56,9 +57,6 @@ public:
fileTypeUnknown = 4 fileTypeUnknown = 4
}; };
//Wait until there is a free slot in the queue
static bool waitForFreeSlot(volatile bool *abortFlag);
signals: signals:
void fileAnalyzed(const unsigned int taskId, const int fileType, const AudioFileModel &file); void fileAnalyzed(const unsigned int taskId, const int fileType, const AudioFileModel &file);
void taskCompleted(const unsigned int taskId); void taskCompleted(const unsigned int taskId);
@ -68,20 +66,12 @@ protected:
void run_ex(void); void run_ex(void);
private: private:
enum cover_t
{
coverNone,
coverJpeg,
coverPng,
coverGif
};
const AudioFileModel analyzeFile(const QString &filePath, int *type); 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 parseYear(const QString &str);
unsigned int parseDuration(const QString &str); unsigned int parseDuration(const QString &str);
bool checkFile_CDDA(QFile &file); 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); bool analyzeAvisynthFile(const QString &filePath, AudioFileModel &info);
const unsigned int m_taskId; const unsigned int m_taskId;