/* * Cantata * * Copyright (c) 2011-2017 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 "support/utils.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+=usingAvconv ? QLatin1String(" (avconv)") : 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"), QObject::tr("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."), QObject::tr("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"), QObject::tr("Expected average bitrate for variable bitrate encoding"), QList() << Setting(QObject::tr(vbr).arg(25), 30) << Setting(QObject::tr(vbr).arg(50), 55) << Setting(QObject::tr(vbr).arg(70), 80) << Setting(QObject::tr(vbr).arg(90), 105) << Setting(QObject::tr(vbr).arg(120), 125) << Setting(QObject::tr(vbr).arg(150), 155) << Setting(QObject::tr(vbr).arg(170), 180) << Setting(QObject::tr(vbr).arg(180), 205) << Setting(QObject::tr(vbr).arg(190), 230) << Setting(QObject::tr(vbr).arg(200), 255) << Setting(QObject::tr(vbr).arg(210), 280), QObject::tr("Smaller file"), QObject::tr("Better sound quality"), 5); Encoder lame(QLatin1String("MP3"), QObject::tr("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."), QObject::tr("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"), QObject::tr("Expected average bitrate for variable bitrate encoding"), QList() << Setting(QObject::tr(vbr).arg(80), 9) << Setting(QObject::tr(vbr).arg(100), 8) << Setting(QObject::tr(vbr).arg(120), 7) << Setting(QObject::tr(vbr).arg(140), 6) << Setting(QObject::tr(vbr).arg(160), 5) << Setting(QObject::tr(vbr).arg(175), 4) << Setting(QObject::tr(vbr).arg(190), 3) << Setting(QObject::tr(vbr).arg(205), 2) << Setting(QObject::tr(vbr).arg(220), 1) << Setting(QObject::tr(vbr).arg(240), 0), QObject::tr("Smaller file"), QObject::tr("Better sound quality"), 4); Encoder ogg(QObject::tr("Ogg Vorbis"), QObject::tr("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."), QObject::tr("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"), QObject::tr("Quality rating"), QList() << Setting(QObject::tr(quality).arg(-1).arg(45), -1) << Setting(QObject::tr(quality).arg(0).arg(64), 0) << Setting(QObject::tr(quality).arg(1).arg(80), 1) << Setting(QObject::tr(quality).arg(2).arg(96), 2) << Setting(QObject::tr(quality).arg(3).arg(112), 3) << Setting(QObject::tr(quality).arg(4).arg(128), 4) << Setting(QObject::tr(quality).arg(5).arg(160), 5) << Setting(QObject::tr(quality).arg(6).arg(192), 6) << Setting(QObject::tr(quality).arg(7).arg(224), 7) << Setting(QObject::tr(quality).arg(8).arg(256), 8) << Setting(QObject::tr(quality).arg(9).arg(320), 9) << Setting(QObject::tr(quality).arg(10).arg(500), 10), QObject::tr("Smaller file"), QObject::tr("Better sound quality"), 6); Encoder opus(QObject::tr("Opus"), QObject::tr("Opus is " "a patent-free digital audio codec using a form of lossy data compression."), QObject::tr("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"), QObject::tr("Bitrate"), QList() << Setting(QObject::tr(vbr).arg(32), 32) << Setting(QObject::tr(vbr).arg(64), 64) << Setting(QObject::tr(vbr).arg(96), 96) << Setting(QObject::tr(vbr).arg(128), 128) << Setting(QObject::tr(vbr).arg(160), 160) << Setting(QObject::tr(vbr).arg(192), 192) << Setting(QObject::tr(vbr).arg(256), 256) << Setting(QObject::tr(vbr).arg(320), 320) << Setting(QObject::tr(vbr).arg(360), 360), QObject::tr("Smaller file"), QObject::tr("Better sound quality"), 4, 1000); if (!command.isEmpty()) { QList initial; initial.append(aac); initial.append( Encoder(QObject::tr("Apple Lossless"), QObject::tr("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(QObject::tr("FLAC"), QObject::tr("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."), QObject::tr("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"), QObject::tr("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), QObject::tr("Faster compression"), QObject::tr("Smaller file"), 5)); initial.append(lame); initial.append(ogg); initial.append(opus); initial.append( Encoder(QObject::tr("Windows Media Audio"), QObject::tr("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."), QObject::tr("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"), QObject::tr("Bitrate"), QList() << Setting(QObject::tr(cbr).arg(64), 65) << Setting(QObject::tr(cbr).arg(80), 75) << Setting(QObject::tr(cbr).arg(96), 88) << Setting(QObject::tr(cbr).arg(112), 106) << Setting(QObject::tr(cbr).arg(136), 133) << Setting(QObject::tr(cbr).arg(182), 180) << Setting(QObject::tr(cbr).arg(275), 271) << Setting(QObject::tr(cbr).arg(550), 545), QObject::tr("Smaller file"), QObject::tr("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.toLower()!=changeExtension(file).toLower(); } 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(); } }