~ubuntu-branches/ubuntu/trusty/k3b/trusty

« back to all changes in this revision

Viewing changes to .pc/Fixed_compilation_with_new_FFMPEG.patch/plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-11-12 10:36:01 UTC
  • mfrom: (2.1.20 sid)
  • Revision ID: package-import@ubuntu.com-20131112103601-q6vvln9lv3mg7qxh
Tags: 2.0.2-7ubuntu1
* Merge with Debian, remaining changes:
  - Suggest, not recommend libk3b6-extracodecs (Cannot be on the CD)
  - Do not ship k3b documentation, it's for the KDE3 version.
  - Do not install unused scalable icons to save space
  - Keep kubuntu_02_kubuntu_restricted.diff
  - Keep kubuntu_03_no_missing_mp3_warn.diff
  - Keep kubuntu_05_no_system_settings.diff
  - Keep kubuntu_07_quicklists.diff
  - Disable 111_advice_debian_libk3b3-extracodes.diff and
    112_dont_require_mp3.diff which aren't required due to our mp3 patches.
  - swap kubuntu_06_libav_0.7.diff for Debian's
    Fixed_compilation_with_new_FFMPEG.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 *
 
4
 * Copyright (C) 2004-2008 Sebastian Trueg <trueg@k3b.org>
 
5
 *
 
6
 * This file is part of the K3b project.
 
7
 * Copyright (C) 1998-2008 Sebastian Trueg <trueg@k3b.org>
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or modify
 
10
 * it under the terms of the GNU General Public License as published by
 
11
 * the Free Software Foundation; either version 2 of the License, or
 
12
 * (at your option) any later version.
 
13
 * See the file "COPYING" for the exact licensing terms.
 
14
 */
 
15
#include "k3bffmpegwrapper.h"
 
16
 
 
17
#include <config-k3b.h>
 
18
 
 
19
extern "C" {
 
20
/*
 
21
 Recent versions of FFmepg uses C99 constant macros which are not presebt in C++ standard.
 
22
 The macro __STDC_CONSTANT_MACROS allow C++ to use these macros. Altough it's not defined by C++ standard
 
23
 it's supported by many implementations.
 
24
 See bug 236036 and discussion: http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2010-May/088074.html
 
25
 */
 
26
#define __STDC_CONSTANT_MACROS
 
27
#ifdef NEWFFMPEGAVCODECPATH
 
28
#include <libavcodec/avcodec.h>
 
29
#include <libavformat/avformat.h>
 
30
#else
 
31
#include <ffmpeg/avcodec.h>
 
32
#include <ffmpeg/avformat.h>
 
33
#endif
 
34
}
 
35
 
 
36
#include <string.h>
 
37
 
 
38
#include <klocale.h>
 
39
 
 
40
 
 
41
#if LIBAVFORMAT_BUILD < 4629
 
42
#define FFMPEG_BUILD_PRE_4629
 
43
#endif
 
44
 
 
45
 
 
46
K3bFFMpegWrapper* K3bFFMpegWrapper::s_instance = 0;
 
47
 
 
48
 
 
49
class K3bFFMpegFile::Private
 
50
{
 
51
public:
 
52
    ::AVFormatContext* formatContext;
 
53
    ::AVCodec* codec;
 
54
 
 
55
    K3b::Msf length;
 
56
 
 
57
    // for decoding. ffmpeg requires 16-byte alignment.
 
58
    char outputBuffer[AVCODEC_MAX_AUDIO_FRAME_SIZE + 15];
 
59
    char* alignedOutputBuffer;
 
60
    char* outputBufferPos;
 
61
    int outputBufferSize;
 
62
    ::AVPacket packet;
 
63
    quint8* packetData;
 
64
    int packetSize;
 
65
};
 
66
 
 
67
 
 
68
K3bFFMpegFile::K3bFFMpegFile( const QString& filename )
 
69
    : m_filename(filename)
 
70
{
 
71
    d = new Private;
 
72
    d->formatContext = 0;
 
73
    d->codec = 0;
 
74
    int offset = 0x10 - (reinterpret_cast<intptr_t>(&d->outputBuffer) & 0xf);
 
75
    d->alignedOutputBuffer = &d->outputBuffer[offset];
 
76
}
 
77
 
 
78
 
 
79
K3bFFMpegFile::~K3bFFMpegFile()
 
80
{
 
81
    close();
 
82
    delete d;
 
83
}
 
84
 
 
85
 
 
86
bool K3bFFMpegFile::open()
 
87
{
 
88
    close();
 
89
 
 
90
    // open the file
 
91
    int err = ::av_open_input_file( &d->formatContext, m_filename.toLocal8Bit(), 0, 0, 0 );
 
92
    if( err < 0 ) {
 
93
        kDebug() << "(K3bFFMpegFile) unable to open " << m_filename << " with error " << err;
 
94
        return false;
 
95
    }
 
96
 
 
97
    // analyze the streams
 
98
    ::av_find_stream_info( d->formatContext );
 
99
 
 
100
    // we only handle files containing one audio stream
 
101
    if( d->formatContext->nb_streams != 1 ) {
 
102
        kDebug() << "(K3bFFMpegFile) more than one stream in " << m_filename;
 
103
        return false;
 
104
    }
 
105
 
 
106
    // urgh... ugly
 
107
#ifdef FFMPEG_BUILD_PRE_4629
 
108
    ::AVCodecContext* codecContext =  &d->formatContext->streams[0]->codec;
 
109
#else
 
110
    ::AVCodecContext* codecContext =  d->formatContext->streams[0]->codec;
 
111
#endif
 
112
    if( codecContext->codec_type != CODEC_TYPE_AUDIO ) {
 
113
        kDebug() << "(K3bFFMpegFile) not a simple audio stream: " << m_filename;
 
114
        return false;
 
115
    }
 
116
 
 
117
    // get the codec
 
118
    d->codec = ::avcodec_find_decoder(codecContext->codec_id);
 
119
    if( !d->codec ) {
 
120
        kDebug() << "(K3bFFMpegFile) no codec found for " << m_filename;
 
121
        return false;
 
122
    }
 
123
 
 
124
    // open the codec on our context
 
125
    kDebug() << "(K3bFFMpegFile) found codec for " << m_filename;
 
126
    if( ::avcodec_open( codecContext, d->codec ) < 0 ) {
 
127
        kDebug() << "(K3bFFMpegDecoderFactory) could not open codec.";
 
128
        return false;
 
129
    }
 
130
 
 
131
    // determine the length of the stream
 
132
    d->length = K3b::Msf::fromSeconds( (double)d->formatContext->duration / (double)AV_TIME_BASE );
 
133
 
 
134
    if( d->length == 0 ) {
 
135
        kDebug() << "(K3bFFMpegDecoderFactory) invalid length.";
 
136
        return false;
 
137
    }
 
138
 
 
139
    // dump some debugging info
 
140
    ::dump_format( d->formatContext, 0, m_filename.toLocal8Bit(), 0 );
 
141
 
 
142
    return true;
 
143
}
 
144
 
 
145
 
 
146
void K3bFFMpegFile::close()
 
147
{
 
148
    d->outputBufferSize = 0;
 
149
    d->packetSize = 0;
 
150
    d->packetData = 0;
 
151
 
 
152
    if( d->codec ) {
 
153
#ifdef FFMPEG_BUILD_PRE_4629
 
154
        ::avcodec_close( &d->formatContext->streams[0]->codec );
 
155
#else
 
156
        ::avcodec_close( d->formatContext->streams[0]->codec );
 
157
#endif
 
158
        d->codec = 0;
 
159
    }
 
160
 
 
161
    if( d->formatContext ) {
 
162
        ::av_close_input_file( d->formatContext );
 
163
        d->formatContext = 0;
 
164
    }
 
165
}
 
166
 
 
167
 
 
168
K3b::Msf K3bFFMpegFile::length() const
 
169
{
 
170
    return d->length;
 
171
}
 
172
 
 
173
 
 
174
int K3bFFMpegFile::sampleRate() const
 
175
{
 
176
#ifdef FFMPEG_BUILD_PRE_4629
 
177
    return d->formatContext->streams[0]->codec.sample_rate;
 
178
#else
 
179
    return d->formatContext->streams[0]->codec->sample_rate;
 
180
#endif
 
181
}
 
182
 
 
183
 
 
184
int K3bFFMpegFile::channels() const
 
185
{
 
186
#ifdef FFMPEG_BUILD_PRE_4629
 
187
    return d->formatContext->streams[0]->codec.channels;
 
188
#else
 
189
    return d->formatContext->streams[0]->codec->channels;
 
190
#endif
 
191
}
 
192
 
 
193
 
 
194
int K3bFFMpegFile::type() const
 
195
{
 
196
#ifdef FFMPEG_BUILD_PRE_4629
 
197
    return d->formatContext->streams[0]->codec.codec_id;
 
198
#else
 
199
    return d->formatContext->streams[0]->codec->codec_id;
 
200
#endif
 
201
}
 
202
 
 
203
 
 
204
QString K3bFFMpegFile::typeComment() const
 
205
{
 
206
    switch( type() ) {
 
207
    case CODEC_ID_WMAV1:
 
208
        return i18n("Windows Media v1");
 
209
    case CODEC_ID_WMAV2:
 
210
        return i18n("Windows Media v2");
 
211
#if LIBAVCODEC_VERSION_MAJOR < 52
 
212
    case CODEC_ID_MP3LAME:
 
213
#else
 
214
    case CODEC_ID_MP3:
 
215
#endif
 
216
        return i18n("MPEG 1 Layer III");
 
217
    case CODEC_ID_AAC:
 
218
        return i18n("Advanced Audio Coding (AAC)");
 
219
    default:
 
220
        return QString::fromLocal8Bit( d->codec->name );
 
221
    }
 
222
}
 
223
 
 
224
 
 
225
QString K3bFFMpegFile::title() const
 
226
{
 
227
    // FIXME: is this UTF8 or something??
 
228
    if( d->formatContext->title[0] != '\0' )
 
229
        return QString::fromLocal8Bit( d->formatContext->title );
 
230
    else
 
231
        return QString();
 
232
}
 
233
 
 
234
 
 
235
QString K3bFFMpegFile::author() const
 
236
{
 
237
    // FIXME: is this UTF8 or something??
 
238
    if( d->formatContext->author[0] != '\0' )
 
239
        return QString::fromLocal8Bit( d->formatContext->author );
 
240
    else
 
241
        return QString();
 
242
}
 
243
 
 
244
 
 
245
QString K3bFFMpegFile::comment() const
 
246
{
 
247
    // FIXME: is this UTF8 or something??
 
248
    if( d->formatContext->comment[0] != '\0' )
 
249
        return QString::fromLocal8Bit( d->formatContext->comment );
 
250
    else
 
251
        return QString();
 
252
}
 
253
 
 
254
 
 
255
int K3bFFMpegFile::read( char* buf, int bufLen )
 
256
{
 
257
    int ret = fillOutputBuffer();
 
258
    if (ret <= 0) {
 
259
        return ret;
 
260
    }
 
261
 
 
262
    int len = qMin(bufLen, d->outputBufferSize);
 
263
    ::memcpy( buf, d->outputBufferPos, len );
 
264
 
 
265
    // TODO: only swap if needed
 
266
    for( int i = 0; i < len-1; i+=2 ) {
 
267
        char a = buf[i];
 
268
        buf[i] = buf[i+1];
 
269
        buf[i+1] = a;
 
270
    }
 
271
 
 
272
    d->outputBufferPos += len;
 
273
    d->outputBufferSize -= len;
 
274
    return len;
 
275
}
 
276
 
 
277
 
 
278
// fill d->packetData with data to decode
 
279
int K3bFFMpegFile::readPacket()
 
280
{
 
281
    if( d->packetSize <= 0 ) {
 
282
        ::av_init_packet( &d->packet );
 
283
 
 
284
        if( ::av_read_frame( d->formatContext, &d->packet ) < 0 ) {
 
285
            return 0;
 
286
        }
 
287
        d->packetSize = d->packet.size;
 
288
        d->packetData = d->packet.data;
 
289
    }
 
290
 
 
291
    return d->packetSize;
 
292
}
 
293
 
 
294
 
 
295
// decode data in d->packetData and fill d->outputBuffer
 
296
int K3bFFMpegFile::fillOutputBuffer()
 
297
{
 
298
    // decode if the output buffer is empty
 
299
    if( d->outputBufferSize <= 0 ) {
 
300
 
 
301
        // make sure we have data to decode
 
302
        if( readPacket() == 0 ) {
 
303
            return 0;
 
304
        }
 
305
 
 
306
        d->outputBufferPos = d->alignedOutputBuffer;
 
307
        d->outputBufferSize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
 
308
 
 
309
#if LIBAVCODEC_VERSION_MAJOR < 52
 
310
        int len = ::avcodec_decode_audio(
 
311
#else
 
312
        int len = ::avcodec_decode_audio2(
 
313
#endif
 
314
#ifdef FFMPEG_BUILD_PRE_4629
 
315
            &d->formatContext->streams[0]->codec,
 
316
#else
 
317
            d->formatContext->streams[0]->codec,
 
318
#endif
 
319
            (short*)d->alignedOutputBuffer,
 
320
            &d->outputBufferSize,
 
321
            d->packetData, d->packetSize );
 
322
 
 
323
        if( d->packetSize <= 0 || len < 0 )
 
324
            ::av_free_packet( &d->packet );
 
325
        if( len < 0 ) {
 
326
            kDebug() << "(K3bFFMpegFile) decoding failed for " << m_filename;
 
327
            return -1;
 
328
        }
 
329
 
 
330
        d->packetSize -= len;
 
331
        d->packetData += len;
 
332
    }
 
333
 
 
334
    // if it is still empty try again
 
335
    if( d->outputBufferSize <= 0 )
 
336
        return fillOutputBuffer();
 
337
    else
 
338
        return d->outputBufferSize;
 
339
}
 
340
 
 
341
 
 
342
bool K3bFFMpegFile::seek( const K3b::Msf& msf )
 
343
{
 
344
    d->outputBufferSize = 0;
 
345
    d->packetSize = 0;
 
346
 
 
347
    double seconds = (double)msf.totalFrames()/75.0;
 
348
    quint64 timestamp = (quint64)(seconds * (double)AV_TIME_BASE);
 
349
 
 
350
    // FIXME: do we really need the start_time and why?
 
351
#if LIBAVFORMAT_BUILD >= 4619
 
352
    return ( ::av_seek_frame( d->formatContext, -1, timestamp + d->formatContext->start_time, 0 ) >= 0 );
 
353
#else
 
354
    return ( ::av_seek_frame( d->formatContext, -1, timestamp + d->formatContext->start_time ) >= 0 );
 
355
#endif
 
356
}
 
357
 
 
358
 
 
359
 
 
360
 
 
361
 
 
362
 
 
363
K3bFFMpegWrapper::K3bFFMpegWrapper()
 
364
{
 
365
    ::av_register_all();
 
366
}
 
367
 
 
368
 
 
369
K3bFFMpegWrapper::~K3bFFMpegWrapper()
 
370
{
 
371
    s_instance = 0;
 
372
}
 
373
 
 
374
 
 
375
K3bFFMpegWrapper* K3bFFMpegWrapper::instance()
 
376
{
 
377
    if( !s_instance ) {
 
378
        s_instance = new K3bFFMpegWrapper();
 
379
    }
 
380
 
 
381
    return s_instance;
 
382
}
 
383
 
 
384
 
 
385
K3bFFMpegFile* K3bFFMpegWrapper::open( const QString& filename ) const
 
386
{
 
387
    K3bFFMpegFile* file = new K3bFFMpegFile( filename );
 
388
    if( file->open() ) {
 
389
#ifndef K3B_FFMPEG_ALL_CODECS
 
390
        //
 
391
        // only allow tested formats. ffmpeg seems not to be too reliable with every format.
 
392
        // mp3 being one of them sadly. Most importantly: allow the libsndfile decoder to do
 
393
        // its thing.
 
394
        //
 
395
        if( file->type() == CODEC_ID_WMAV1 ||
 
396
            file->type() == CODEC_ID_WMAV2 ||
 
397
            file->type() == CODEC_ID_AAC )
 
398
#endif
 
399
            return file;
 
400
    }
 
401
 
 
402
    delete file;
 
403
    return 0;
 
404
}