/* * Cantata * * Copyright (c) 2011-2013 Craig Drummond * * Large portions of this file, mainly the textual descriptions, etc, are taken from * Amarok - hence the (c) notice below... */ /**************************************************************************************** * Copyright (c) 2010 Téo Mrnjavac * * * * 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. * * * * 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 Encoder. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see . * ****************************************************************************************/ #include "encoders.h" #include "utils.h" #include "localize.h" #include #include namespace Encoders { static QList installedEncoders; static bool usingAvconv=false; static void insertCodec(const QString &cmd, const QString ¶m,const QString &outputParam, Encoder &enc) { QString command=Utils::findExe(cmd); if (!command.isEmpty()) { int index=installedEncoders.indexOf(enc); enc.codec=cmd; enc.param=param; enc.transcoder=false; enc.app=command; enc.outputParam=outputParam; if (-1!=index) { Encoder orig=installedEncoders.takeAt(index); orig.name+=QLatin1String(" (ffmpeg)"); installedEncoders.insert(index, orig); enc.name+=QLatin1String(" (")+cmd+QChar(')'); installedEncoders.insert(index+1, enc); } else { installedEncoders.append(enc); } } } static void init() { static bool initialised=false; if (!initialised) { initialised=true; QString command=Utils::findExe(QLatin1String("ffmpeg")); if (command.isEmpty()) { command=Utils::findExe(QLatin1String("avconv")); usingAvconv=true; } QByteArray vbr = "~%1kb/s VBR"; QByteArray cbr = "%1kb/s CBR"; QByteArray quality = "%1 (~%2kb/s VBR)"; Encoder aac(QLatin1String("AAC"), i18nc("Feel free to redirect the english Wikipedia link to a local version, if " "it exists.", "Advanced Audio " "Coding (AAC) is a patented lossy codec for digital audio.
AAC " "generally achieves better sound quality than MP3 at similar bit rates. " "It is a reasonable choice for the iPod and some other portable music " "players."), i18n("The bitrate is a measure of the quantity of data used to represent a second " "of the audio track.
The AAC 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.
" "150kb/s is a good choice for music listening on a portable player.
" "Anything below 120kb/s might be unsatisfactory for music and anything above " "200kb/s is probably overkill."), QLatin1String("m4a"), command, QLatin1String("libfaac"), 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), i18n("Smaller file"), i18n("Better sound quality"), 5); Encoder lame(QLatin1String("MP3"), i18nc("Feel free to redirect the english Wikipedia link to a local version, if " "it exists.", "MPEG Audio Layer 3 (MP3) is " "a patented digital audio codec using a form of lossy data compression." "
In spite of its shortcomings, it is a common format for consumer " "audio storage, and is widely supported on portable music players."), i18n("The bitrate is a measure of the quantity of data used to represent a " "second of the audio track.
The MP3 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.
" "160kb/s is a good choice for music listening on a portable player.
" "Anything below 120kb/s might be unsatisfactory for music and anything above " "205kb/s is probably overkill."), QLatin1String("mp3"), command, QLatin1String("libmp3lame"), QLatin1String("-aq"), i18n("Expected average bitrate for variable bitrate encoding"), QList() << Setting(i18n(vbr, 80), 9) << Setting(i18n(vbr, 100), 8) << Setting(i18n(vbr, 120), 7) << Setting(i18n(vbr, 140), 6) << Setting(i18n(vbr, 160), 5) << Setting(i18n(vbr, 175), 4) << Setting(i18n(vbr, 190), 3) << Setting(i18n(vbr, 205), 2) << Setting(i18n(vbr, 220), 1) << Setting(i18n(vbr, 240), 0), i18n("Smaller file"), i18n("Better sound quality"), 4); Encoder ogg(i18n("Ogg Vorbis"), i18nc("Feel free to redirect the english Wikipedia link to a local version, if " "it exists.", "Ogg Vorbis is an open " "and royalty-free audio codec for lossy audio compression.
It produces " "smaller files than MP3 at equivalent or higher quality. Ogg Vorbis is an " "all-around excellent choice, especially for portable music players that " "support it."), i18n("The bitrate is a measure of the quantity of data used to represent a " "second of the audio track.
The Vorbis 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.
" "The Vorbis encoder uses a quality rating between -1 and 10 to define " "a certain expected audio quality level. The bitrate measure in this slider is " "just a rough estimate (provided by Vorbis) of the average bitrate of the encoded " "track given a quality value. In fact, with newer and more efficient Vorbis versions the " "actual bitrate is even lower.
" "5 is a good choice for music listening on a portable player.
" "Anything below 3 might be unsatisfactory for music and anything above " "8 is probably overkill."), QLatin1String("ogg"), command, QLatin1String("libvorbis"), 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), 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); initial.append( Encoder(i18n("Apple Lossless"), i18nc("Feel free to redirect the english Wikipedia link to a local version, if " "it exists.", "Apple Lossless " "(ALAC) is an audio codec for lossless compression of digital music.
" "Recommended only for Apple music players and players that do not support " "FLAC."), QString(), QLatin1String("m4a"), command, QLatin1String("alac"), QString(), QString(), QList(), QString(), QString(), 0)); initial.append( Encoder(i18n("FLAC"), i18nc("Feel free to redirect the english Wikipedia link to a local version, if " "it exists.", "Free " "Lossless Audio Codec (FLAC) is an open and royalty-free codec for " "lossless compression of digital music.
If you wish to store your music " "without compromising on audio quality, FLAC is an excellent choice."), i18n("The " "compression level is an integer value between 0 and 8 that represents " "the tradeoff between file size and compression speed while encoding with FLAC.
" "Setting the compression level to 0 yields the shortest compression time but " "generates a comparably big file.
" "On the other hand, a compression level of 8 makes compression quite slow but " "produces the smallest file.
" "Note that since FLAC is by definition a lossless codec, the audio quality " "of the output is exactly the same regardless of the compression level.
" "Also, levels above 5 dramatically increase compression time but create an only " "slightly smaller file, and are not recommended."), QLatin1String("flac"), command, QLatin1String("flac"), 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), 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 " "it exists.", "Windows Media " "Audio (WMA) is a proprietary codec developed by Microsoft for lossy " "audio compression.
Recommended only for portable music players that " "do not support Ogg Vorbis."), i18n("The bitrate is a measure of the quantity of data used to represent a " "second of the audio track.
Due to the limitations of the proprietary WMA " "format and the difficulty of reverse-engineering a proprietary encoder, the " "WMA encoder used by Cantata sets a constant bitrate (CBR) setting.
" "For this reason, the bitrate measure in this slider is a pretty accurate estimate " "of the bitrate of the encoded track.
" "136kb/s is a good choice for music listening on a portable player.
" "Anything below 112kb/s might be unsatisfactory for music and anything above " "182kb/s is probably overkill."), QLatin1String("wma"), command, QLatin1String("wmav2"), QLatin1String("-ab"), i18n("Bitrate"), 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, 1000)); QProcess proc; proc.start(command, QStringList() << "-codecs"); if (proc.waitForStarted()) { proc.waitForFinished(); } if (0!=proc.exitCode()) { return; } QString output=proc.readAllStandardOutput(); if (output.simplified().isEmpty()) { return; } QStringList lines=output.split('\n', QString::SkipEmptyParts); foreach (const QString &line, lines) { int pos=line.indexOf(QRegExp(QLatin1String("[\\. D]EA"))); if (0==pos || 1==pos) { QList::Iterator it(initial.begin()); QList::Iterator end(initial.end()); for (; it!=end; ++it) { if (line.contains((*it).codec)) { installedEncoders.append((*it)); initial.erase(it); break; } } if (initial.isEmpty()) { break; } } } } insertCodec(QLatin1String("faac"), QLatin1String("-q"), QLatin1String("-o"), aac); insertCodec(QLatin1String("lame"), QLatin1String("-V"), QString(), lame); insertCodec(QLatin1String("oggenc"), QLatin1String("-q"), QLatin1String("-o"), ogg); insertCodec(QLatin1String("opusenc"), QLatin1String("--bitrate"), QString(), opus); qSort(installedEncoders); } } bool Encoder::operator<(const Encoder &o) const { return name.compare(o.name)<0; } QString Encoder::changeExtension(const QString &file) { return Utils::changeExtension(file, extension); } bool Encoder::isDifferent(const QString &file) { return file!=changeExtension(file); } QStringList Encoder::params(int value, const QString &in, const QString &out) const { QStringList p; if (transcoder) { p << app << QLatin1String("-i") << in << QLatin1String("-threads") << QLatin1String("0") << QLatin1String(usingAvconv ? "-c:a" : "-acodec") << codec; } else { p << app; } if (!param.isEmpty() && values.size()>1) { bool increase=values.at(0).valuevalue) || (!increase && s.value getAvailable() { init(); return installedEncoders; } Encoder getEncoder(const QString &codec) { init(); foreach (const Encoder &encoder, installedEncoders) { if (encoder.codec==codec) { return encoder; } } return Encoder(); } }