File indexing completed on 2024-05-19 04:52:39

0001 /*
0002     SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl>
0003     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "k3blameencoder.h"
0009 #include "k3blameencoderdefaults.h"
0010 #include "k3blametyes.h"
0011 #include "k3bplugin_i18n.h"
0012 #include "k3bcore.h"
0013 #include <config-k3b.h>
0014 
0015 #include <KConfig>
0016 #include <KConfigGroup>
0017 #include <KSharedConfig>
0018 #include <QDebug>
0019 #include <QTextCodec>
0020 
0021 #include <stdio.h>
0022 #include <lame/lame.h>
0023 
0024 #include <QFile>
0025 
0026 
0027 K_PLUGIN_CLASS_WITH_JSON(K3bLameEncoder, "k3blameencoder.json")
0028 
0029 
0030 class K3bLameEncoder::Private
0031 {
0032 public:
0033     Private()
0034         : flags(0),
0035           fid(0) {
0036     }
0037 
0038     lame_global_flags* flags;
0039 
0040     char buffer[8000];
0041 
0042     QString filename;
0043     FILE* fid;
0044 };
0045 
0046 
0047 
0048 
0049 K3bLameEncoder::K3bLameEncoder( QObject* parent, const QVariantList& )
0050     : K3b::AudioEncoder( parent )
0051 {
0052     d = new Private();
0053 }
0054 
0055 
0056 K3bLameEncoder::~K3bLameEncoder()
0057 {
0058     closeFile();
0059 
0060     delete d;
0061 }
0062 
0063 
0064 bool K3bLameEncoder::openFile( const QString& extension, const QString& filename, const K3b::Msf& length, const MetaData& metaData )
0065 {
0066     closeFile();
0067 
0068     d->filename = filename;
0069     d->fid = ::fopen( QFile::encodeName( filename ), "w+" );
0070     if( d->fid )
0071         return initEncoder( extension, length, metaData );
0072     else
0073         return false;
0074 }
0075 
0076 
0077 bool K3bLameEncoder::isOpen() const
0078 {
0079     return ( d->fid != 0 );
0080 }
0081 
0082 
0083 void K3bLameEncoder::closeFile()
0084 {
0085     if( isOpen() ) {
0086         finishEncoder();
0087         ::fclose( d->fid );
0088         d->fid = 0;
0089         d->filename.truncate(0);
0090     }
0091 }
0092 
0093 
0094 QString K3bLameEncoder::filename() const
0095 {
0096     return d->filename;
0097 }
0098 
0099 
0100 bool K3bLameEncoder::initEncoderInternal( const QString&, const K3b::Msf& length, const MetaData& metaData )
0101 {
0102     KSharedConfig::Ptr c = KSharedConfig::openConfig();
0103     KConfigGroup grp(c, QStringLiteral("K3bLameEncoderPlugin") );
0104 
0105     d->flags = lame_init();
0106 
0107     if( d->flags == 0 ) {
0108         qDebug() << "(K3bLameEncoder) lame_init failed.";
0109         return false;
0110     }
0111 
0112     //
0113     // set the format of the input data
0114     //
0115     lame_set_num_samples( d->flags, length.lba()*588 );
0116     lame_set_in_samplerate( d->flags, 44100 );
0117     lame_set_num_channels( d->flags, 2 );
0118 
0119     //
0120     // Lame by default determines the samplerate based on the bitrate
0121     // since we have no option for the user to influence this yet
0122     // we just keep to the good old 44.1 khz
0123     //
0124     lame_set_out_samplerate( d->flags, 44100 );
0125 
0126     //
0127     // Choose the quality level
0128     //
0129     if( grp.readEntry( "Manual Bitrate Settings", DEFAULT_MANUAL_BITRATE ) ) {
0130         //
0131         // Mode
0132         //
0133         QString mode = grp.readEntry( "Mode", DEFAULT_MODE );
0134         if( mode == "stereo" )
0135             lame_set_mode( d->flags, STEREO );
0136         else if( mode == "joint" )
0137             lame_set_mode( d->flags, JOINT_STEREO );
0138         else // mono
0139             lame_set_mode( d->flags, MONO );
0140 
0141         //
0142         // Variable Bitrate
0143         //
0144         if( grp.readEntry( "VBR", DEFAULT_VBR ) ) {
0145             // we use the default algorithm here
0146             lame_set_VBR( d->flags, vbr_default );
0147 
0148             if( grp.readEntry( "Use Maximum Bitrate", DEFAULT_USE_MAXIMUM_BITRATE ) ) {
0149                 lame_set_VBR_max_bitrate_kbps( d->flags, grp.readEntry( "Maximum Bitrate", DEFAULT_MAXIMUM_BITRATE ) );
0150             }
0151             if( grp.readEntry( "Use Minimum Bitrate", DEFAULT_USE_MINIMUM_BITRATE ) ) {
0152                 lame_set_VBR_min_bitrate_kbps( d->flags, grp.readEntry( "Minimum Bitrate", DEFAULT_MINIMUM_BITRATE ) );
0153 
0154                 // TODO: lame_set_hard_min
0155             }
0156             if( grp.readEntry( "Use Average Bitrate", DEFAULT_USE_AVERAGE_BITRATE ) ) {
0157                 lame_set_VBR( d->flags, vbr_abr );
0158                 lame_set_VBR_mean_bitrate_kbps( d->flags, grp.readEntry( "Average Bitrate", DEFAULT_AVERAGE_BITRATE ) );
0159             }
0160         }
0161 
0162         //
0163         // Constant Bitrate
0164         //
0165         else {
0166             lame_set_VBR( d->flags, vbr_off );
0167             lame_set_brate( d->flags, grp.readEntry( "Constant Bitrate", DEFAULT_CONSTANT_BITRATE ) );
0168         }
0169     }
0170 
0171     else {
0172         //
0173         // In lame 0 is the highest quality. Since that is just confusing for the user
0174         // if we call the setting "Quality" we simply invert the value.
0175         //
0176         int q = grp.readEntry( "Quality Level", DEFAULT_QUALITY_LEVEL );
0177         if( q < 0 ) q = 0;
0178         if( q > 9 ) q = 9;
0179 
0180         qDebug() << "(K3bLameEncoder) setting preset encoding value to " << q;
0181 
0182         if ( q < 2 || q > 8 ) {
0183             lame_set_VBR( d->flags, vbr_abr );
0184         }
0185         else {
0186             lame_set_VBR( d->flags, vbr_default );
0187         }
0188         lame_set_preset( d->flags, s_lame_presets[q] );
0189 
0190         if( q < 2 )
0191             lame_set_mode( d->flags, MONO );
0192     }
0193 
0194 
0195     //
0196     // file options
0197     //
0198     lame_set_copyright( d->flags, grp.readEntry( "Copyright", DEFAULT_COPYRIGHT ) );
0199     lame_set_original( d->flags, grp.readEntry( "Original", DEFAULT_ORIGINAL ) );
0200     lame_set_strict_ISO( d->flags, grp.readEntry( "ISO compliance", DEFAULT_ISO_COMPLIANCE ) );
0201     lame_set_error_protection( d->flags, grp.readEntry( "Error Protection", DEFAULT_ERROR_PROTECTION ) );
0202 
0203 
0204     //
0205     // Used Algorithm
0206     //
0207     // default to 2 which is the same as the -h lame option
0208     // THIS HAS NO INFLUENCE ON THE SIZE OF THE FILE!
0209     //
0210     //
0211     // In lame 0 is the highest quality. Since that is just confusing for the user
0212     // if we call the setting "Quality" we simply invert the value.
0213     //
0214     int q = grp.readEntry( "Encoder Quality", DEFAULT_ENCODER_QUALITY );
0215     if( q < 0 ) q = 0;
0216     if( q > 9 ) q = 9;
0217     lame_set_quality( d->flags, 9-q );
0218 
0219     //
0220     // ID3 settings
0221     //
0222     // for now we default to both v1 and v2 tags
0223     id3tag_add_v2( d->flags );
0224     id3tag_pad_v2( d->flags );
0225 
0226     // let's not use UTF-8 here since I don't know how to tell lame...
0227     // FIXME: when we use the codec we only get garbage. Why?
0228     QTextCodec* codec = 0;//QTextCodec::codecForName( "ISO8859-1" );
0229 //  if( !codec )
0230 //    qDebug() << "(K3bLameEncoder) could not find codec ISO8859-1.";
0231 
0232     for( MetaData::const_iterator it = metaData.constBegin(); it != metaData.constEnd(); ++it ) {
0233         QByteArray value = codec ? codec->fromUnicode( it.value().toString() ).data()
0234                                  : it.value().toString().toLatin1().data();
0235         switch( it.key() ) {
0236         case META_TRACK_TITLE:
0237             id3tag_set_title( d->flags, value );
0238             break;
0239         case META_TRACK_ARTIST:
0240             id3tag_set_artist( d->flags, value );
0241             break;
0242         case META_ALBUM_TITLE:
0243             id3tag_set_album( d->flags, value );
0244             break;
0245         case META_ALBUM_COMMENT:
0246             id3tag_set_comment( d->flags, value );
0247             break;
0248         case META_YEAR:
0249             id3tag_set_year( d->flags, value );
0250             break;
0251         case META_TRACK_NUMBER:
0252             id3tag_set_track( d->flags, value );
0253             break;
0254         case META_GENRE:
0255             if( id3tag_set_genre( d->flags, value ) )
0256                 qDebug() << "(K3bLameEncoder) unable to set genre.";
0257             break;
0258         default:
0259             break;
0260         }
0261     }
0262 
0263     return( lame_init_params( d->flags ) != -1 );
0264 }
0265 
0266 
0267 qint64 K3bLameEncoder::encodeInternal( const char* data, qint64 len )
0268 {
0269     // FIXME: we may have to swap data here
0270     int size = lame_encode_buffer_interleaved( d->flags,
0271                                                (short int*)data,
0272                                                len/4,
0273                                                (unsigned char*)d->buffer,
0274                                                8000 );
0275     if( size < 0 ) {
0276         qDebug() << "(K3bLameEncoder) lame_encode_buffer_interleaved failed.";
0277         return -1;
0278     }
0279 
0280     return ::fwrite( d->buffer, 1, size, d->fid );
0281 }
0282 
0283 
0284 void K3bLameEncoder::finishEncoderInternal()
0285 {
0286     int size = lame_encode_flush( d->flags,
0287                                   (unsigned char*)d->buffer,
0288                                   8000 );
0289     if( size > 0 )
0290         ::fwrite( d->buffer, 1, size, d->fid );
0291 
0292     lame_mp3_tags_fid( d->flags, d->fid );
0293 
0294     lame_close( d->flags );
0295     d->flags = 0;
0296 }
0297 
0298 
0299 QStringList K3bLameEncoder::extensions() const
0300 {
0301     return QStringList( "mp3" );
0302 }
0303 
0304 
0305 QString K3bLameEncoder::fileTypeComment( const QString& ) const
0306 {
0307     return "MPEG1 Layer III (mp3)";
0308 }
0309 
0310 
0311 long long K3bLameEncoder::fileSize( const QString&, const K3b::Msf& msf ) const
0312 {
0313     KSharedConfig::Ptr c = KSharedConfig::openConfig();
0314     KConfigGroup grp(c, QStringLiteral("K3bLameEncoderPlugin") );
0315     int bitrate = 0;
0316     if( grp.readEntry( "Manual Bitrate Settings", DEFAULT_MANUAL_BITRATE ) ) {
0317         if( grp.readEntry( "VBR", DEFAULT_VBR ) ) {
0318             if( grp.readEntry( "Use Maximum Bitrate", DEFAULT_USE_MAXIMUM_BITRATE ) )
0319                 bitrate = grp.readEntry( "Maximum Bitrate", DEFAULT_MAXIMUM_BITRATE );
0320             if( grp.readEntry( "Use Minimum Bitrate", DEFAULT_USE_MINIMUM_BITRATE ) )
0321                 bitrate = ( bitrate > 0
0322                             ? (bitrate - grp.readEntry( "Minimum Bitrate", DEFAULT_MINIMUM_BITRATE )) / 2
0323                             : grp.readEntry( "Minimum Bitrate", DEFAULT_MINIMUM_BITRATE ) );
0324             if( grp.readEntry( "Use Average Bitrate", DEFAULT_USE_AVERAGE_BITRATE ) )
0325                 bitrate = grp.readEntry( "Average Bitrate", DEFAULT_AVERAGE_BITRATE );
0326         }
0327         else {
0328             bitrate = grp.readEntry( "Constant Bitrate", DEFAULT_CONSTANT_BITRATE );
0329         }
0330     }
0331     else {
0332         int q = grp.readEntry( "Quality Level", DEFAULT_ENCODER_QUALITY );
0333         if( q < 0 ) q = 0;
0334         if( q > 9 ) q = 9;
0335         bitrate = s_lame_preset_approx_bitrates[q];
0336     }
0337 
0338     return (msf.totalFrames()/75 * bitrate * 1000)/8;
0339 }
0340 
0341 #include "k3blameencoder.moc"
0342 
0343 #include "moc_k3blameencoder.cpp"