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

« back to all changes in this revision

Viewing changes to .pc/kubuntu_06_libav_0.7.diff/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
 
}