diff --git a/ChangeLog b/ChangeLog index 2f194e7db..0be3845d7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,9 @@ -1.1.1 +1.2.0 +----- +1. Add support for opus audio format - AudioCD encoding, transcoding, HTTP + server, etc. + +1.1.1 ----- 1. Fix crash in settings dialog if current connection name is removed from config file. diff --git a/devices/encoders.cpp b/devices/encoders.cpp index ae5f01c9d..d2a97c197 100644 --- a/devices/encoders.cpp +++ b/devices/encoders.cpp @@ -27,7 +27,6 @@ #include "localize.h" #include #include -#include namespace Encoders { @@ -100,16 +99,16 @@ static void init() QLatin1String("-aq"), i18n("Expected average bitrate for variable bitrate encoding"), QList() << Setting(i18n(vbr, 25), 30) - << Setting(i18n(vbr, 50), 55) - << Setting(i18n(vbr, 70), 80) - << Setting(i18n(vbr, 90), 105) - << Setting(i18n(vbr, 120), 125) - << Setting(i18n(vbr, 150), 155) - << Setting(i18n(vbr, 170), 180) - << Setting(i18n(vbr, 180), 205) - << Setting(i18n(vbr, 190), 230) - << Setting(i18n(vbr, 200), 255) - << Setting(i18n(vbr, 210), 280), + << Setting(i18n(vbr, 50), 55) + << Setting(i18n(vbr, 70), 80) + << Setting(i18n(vbr, 90), 105) + << Setting(i18n(vbr, 120), 125) + << Setting(i18n(vbr, 150), 155) + << Setting(i18n(vbr, 170), 180) + << Setting(i18n(vbr, 180), 205) + << Setting(i18n(vbr, 190), 230) + << Setting(i18n(vbr, 200), 255) + << Setting(i18n(vbr, 210), 280), i18n("Smaller file"), i18n("Better sound quality"), 5); @@ -183,21 +182,58 @@ static void init() QLatin1String("-aq"), i18n("Quality rating"), QList() << Setting(i18n(quality, -1, 45), -1) - << Setting(i18n(quality, 0, 64), 0) - << Setting(i18n(quality, 1, 80), 1) - << Setting(i18n(quality, 2, 96), 2) - << Setting(i18n(quality, 3, 112), 3) - << Setting(i18n(quality, 4, 128), 4) - << Setting(i18n(quality, 5, 160), 5) - << Setting(i18n(quality, 6, 192), 6) - << Setting(i18n(quality, 7, 224), 7) - << Setting(i18n(quality, 8, 256), 8) - << Setting(i18n(quality, 9, 320), 9) - << Setting(i18n(quality, 10, 500), 10), + << Setting(i18n(quality, 0, 64), 0) + << Setting(i18n(quality, 1, 80), 1) + << Setting(i18n(quality, 2, 96), 2) + << Setting(i18n(quality, 3, 112), 3) + << Setting(i18n(quality, 4, 128), 4) + << Setting(i18n(quality, 5, 160), 5) + << Setting(i18n(quality, 6, 192), 6) + << Setting(i18n(quality, 7, 224), 7) + << Setting(i18n(quality, 8, 256), 8) + << Setting(i18n(quality, 9, 320), 9) + << Setting(i18n(quality, 10, 500), 10), i18n("Smaller file"), i18n("Better sound quality"), 6); + Encoder opus(i18n("Opus"), + i18nc("Feel free to redirect the english Wikipedia link to a local version, if " + "it exists.", + "Opus is " + "a patent-free digital audio codec using a form of lossy data compression."), + i18n("The bitrate is a measure of the quantity of data used to represent a " + "second of the audio track.
The Opus encoder used by Cantata supports " + "a variable bitrate (VBR) " + "setting, which means that the bitrate value fluctuates along the track " + "based on the complexity of the audio content. More complex intervals of " + "data are encoded with a higher bitrate than less complex ones; this " + "approach yields overall better quality and a smaller file than having a " + "constant bitrate throughout the track.
" + "For this reason, the bitrate measure in this slider is just an estimate " + "of the average bitrate of the encoded track.
" + "128kb/s is a good choice for music listening on a portable player.
" + "Anything below 100kb/s might be unsatisfactory for music and anything above " + "256kb/s is probably overkill."), + QLatin1String("opus"), + command, + QLatin1String("libopus"), + QLatin1String("-ab"), + i18n("Bitrate"), + QList() << Setting(i18n(vbr, 32), 32) + << Setting(i18n(vbr, 64), 64) + << Setting(i18n(vbr, 96), 96) + << Setting(i18n(vbr, 128), 128) + << Setting(i18n(vbr, 160), 160) + << Setting(i18n(vbr, 192), 192) + << Setting(i18n(vbr, 256), 256) + << Setting(i18n(vbr, 320), 320) + << Setting(i18n(vbr, 360), 360), + i18n("Smaller file"), + i18n("Better sound quality"), + 4, + 1000); + if (!command.isEmpty()) { QList initial; initial.append(aac); @@ -244,19 +280,20 @@ static void init() QLatin1String("-compression_level"), i18n("Compression level"), QList() << Setting(QString::number(0), 0) - << Setting(QString::number(1), 1) - << Setting(QString::number(2), 2) - << Setting(QString::number(3), 3) - << Setting(QString::number(4), 4) - << Setting(QString::number(5), 5) - << Setting(QString::number(6), 6) - << Setting(QString::number(7), 7) - << Setting(QString::number(8), 8), + << Setting(QString::number(1), 1) + << Setting(QString::number(2), 2) + << Setting(QString::number(3), 3) + << Setting(QString::number(4), 4) + << Setting(QString::number(5), 5) + << Setting(QString::number(6), 6) + << Setting(QString::number(7), 7) + << Setting(QString::number(8), 8), i18n("Faster compression"), i18n("Smaller file"), 5)); initial.append(lame); initial.append(ogg); + initial.append(opus); initial.append( Encoder(i18n("Windows Media Audio"), i18nc("Feel free to redirect the english Wikipedia link to a local version, if " @@ -280,17 +317,18 @@ static void init() QLatin1String("wmav2"), QLatin1String("-ab"), i18n("Bitrate"), - QList() << Setting(i18n(cbr, 64), 65*1000) - << Setting(i18n(cbr, 80), 75*1000) - << Setting(i18n(cbr, 96), 88*1000) - << Setting(i18n(cbr, 112), 106*1000) - << Setting(i18n(cbr, 136), 133*1000) - << Setting(i18n(cbr, 182), 180*1000) - << Setting(i18n(cbr, 275), 271*1000) - << Setting(i18n(cbr, 550), 545*1000), + QList() << Setting(i18n(cbr, 64), 65) + << Setting(i18n(cbr, 80), 75) + << Setting(i18n(cbr, 96), 88) + << Setting(i18n(cbr, 112), 106) + << Setting(i18n(cbr, 136), 133) + << Setting(i18n(cbr, 182), 180) + << Setting(i18n(cbr, 275), 271) + << Setting(i18n(cbr, 550), 545), i18n("Smaller file"), i18n("Better sound quality"), - 4)); + 4, + 1000)); QProcess proc; proc.start(command, QStringList() << "-codecs"); @@ -330,6 +368,7 @@ static void init() insertCodec(QLatin1String("faac"), QLatin1String("-q"), aac); insertCodec(QLatin1String("lame"), QLatin1String("-V"), lame); insertCodec(QLatin1String("oggenc"), QLatin1String("-q"), ogg); + insertCodec(QLatin1String("opusenc"), QLatin1String("--bitrate"), opus); qSort(installedEncoders); } } @@ -367,7 +406,7 @@ QStringList Encoder::params(int value, const QString &in, const QString &out) co v=s.value; } } - p << param << QString::number(v); + p << param << QString::number(v*ffmpegValueAdjust); } if (transcoder) { diff --git a/devices/encoders.h b/devices/encoders.h index 9441edacd..da2ff8853 100644 --- a/devices/encoders.h +++ b/devices/encoders.h @@ -43,7 +43,8 @@ namespace Encoders Encoder() : defaultValueIndex(0) { } - Encoder(const QString &n, const QString &d, const QString &t, const QString &e, const QString &a, const QString &c, const QString &f, const QString &v, const QList &vs, const QString &l, const QString &h, int def) + Encoder(const QString &n, const QString &d, const QString &t, const QString &e, const QString &a, const QString &c, + const QString &f, const QString &v, const QList &vs, const QString &l, const QString &h, int def, int adj=0) : name(n) , description(d) , tooltip(t) @@ -56,6 +57,7 @@ namespace Encoders , low(l) , high(h) , defaultValueIndex(def) + , ffmpegValueAdjust(adj) , transcoder(true) { } bool isNull() { return name.isEmpty(); } @@ -76,6 +78,7 @@ namespace Encoders QString low; QString high; int defaultValueIndex; + int ffmpegValueAdjust; bool transcoder; }; diff --git a/http/httpsocket.cpp b/http/httpsocket.cpp index 1291c4a7e..302c19581 100644 --- a/http/httpsocket.cpp +++ b/http/httpsocket.cpp @@ -93,6 +93,15 @@ static QString detectMimeType(const QString &file) } delete result; } + #ifdef TAGLIB_OPUS_FOUND + if (mime.isEmpty()) { + result = new TagLib::Ogg::Opus::File(encodedName, false, TagLib::AudioProperties::Fast); + if (result->isValid()) { + mime=QLatin1String("audio/x-opus+ogg"); + } + delete result; + } + #endif return QLatin1String("audio/ogg"); } #endif @@ -120,6 +129,8 @@ static QString detectMimeType(const QString &file) return QLatin1String("application/x-dff"); } else if (suffix == QLatin1String("dsf")) { return QLatin1String("application/x-dsf"); + } else if (suffix == QLatin1String("opus")) { + return QLatin1String("audio/opus"); } return QString(); diff --git a/tags/filetyperesolver.cpp b/tags/filetyperesolver.cpp index 4e18b5f38..05906e971 100644 --- a/tags/filetyperesolver.cpp +++ b/tags/filetyperesolver.cpp @@ -46,6 +46,9 @@ #include #include #include +#ifdef TAGLIB_OPUS_FOUND +#include +#endif TagLib::File *Meta::Tag::FileTypeResolver::createFile(TagLib::FileName fileName, bool readProperties, @@ -75,6 +78,11 @@ TagLib::File *Meta::Tag::FileTypeResolver::createFile(TagLib::FileName fileName, result = new TagLibExtras::RealMedia::File(fileName, readProperties, propertiesStyle); } #endif + #ifdef TAGLIB_OPUS_FOUND + else if (mimetype->is(QLatin1String("audio/opus")) || mimetype->is(QLatin1String("audio/x-opus+ogg"))) { + result = new TagLib::Ogg::Opus::File(fileName, readProperties, propertiesStyle); + } + #endif else if (mimetype->is(QLatin1String("audio/x-vorbis+ogg"))) { result = new TagLib::Ogg::Vorbis::File(fileName, readProperties, propertiesStyle); } else if (mimetype->is(QLatin1String("audio/x-flac+ogg"))) { @@ -115,6 +123,12 @@ TagLib::File *Meta::Tag::FileTypeResolver::createFile(TagLib::FileName fileName, delete result; result = new TagLib::TrueAudio::File(fileName, readProperties, propertiesStyle); } + #ifdef TAGLIB_OPUS_FOUND + if (!result->isValid()) { + delete result; + result = new TagLib::Ogg::Opus::File(fileName, readProperties, propertiesStyle); + } + #endif } #endif // else if (suffix == QLatin1String("m4a") || suffix == QLatin1String("m4b") @@ -138,6 +152,11 @@ TagLib::File *Meta::Tag::FileTypeResolver::createFile(TagLib::FileName fileName, } else if (suffix == QLatin1String("mpc") || suffix == QLatin1String("mpp") || suffix == QLatin1String("mp+")) { result = new TagLib::MPC::File(fileName, readProperties, propertiesStyle); } + #ifdef TAGLIB_OPUS_FOUND + else if (suffix == QLatin1String("opus")) { + result = new TagLib::Ogg::Opus::File(fileName, readProperties, propertiesStyle); + } + #endif // #ifndef Q_OS_WIN // if (!result) diff --git a/tags/tags.cpp b/tags/tags.cpp index 6f3e41f06..870ddc7cb 100644 --- a/tags/tags.cpp +++ b/tags/tags.cpp @@ -47,6 +47,9 @@ #ifdef TAGLIB_MP4_FOUND #include #endif +#ifdef TAGLIB_OPUS_FOUND +#include +#endif #include #include #include @@ -783,6 +786,12 @@ static void readTags(const TagLib::FileRef fileref, Song *song, ReplayGain *rg, if (file->tag()) { readVorbisCommentTags(file->tag(), song, rg, img); } + #ifdef TAGLIB_OPUS_FOUND + } else if (TagLib::Ogg::Opus::File *file = dynamic_cast< TagLib::Ogg::Opus::File * >(fileref.file())) { + if (file->tag()) { + readVorbisCommentTags(file->tag(), song, rg, img); + } + #endif } else if (TagLib::FLAC::File *file = dynamic_cast< TagLib::FLAC::File * >(fileref.file())) { if (file->xiphComment()) { readVorbisCommentTags(file->xiphComment(), song, rg, img); @@ -891,6 +900,12 @@ static bool writeTags(const TagLib::FileRef fileref, const Song &from, const Son if (file->tag()) { changed=writeVorbisCommentTags(file->tag(), from, to, rg, img) || changed; } + #ifdef TAGLIB_OPUS_FOUND + } else if (TagLib::Ogg::Opus::File *file = dynamic_cast< TagLib::Ogg::Opus::File * >(fileref.file())) { + if (file->tag()) { + changed=writeVorbisCommentTags(file->tag(), from, to, rg, img) || changed; + } + #endif } else if (TagLib::FLAC::File *file = dynamic_cast< TagLib::FLAC::File * >(fileref.file())) { if (file->xiphComment()) { changed=writeVorbisCommentTags(file->xiphComment(), from, to, rg, img) || changed;