Changeset View
Changeset View
Standalone View
Standalone View
plugins/decoder/ffmpeg/k3bffmpegwrapper.cpp
Show All 29 Lines | |||||
30 | #include <libavformat/avformat.h> | 30 | #include <libavformat/avformat.h> | ||
31 | #else | 31 | #else | ||
32 | #include <ffmpeg/avcodec.h> | 32 | #include <ffmpeg/avcodec.h> | ||
33 | #include <ffmpeg/avformat.h> | 33 | #include <ffmpeg/avformat.h> | ||
34 | #endif | 34 | #endif | ||
35 | } | 35 | } | ||
36 | 36 | | |||
37 | #include <string.h> | 37 | #include <string.h> | ||
38 | #include <math.h> | ||||
38 | 39 | | |||
39 | 40 | | |||
40 | #if LIBAVFORMAT_BUILD < 4629 | 41 | #if LIBAVFORMAT_BUILD < 4629 | ||
41 | #define FFMPEG_CODEC(s) (&s->codec) | 42 | #define FFMPEG_CODEC(s) (&s->codec) | ||
42 | #else | 43 | #else | ||
43 | #define FFMPEG_CODEC(s) (s->codec) | 44 | #define FFMPEG_CODEC(s) (s->codec) | ||
44 | #endif | 45 | #endif | ||
45 | 46 | | |||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Line(s) | 91 | #else | |||
91 | char outputBuffer[AVCODEC_MAX_AUDIO_FRAME_SIZE + 15]; | 92 | char outputBuffer[AVCODEC_MAX_AUDIO_FRAME_SIZE + 15]; | ||
92 | char* alignedOutputBuffer; | 93 | char* alignedOutputBuffer; | ||
93 | #endif | 94 | #endif | ||
94 | char* outputBufferPos; | 95 | char* outputBufferPos; | ||
95 | int outputBufferSize; | 96 | int outputBufferSize; | ||
96 | ::AVPacket packet; | 97 | ::AVPacket packet; | ||
97 | quint8* packetData; | 98 | quint8* packetData; | ||
98 | int packetSize; | 99 | int packetSize; | ||
100 | bool isSpacious; | ||||
101 | int sampleFormat; | ||||
99 | }; | 102 | }; | ||
100 | 103 | | |||
101 | 104 | | |||
102 | K3bFFMpegFile::K3bFFMpegFile( const QString& filename ) | 105 | K3bFFMpegFile::K3bFFMpegFile( const QString& filename ) | ||
103 | : m_filename(filename) | 106 | : m_filename(filename) | ||
104 | { | 107 | { | ||
105 | d = new Private; | 108 | d = new Private; | ||
106 | d->formatContext = 0; | 109 | d->formatContext = 0; | ||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Line(s) | 139 | { | |||
177 | // determine the length of the stream | 180 | // determine the length of the stream | ||
178 | d->length = K3b::Msf::fromSeconds( (double)d->formatContext->duration / (double)AV_TIME_BASE ); | 181 | d->length = K3b::Msf::fromSeconds( (double)d->formatContext->duration / (double)AV_TIME_BASE ); | ||
179 | 182 | | |||
180 | if( d->length == 0 ) { | 183 | if( d->length == 0 ) { | ||
181 | qDebug() << "(K3bFFMpegDecoderFactory) invalid length."; | 184 | qDebug() << "(K3bFFMpegDecoderFactory) invalid length."; | ||
182 | return false; | 185 | return false; | ||
183 | } | 186 | } | ||
184 | 187 | | |||
188 | d->isSpacious = ::av_sample_fmt_is_planar( | ||||
189 | FFMPEG_CODEC(d->formatContext->streams[0])->sample_fmt) | ||||
190 | && FFMPEG_CODEC(d->formatContext->streams[0])->channels > 1; | ||||
191 | d->sampleFormat = FFMPEG_CODEC(d->formatContext->streams[0])->sample_fmt; | ||||
192 | | ||||
185 | // dump some debugging info | 193 | // dump some debugging info | ||
186 | ::av_dump_format( d->formatContext, 0, m_filename.toLocal8Bit(), 0 ); | 194 | ::av_dump_format( d->formatContext, 0, m_filename.toLocal8Bit(), 0 ); | ||
187 | 195 | | |||
188 | return true; | 196 | return true; | ||
189 | } | 197 | } | ||
190 | 198 | | |||
191 | 199 | | |||
192 | void K3bFFMpegFile::close() | 200 | void K3bFFMpegFile::close() | ||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Line(s) | 244 | #if LIBAVCODEC_BUILD < AV_VERSION_INT(54,25,0) | |||
239 | #define AV_CODEC_ID_MP3 CODEC_ID_MP3 | 247 | #define AV_CODEC_ID_MP3 CODEC_ID_MP3 | ||
240 | #define AV_CODEC_ID_AAC CODEC_ID_AAC | 248 | #define AV_CODEC_ID_AAC CODEC_ID_AAC | ||
241 | #endif | 249 | #endif | ||
242 | switch( type() ) { | 250 | switch( type() ) { | ||
243 | case AV_CODEC_ID_WMAV1: | 251 | case AV_CODEC_ID_WMAV1: | ||
244 | return i18n("Windows Media v1"); | 252 | return i18n("Windows Media v1"); | ||
245 | case AV_CODEC_ID_WMAV2: | 253 | case AV_CODEC_ID_WMAV2: | ||
246 | return i18n("Windows Media v2"); | 254 | return i18n("Windows Media v2"); | ||
247 | case AV_CODEC_ID_MP3: | 255 | case AV_CODEC_ID_WAVPACK: | ||
248 | return i18n("MPEG 1 Layer III"); | 256 | return i18n("WavPack"); | ||
257 | case AV_CODEC_ID_APE: | ||||
258 | return i18n("Monkey's Audio (APE)"); | ||||
249 | case AV_CODEC_ID_AAC: | 259 | case AV_CODEC_ID_AAC: | ||
250 | return i18n("Advanced Audio Coding (AAC)"); | 260 | return i18n("Advanced Audio Coding (AAC)"); | ||
251 | default: | 261 | default: | ||
252 | return QString::fromLocal8Bit( d->codec->name ); | 262 | return QString::fromLocal8Bit( d->codec->name ); | ||
253 | } | 263 | } | ||
254 | } | 264 | } | ||
255 | 265 | | |||
256 | 266 | | |||
Show All 29 Lines | 292 | { | |||
286 | int ret = fillOutputBuffer(); | 296 | int ret = fillOutputBuffer(); | ||
287 | if (ret <= 0) { | 297 | if (ret <= 0) { | ||
288 | return ret; | 298 | return ret; | ||
289 | } | 299 | } | ||
290 | 300 | | |||
291 | int len = qMin(bufLen, d->outputBufferSize); | 301 | int len = qMin(bufLen, d->outputBufferSize); | ||
292 | ::memcpy(buf, d->outputBufferPos, len); | 302 | ::memcpy(buf, d->outputBufferPos, len); | ||
293 | 303 | | |||
304 | if(d->isSpacious && bufLen > d->outputBufferSize) | ||||
305 | delete[] d->outputBufferPos; // clean up allocated space | ||||
306 | | ||||
294 | // TODO: only swap if needed | 307 | // TODO: only swap if needed | ||
295 | for( int i = 0; i < len-1; i+=2 ) { | 308 | for(int i=0; i<len-1; i+=2) | ||
296 | char a = buf[i]; | 309 | qSwap(buf[i], buf[i+1]); // BE -> LE | ||
297 | buf[i] = buf[i+1]; | | |||
298 | buf[i+1] = a; | | |||
299 | } | | |||
300 | 310 | | |||
301 | d->outputBufferPos += len; | | |||
302 | d->outputBufferSize -= len; | 311 | d->outputBufferSize -= len; | ||
312 | if(d->outputBufferSize > 0) | ||||
313 | d->outputBufferPos += len; | ||||
303 | return len; | 314 | return len; | ||
304 | } | 315 | } | ||
305 | 316 | | |||
306 | 317 | | |||
307 | // fill d->packetData with data to decode | 318 | // fill d->packetData with data to decode | ||
308 | int K3bFFMpegFile::readPacket() | 319 | int K3bFFMpegFile::readPacket() | ||
309 | { | 320 | { | ||
310 | if( d->packetSize <= 0 ) { | 321 | if( d->packetSize <= 0 ) { | ||
311 | ::av_init_packet( &d->packet ); | 322 | ::av_init_packet( &d->packet ); | ||
312 | 323 | | |||
313 | if( ::av_read_frame( d->formatContext, &d->packet ) < 0 ) { | 324 | if( ::av_read_frame( d->formatContext, &d->packet ) < 0 ) { | ||
314 | return 0; | 325 | return 0; | ||
anthonyfieroni: This should be delete[] | |||||
315 | } | 326 | } | ||
316 | d->packetSize = d->packet.size; | 327 | d->packetSize = d->packet.size; | ||
317 | d->packetData = d->packet.data; | 328 | d->packetData = d->packet.data; | ||
318 | } | 329 | } | ||
319 | 330 | | |||
320 | return d->packetSize; | 331 | return d->packetSize; | ||
anthonyfieroni: What about here, it advance on dangling pointer? | |||||
321 | } | 332 | } | ||
322 | 333 | | |||
323 | 334 | | |||
324 | // decode data in d->packetData and fill d->outputBuffer | 335 | // decode data in d->packetData and fill d->outputBuffer | ||
325 | int K3bFFMpegFile::fillOutputBuffer() | 336 | int K3bFFMpegFile::fillOutputBuffer() | ||
326 | { | 337 | { | ||
327 | // decode if the output buffer is empty | 338 | // decode if the output buffer is empty | ||
328 | if( d->outputBufferSize <= 0 ) { | 339 | while(d->outputBufferSize <= 0) { | ||
329 | 340 | | |||
330 | // make sure we have data to decode | 341 | // make sure we have data to decode | ||
331 | if( readPacket() == 0 ) { | 342 | if( readPacket() == 0 ) { | ||
332 | return 0; | 343 | return 0; | ||
333 | } | 344 | } | ||
334 | 345 | | |||
335 | #ifdef HAVE_FFMPEG_AVCODEC_DECODE_AUDIO4 | 346 | #ifdef HAVE_FFMPEG_AVCODEC_DECODE_AUDIO4 | ||
336 | int gotFrame = 0; | 347 | int gotFrame = 0; | ||
Show All 34 Lines | 381 | #else | |||
371 | ::av_free_packet( &d->packet ); | 382 | ::av_free_packet( &d->packet ); | ||
372 | #endif | 383 | #endif | ||
373 | if( len < 0 ) { | 384 | if( len < 0 ) { | ||
374 | qDebug() << "(K3bFFMpegFile) decoding failed for " << m_filename; | 385 | qDebug() << "(K3bFFMpegFile) decoding failed for " << m_filename; | ||
375 | return -1; | 386 | return -1; | ||
376 | } | 387 | } | ||
377 | 388 | | |||
378 | #ifdef HAVE_FFMPEG_AVCODEC_DECODE_AUDIO4 | 389 | #ifdef HAVE_FFMPEG_AVCODEC_DECODE_AUDIO4 | ||
379 | if ( gotFrame ) { | 390 | if (gotFrame) { | ||
380 | d->outputBufferSize = ::av_samples_get_buffer_size( | 391 | int nb_s = d->frame->nb_samples; | ||
381 | NULL, | 392 | int nb_ch = 2; // copy only two channels even if there're more | ||
382 | FFMPEG_CODEC(d->formatContext->streams[0])->channels, | 393 | d->outputBufferSize = nb_s * nb_ch * 2; // 2 means 2 bytes (16bit) | ||
383 | d->frame->nb_samples, | 394 | d->outputBufferPos = reinterpret_cast<char*>( | ||
384 | FFMPEG_CODEC(d->formatContext->streams[0])->sample_fmt, | 395 | d->frame->extended_data[0]); | ||
385 | 1 ); | 396 | if(d->isSpacious) { | ||
386 | d->outputBufferPos = reinterpret_cast<char*>( d->frame->data[0] ); | 397 | d->outputBufferPos = new char[d->outputBufferSize]; | ||
398 | if(d->sampleFormat == AV_SAMPLE_FMT_FLTP) { | ||||
399 | int width = sizeof(float); // sample width of float audio | ||||
400 | for(int sample=0; sample<nb_s; sample++) { | ||||
401 | for(int ch=0; ch<nb_ch; ch++) { | ||||
402 | float val = *(reinterpret_cast<float*>( | ||||
403 | d->frame->extended_data[ch] + sample * width)); | ||||
404 | val = ::abs(val) > 1 ? ::copysign(1.0, val) : val; | ||||
405 | int16_t result = static_cast<int16_t>( | ||||
406 | val * 32767.0 + 32768.5) - 32768; | ||||
407 | ::memcpy(d->outputBufferPos + (sample*nb_ch+ch) * 2, | ||||
408 | &result, | ||||
409 | 2); // 2 is sample width of 16 bit audio | ||||
410 | } | ||||
411 | } | ||||
412 | } else { | ||||
413 | for(int sample=0; sample<nb_s; sample++) { | ||||
414 | for(int ch=0; ch<nb_ch; ch++) { | ||||
415 | ::memcpy(d->outputBufferPos + (sample*nb_ch+ch) * 2, | ||||
416 | d->frame->extended_data[ch] + sample * 2, | ||||
417 | 2); // 16 bit here as well | ||||
418 | } | ||||
419 | } | ||||
420 | } | ||||
421 | } | ||||
387 | } | 422 | } | ||
388 | #endif | 423 | #endif | ||
389 | d->packetSize -= len; | 424 | d->packetSize -= len; | ||
390 | d->packetData += len; | 425 | d->packetData += len; | ||
391 | } | 426 | } | ||
392 | 427 | | |||
393 | // if it is still empty try again | | |||
394 | if( d->outputBufferSize <= 0 ) | | |||
395 | return fillOutputBuffer(); | | |||
396 | else | | |||
397 | return d->outputBufferSize; | 428 | return d->outputBufferSize; | ||
398 | } | 429 | } | ||
399 | 430 | | |||
400 | 431 | | |||
401 | bool K3bFFMpegFile::seek( const K3b::Msf& msf ) | 432 | bool K3bFFMpegFile::seek( const K3b::Msf& msf ) | ||
402 | { | 433 | { | ||
403 | d->outputBufferSize = 0; | 434 | d->outputBufferSize = 0; | ||
404 | d->packetSize = 0; | 435 | d->packetSize = 0; | ||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Line(s) | |||||
448 | #ifndef K3B_FFMPEG_ALL_CODECS | 479 | #ifndef K3B_FFMPEG_ALL_CODECS | ||
449 | // | 480 | // | ||
450 | // only allow tested formats. ffmpeg seems not to be too reliable with every format. | 481 | // only allow tested formats. ffmpeg seems not to be too reliable with every format. | ||
451 | // mp3 being one of them sadly. Most importantly: allow the libsndfile decoder to do | 482 | // mp3 being one of them sadly. Most importantly: allow the libsndfile decoder to do | ||
452 | // its thing. | 483 | // its thing. | ||
453 | // | 484 | // | ||
454 | if( file->type() == AV_CODEC_ID_WMAV1 || | 485 | if( file->type() == AV_CODEC_ID_WMAV1 || | ||
455 | file->type() == AV_CODEC_ID_WMAV2 || | 486 | file->type() == AV_CODEC_ID_WMAV2 || | ||
456 | file->type() == AV_CODEC_ID_AAC ) | 487 | file->type() == AV_CODEC_ID_AAC || | ||
488 | file->type() == AV_CODEC_ID_APE || | ||||
489 | file->type() == AV_CODEC_ID_WAVPACK ) | ||||
457 | #endif | 490 | #endif | ||
458 | return file; | 491 | return file; | ||
459 | } | 492 | } | ||
460 | 493 | | |||
461 | delete file; | 494 | delete file; | ||
462 | return 0; | 495 | return 0; | ||
463 | } | 496 | } |
This should be delete[]