File: k3blameencoder.cpp

package info (click to toggle)
k3b 25.12.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 55,820 kB
  • sloc: cpp: 99,202; xml: 375; sh: 84; makefile: 10
file content (336 lines) | stat: -rw-r--r-- 9,603 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/*
    SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl>
    SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "k3blameencoder.h"
#include "k3blameencoderdefaults.h"
#include "k3blametyes.h"
#include "k3bplugin_i18n.h"
#include "k3bcore.h"
#include <config-k3b.h>

#include <KConfig>
#include <KConfigGroup>
#include <KSharedConfig>
#include <QDebug>

#include <stdio.h>
#include <lame/lame.h>

#include <QFile>


K_PLUGIN_CLASS_WITH_JSON(K3bLameEncoder, "k3blameencoder.json")


class K3bLameEncoder::Private
{
public:
    Private()
        : flags(0),
          fid(0) {
    }

    lame_global_flags* flags;

    char buffer[8000];

    QString filename;
    FILE* fid;
};




K3bLameEncoder::K3bLameEncoder( QObject* parent, const QVariantList& )
    : K3b::AudioEncoder( parent )
{
    d = new Private();
}


K3bLameEncoder::~K3bLameEncoder()
{
    closeFile();

    delete d;
}


bool K3bLameEncoder::openFile( const QString& extension, const QString& filename, const K3b::Msf& length, const MetaData& metaData )
{
    closeFile();

    d->filename = filename;
    d->fid = ::fopen( QFile::encodeName( filename ), "w+" );
    if( d->fid )
        return initEncoder( extension, length, metaData );
    else
        return false;
}


bool K3bLameEncoder::isOpen() const
{
    return ( d->fid != 0 );
}


void K3bLameEncoder::closeFile()
{
    if( isOpen() ) {
        finishEncoder();
        ::fclose( d->fid );
        d->fid = 0;
        d->filename.truncate(0);
    }
}


QString K3bLameEncoder::filename() const
{
    return d->filename;
}


bool K3bLameEncoder::initEncoderInternal( const QString&, const K3b::Msf& length, const MetaData& metaData )
{
    KSharedConfig::Ptr c = KSharedConfig::openConfig();
    KConfigGroup grp(c, QStringLiteral("K3bLameEncoderPlugin") );

    d->flags = lame_init();

    if( d->flags == 0 ) {
        qDebug() << "(K3bLameEncoder) lame_init failed.";
        return false;
    }

    //
    // set the format of the input data
    //
    lame_set_num_samples( d->flags, length.lba()*588 );
    lame_set_in_samplerate( d->flags, 44100 );
    lame_set_num_channels( d->flags, 2 );

    //
    // Lame by default determines the samplerate based on the bitrate
    // since we have no option for the user to influence this yet
    // we just keep to the good old 44.1 khz
    //
    lame_set_out_samplerate( d->flags, 44100 );

    //
    // Choose the quality level
    //
    if( grp.readEntry( "Manual Bitrate Settings", DEFAULT_MANUAL_BITRATE ) ) {
        //
        // Mode
        //
        QString mode = grp.readEntry( "Mode", DEFAULT_MODE );
        if( mode == "stereo" )
            lame_set_mode( d->flags, STEREO );
        else if( mode == "joint" )
            lame_set_mode( d->flags, JOINT_STEREO );
        else // mono
            lame_set_mode( d->flags, MONO );

        //
        // Variable Bitrate
        //
        if( grp.readEntry( "VBR", DEFAULT_VBR ) ) {
            // we use the default algorithm here
            lame_set_VBR( d->flags, vbr_default );

            if( grp.readEntry( "Use Maximum Bitrate", DEFAULT_USE_MAXIMUM_BITRATE ) ) {
                lame_set_VBR_max_bitrate_kbps( d->flags, grp.readEntry( "Maximum Bitrate", DEFAULT_MAXIMUM_BITRATE ) );
            }
            if( grp.readEntry( "Use Minimum Bitrate", DEFAULT_USE_MINIMUM_BITRATE ) ) {
                lame_set_VBR_min_bitrate_kbps( d->flags, grp.readEntry( "Minimum Bitrate", DEFAULT_MINIMUM_BITRATE ) );

                // TODO: lame_set_hard_min
            }
            if( grp.readEntry( "Use Average Bitrate", DEFAULT_USE_AVERAGE_BITRATE ) ) {
                lame_set_VBR( d->flags, vbr_abr );
                lame_set_VBR_mean_bitrate_kbps( d->flags, grp.readEntry( "Average Bitrate", DEFAULT_AVERAGE_BITRATE ) );
            }
        }

        //
        // Constant Bitrate
        //
        else {
            lame_set_VBR( d->flags, vbr_off );
            lame_set_brate( d->flags, grp.readEntry( "Constant Bitrate", DEFAULT_CONSTANT_BITRATE ) );
        }
    }

    else {
        //
        // In lame 0 is the highest quality. Since that is just confusing for the user
        // if we call the setting "Quality" we simply invert the value.
        //
        int q = grp.readEntry( "Quality Level", DEFAULT_QUALITY_LEVEL );
        if( q < 0 ) q = 0;
        if( q > 9 ) q = 9;

        qDebug() << "(K3bLameEncoder) setting preset encoding value to " << q;

        if ( q < 2 || q > 8 ) {
            lame_set_VBR( d->flags, vbr_abr );
        }
        else {
            lame_set_VBR( d->flags, vbr_default );
        }
        lame_set_preset( d->flags, s_lame_presets[q] );

        if( q < 2 )
            lame_set_mode( d->flags, MONO );
    }


    //
    // file options
    //
    lame_set_copyright( d->flags, grp.readEntry( "Copyright", DEFAULT_COPYRIGHT ) );
    lame_set_original( d->flags, grp.readEntry( "Original", DEFAULT_ORIGINAL ) );
    lame_set_strict_ISO( d->flags, grp.readEntry( "ISO compliance", DEFAULT_ISO_COMPLIANCE ) );
    lame_set_error_protection( d->flags, grp.readEntry( "Error Protection", DEFAULT_ERROR_PROTECTION ) );


    //
    // Used Algorithm
    //
    // default to 2 which is the same as the -h lame option
    // THIS HAS NO INFLUENCE ON THE SIZE OF THE FILE!
    //
    //
    // In lame 0 is the highest quality. Since that is just confusing for the user
    // if we call the setting "Quality" we simply invert the value.
    //
    int q = grp.readEntry( "Encoder Quality", DEFAULT_ENCODER_QUALITY );
    if( q < 0 ) q = 0;
    if( q > 9 ) q = 9;
    lame_set_quality( d->flags, 9-q );

    //
    // ID3 settings
    //
    // for now we default to both v1 and v2 tags
    id3tag_add_v2( d->flags );
    id3tag_pad_v2( d->flags );

    // let's not use UTF-8 here since I don't know how to tell lame...
    for( MetaData::const_iterator it = metaData.constBegin(); it != metaData.constEnd(); ++it ) {
        QByteArray value = it.value().toString().toLatin1();
        switch( it.key() ) {
        case META_TRACK_TITLE:
            id3tag_set_title( d->flags, value );
            break;
        case META_TRACK_ARTIST:
            id3tag_set_artist( d->flags, value );
            break;
        case META_ALBUM_TITLE:
            id3tag_set_album( d->flags, value );
            break;
        case META_ALBUM_COMMENT:
            id3tag_set_comment( d->flags, value );
            break;
        case META_YEAR:
            id3tag_set_year( d->flags, value );
            break;
        case META_TRACK_NUMBER:
            id3tag_set_track( d->flags, value );
            break;
        case META_GENRE:
            if( id3tag_set_genre( d->flags, value ) )
                qDebug() << "(K3bLameEncoder) unable to set genre.";
            break;
        default:
            break;
        }
    }

    return( lame_init_params( d->flags ) != -1 );
}


qint64 K3bLameEncoder::encodeInternal( const char* data, qint64 len )
{
    // FIXME: we may have to swap data here
    int size = lame_encode_buffer_interleaved( d->flags,
                                               (short int*)data,
                                               len/4,
                                               (unsigned char*)d->buffer,
                                               8000 );
    if( size < 0 ) {
        qDebug() << "(K3bLameEncoder) lame_encode_buffer_interleaved failed.";
        return -1;
    }

    return ::fwrite( d->buffer, 1, size, d->fid );
}


void K3bLameEncoder::finishEncoderInternal()
{
    int size = lame_encode_flush( d->flags,
                                  (unsigned char*)d->buffer,
                                  8000 );
    if( size > 0 )
        ::fwrite( d->buffer, 1, size, d->fid );

    lame_mp3_tags_fid( d->flags, d->fid );

    lame_close( d->flags );
    d->flags = 0;
}


QStringList K3bLameEncoder::extensions() const
{
    return QStringList( "mp3" );
}


QString K3bLameEncoder::fileTypeComment( const QString& ) const
{
    return "MPEG1 Layer III (mp3)";
}


long long K3bLameEncoder::fileSize( const QString&, const K3b::Msf& msf ) const
{
    KSharedConfig::Ptr c = KSharedConfig::openConfig();
    KConfigGroup grp(c, QStringLiteral("K3bLameEncoderPlugin") );
    int bitrate = 0;
    if( grp.readEntry( "Manual Bitrate Settings", DEFAULT_MANUAL_BITRATE ) ) {
        if( grp.readEntry( "VBR", DEFAULT_VBR ) ) {
            if( grp.readEntry( "Use Maximum Bitrate", DEFAULT_USE_MAXIMUM_BITRATE ) )
                bitrate = grp.readEntry( "Maximum Bitrate", DEFAULT_MAXIMUM_BITRATE );
            if( grp.readEntry( "Use Minimum Bitrate", DEFAULT_USE_MINIMUM_BITRATE ) )
                bitrate = ( bitrate > 0
                            ? (bitrate - grp.readEntry( "Minimum Bitrate", DEFAULT_MINIMUM_BITRATE )) / 2
                            : grp.readEntry( "Minimum Bitrate", DEFAULT_MINIMUM_BITRATE ) );
            if( grp.readEntry( "Use Average Bitrate", DEFAULT_USE_AVERAGE_BITRATE ) )
                bitrate = grp.readEntry( "Average Bitrate", DEFAULT_AVERAGE_BITRATE );
        }
        else {
            bitrate = grp.readEntry( "Constant Bitrate", DEFAULT_CONSTANT_BITRATE );
        }
    }
    else {
        int q = grp.readEntry( "Quality Level", DEFAULT_ENCODER_QUALITY );
        if( q < 0 ) q = 0;
        if( q > 9 ) q = 9;
        bitrate = s_lame_preset_approx_bitrates[q];
    }

    return (msf.totalFrames()/75 * bitrate * 1000)/8;
}

#include "k3blameencoder.moc"

#include "moc_k3blameencoder.cpp"