Fix test for bug #32625
[gnash.git] / libmedia / ffmpeg / AudioDecoderFfmpeg.cpp
blobbdeedc62eb1a0f51ff1e08623876b0bef5bfde16
1 // AudioDecoderFfmpeg.cpp: Audio decoding using the FFmpeg library.
2 //
3 // Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "AudioDecoderFfmpeg.h"
22 #include <cmath> // for std::ceil
23 #include <algorithm> // for std::copy, std::max
25 #include "MediaParserFfmpeg.h" // for ExtraAudioInfoFfmpeg
26 #include "FLVParser.h"
27 #include "SoundInfo.h"
28 #include "MediaParser.h" // for AudioInfo
30 //#define GNASH_DEBUG_AUDIO_DECODING
32 #define AVCODEC_DECODE_AUDIO avcodec_decode_audio2
34 namespace gnash {
35 namespace media {
36 namespace ffmpeg {
38 AudioDecoderFfmpeg::AudioDecoderFfmpeg(const AudioInfo& info)
40 _audioCodec(NULL),
41 _audioCodecCtx(NULL),
42 _parser(NULL),
43 _needsParsing(false)
45 setup(info);
47 if (info.type == CODEC_TYPE_CUSTOM) {
48 log_debug(_("AudioDecoderFfmpeg: initialized FFmpeg codec %d (%s)"),
49 _audioCodec->id, _audioCodec->name);
50 } else {
51 log_debug(_("AudioDecoderFfmpeg: initialized FFmpeg codec %d (%s) "
52 "for flash codec %d (%s)"),
53 _audioCodec->id, _audioCodec->name,
54 info.codec, (audioCodecType)info.codec);
58 AudioDecoderFfmpeg::AudioDecoderFfmpeg(SoundInfo& info)
60 _audioCodec(NULL),
61 _audioCodecCtx(NULL),
62 _parser(NULL)
64 setup(info);
66 log_debug(_("AudioDecoderFfmpeg: initialized FFmpeg codec %s (%d)"),
67 _audioCodec->name, _audioCodec->id);
70 AudioDecoderFfmpeg::~AudioDecoderFfmpeg()
72 if (_audioCodecCtx)
74 avcodec_close(_audioCodecCtx);
75 av_free(_audioCodecCtx);
77 if (_parser) av_parser_close(_parser);
80 void AudioDecoderFfmpeg::setup(SoundInfo& info)
82 // Init the avdecoder-decoder
83 avcodec_init();
84 avcodec_register_all();// change this to only register need codec?
86 enum CodecID codec_id;
88 switch(info.getFormat()) {
89 case AUDIO_CODEC_RAW:
90 codec_id = CODEC_ID_PCM_U16LE;
91 break;
92 case AUDIO_CODEC_ADPCM:
93 codec_id = CODEC_ID_ADPCM_SWF;
94 break;
95 case AUDIO_CODEC_MP3:
96 codec_id = CODEC_ID_MP3;
97 _needsParsing=true;
98 break;
99 case AUDIO_CODEC_AAC:
100 codec_id = CODEC_ID_AAC;
101 _needsParsing=true;
102 break;
103 default:
104 boost::format err = boost::format(
105 _("Unsupported audio codec %d")) %
106 static_cast<int>(info.getFormat());
107 throw MediaException(err.str());
110 _audioCodec = avcodec_find_decoder(codec_id);
111 if (!_audioCodec) {
112 audioCodecType codec = info.getFormat();
113 boost::format err = boost::format(
114 _("libavcodec could not find a decoder for codec %d (%s)")) %
115 static_cast<int>(codec) % codec;
116 throw MediaException(err.str());
119 if ( _needsParsing )
121 // Init the parser
122 _parser = av_parser_init(codec_id);
123 if (!_parser) {
124 throw MediaException(_("AudioDecoderFfmpeg can't initialize "
125 "MP3 parser"));
129 _audioCodecCtx = avcodec_alloc_context();
130 if (!_audioCodecCtx) {
131 throw MediaException(_("libavcodec couldn't allocate context"));
134 int ret = avcodec_open(_audioCodecCtx, _audioCodec);
135 if (ret < 0) {
136 av_free(_audioCodecCtx);
137 _audioCodecCtx=0;
138 boost::format err = boost::format(
139 _("AudioDecoderFfmpeg: avcodec_open failed to initialize "
140 "FFmpeg codec %s (%d)")) % _audioCodec->name % (int)codec_id;
141 throw MediaException(err.str());
144 log_debug(_("AudioDecoder: initialized FFMPEG codec %s (%d)"),
145 _audioCodec->name, (int)codec_id);
147 /// @todo do this only if !_needsParsing ?
148 switch (_audioCodecCtx->codec->id)
150 case CODEC_ID_MP3:
151 break;
153 case CODEC_ID_PCM_U16LE:
154 _audioCodecCtx->channels = (info.isStereo() ? 2 : 1);
155 _audioCodecCtx->sample_rate = info.getSampleRate();
156 _audioCodecCtx->sample_fmt = SAMPLE_FMT_S16; // ?! arbitrary ?
157 _audioCodecCtx->frame_size = 1;
158 break;
160 default:
161 _audioCodecCtx->channels = (info.isStereo() ? 2 : 1);
162 _audioCodecCtx->sample_rate = info.getSampleRate();
163 _audioCodecCtx->sample_fmt = SAMPLE_FMT_S16; // ?! arbitrary ?
164 break;
168 void AudioDecoderFfmpeg::setup(const AudioInfo& info)
170 // Init the avdecoder-decoder
171 avcodec_init();
172 avcodec_register_all();// change this to only register need codec?
174 enum CodecID codec_id = CODEC_ID_NONE;
176 if (info.type == CODEC_TYPE_CUSTOM)
178 codec_id = static_cast<CodecID>(info.codec);
179 _needsParsing=true; // @todo check this !
181 else if (info.type == CODEC_TYPE_FLASH)
184 switch(info.codec)
186 case AUDIO_CODEC_UNCOMPRESSED:
187 case AUDIO_CODEC_RAW:
188 if (info.sampleSize == 2) {
189 codec_id = CODEC_ID_PCM_S16LE;
190 } else {
191 codec_id = CODEC_ID_PCM_S8;
193 break;
195 case AUDIO_CODEC_ADPCM:
196 codec_id = CODEC_ID_ADPCM_SWF;
197 break;
199 case AUDIO_CODEC_MP3:
200 codec_id = CODEC_ID_MP3;
201 _needsParsing=true;
202 break;
204 case AUDIO_CODEC_AAC:
205 codec_id = CODEC_ID_AAC;
206 _needsParsing=true;
207 break;
209 #ifdef FFMPEG_NELLYMOSER
210 // NOTE: bjacques found this failing in decodeFrame
211 // (but probably not Ffmpeg's fault, he said)
212 // I'd like to take a look at the testcase --strk
213 case AUDIO_CODEC_NELLYMOSER:
214 codec_id = CODEC_ID_NELLYMOSER;
215 // needs parsing ?
216 break;
217 #endif
219 default:
220 boost::format err = boost::format(
221 _("AudioDecoderFfmpeg: unsupported flash audio "
222 "codec %d (%s)")) %
223 info.codec % (audioCodecType)info.codec;
224 throw MediaException(err.str());
227 else
229 boost::format err = boost::format(
230 _("AudioDecoderFfmpeg: unknown codec type %d "
231 "(should never happen)")) % info.type;
232 throw MediaException(err.str());
235 _audioCodec = avcodec_find_decoder(codec_id);
236 if (!_audioCodec)
238 if (info.type == CODEC_TYPE_FLASH) {
239 boost::format err = boost::format(
240 _("AudioDecoderFfmpeg: libavcodec could not find a decoder "
241 "for codec %d (%s)")) %
242 info.codec % static_cast<audioCodecType>(info.codec);
243 throw MediaException(err.str());
244 } else {
245 boost::format err = boost::format(
246 _("AudioDecoderFfmpeg: libavcodec could not find a decoder "
247 "for ffmpeg codec id %s")) % codec_id;
248 throw MediaException(err.str());
252 // Init the parser
253 if (_needsParsing)
255 #ifdef GNASH_DEBUG_AUDIO_DECODING
256 log_debug(" Initializing ffmpeg parser");
257 #endif // GNASH_DEBUG_AUDIO_DECODING
258 _parser = av_parser_init(codec_id);
259 if (!_parser) {
260 boost::format err;
261 if (info.type == CODEC_TYPE_FLASH) {
262 err = boost::format(
263 _("AudioDecoderFfmpeg: could not initialize a parser for "
264 "flash codec id %d (%s)")) %
265 info.codec % (audioCodecType)info.codec;
266 } else {
267 err = boost::format(
268 _("AudioDecoderFfmpeg: could not initialize a parser "
269 "for ffmpeg codec id %s")) % codec_id;
271 throw MediaException(err.str());
273 #ifdef GNASH_DEBUG_AUDIO_DECODING
274 log_debug(" Ffmpeg parser initialized");
275 #endif // GNASH_DEBUG_AUDIO_DECODING
278 // Create an audioCodecCtx from the ffmpeg parser if exists/possible
279 _audioCodecCtx = avcodec_alloc_context();
280 if (!_audioCodecCtx) {
281 throw MediaException(_("AudioDecoderFfmpeg: libavcodec couldn't "
282 "allocate context"));
285 if ( info.extra.get() )
287 if (dynamic_cast<ExtraAudioInfoFfmpeg*>(info.extra.get())) {
288 const ExtraAudioInfoFfmpeg& ei =
289 static_cast<ExtraAudioInfoFfmpeg&>(*info.extra);
290 _audioCodecCtx->extradata = ei.data;
291 _audioCodecCtx->extradata_size = ei.dataSize;
292 } else if (dynamic_cast<ExtraAudioInfoFlv*>(info.extra.get())) {
293 ExtraAudioInfoFlv* extra =
294 static_cast<ExtraAudioInfoFlv*>(info.extra.get());
295 _audioCodecCtx->extradata = extra->data.get();
296 _audioCodecCtx->extradata_size = extra->size;
300 // Setup known configurations for the audio codec context
301 // (should this be done only if ! _needsParsing?)
302 // NOTE: this is done before calling avcodec_open, as that might update
303 // some of the variables
304 switch (codec_id)
306 case CODEC_ID_MP3:
307 break;
309 case CODEC_ID_PCM_S8:
310 // Either FFMPEG or the parser are getting this wrong.
311 _audioCodecCtx->sample_rate = info.sampleRate / 2;
312 _audioCodecCtx->channels = (info.stereo ? 2 : 1);
313 break;
314 case CODEC_ID_PCM_S16LE:
315 _audioCodecCtx->channels = (info.stereo ? 2 : 1);
316 _audioCodecCtx->sample_rate = info.sampleRate;
317 break;
319 default:
320 _audioCodecCtx->channels = (info.stereo ? 2 : 1);
321 _audioCodecCtx->sample_rate = info.sampleRate;
322 // was commented out (why?):
323 _audioCodecCtx->sample_fmt = SAMPLE_FMT_S16;
324 break;
328 #ifdef GNASH_DEBUG_AUDIO_DECODING
329 log_debug(" Opening codec");
330 #endif // GNASH_DEBUG_AUDIO_DECODING
331 int ret = avcodec_open(_audioCodecCtx, _audioCodec);
332 if (ret < 0) {
333 //avcodec_close(_audioCodecCtx);
334 av_free(_audioCodecCtx);
335 _audioCodecCtx = 0;
337 boost::format err = boost::format(
338 _("AudioDecoderFfmpeg: avcodec_open failed to initialize "
339 "FFmpeg codec %s (%d)")) % _audioCodec->name % (int)codec_id;
340 throw MediaException(err.str());
345 boost::uint8_t*
346 AudioDecoderFfmpeg::decode(const boost::uint8_t* input,
347 boost::uint32_t inputSize, boost::uint32_t&
348 outputSize, boost::uint32_t& decodedBytes,
349 bool parse)
351 //GNASH_REPORT_FUNCTION;
353 if ( ! parse )
355 if ( _needsParsing )
357 log_error("AudioDecoderFfmpeg::decode called with 'parse' "
358 "parameter off but we know we need parsing for this codec");
361 else
363 if ( !_needsParsing )
365 assert(!_parser); // so we can directly return here...
366 log_debug("AudioDecoderFfmpeg::decode called with 'parse' "
367 "parameter on but we know we don't need parsing for "
368 "this codec");
369 parse = false; // let's believe in us !
373 size_t retCapacity = AVCODEC_MAX_AUDIO_FRAME_SIZE;
374 boost::uint8_t* retBuf = new boost::uint8_t[retCapacity];
375 int retBufSize = 0;
377 #ifdef GNASH_DEBUG_AUDIO_DECODING
378 log_debug(" Parsing loop starts, input is %d bytes, retCapacity is %d "
379 "bytes", inputSize, retCapacity);
380 #endif
381 decodedBytes = 0; // nothing decoded yet
382 while (decodedBytes < inputSize)
384 const boost::uint8_t* frame=0; // parsed frame (pointer into input)
385 int framesize; // parsed frame size
387 int consumed = parseInput(input+decodedBytes,
388 inputSize-decodedBytes,
389 &frame, &framesize);
390 if (consumed < 0)
392 log_error(_("av_parser_parse returned %d. "
393 "Upgrading ffmpeg/libavcodec might fix this issue."),
394 consumed);
395 // Setting data position to data size will get the sound removed
396 // from the active sound list later on.
397 decodedBytes = inputSize;
398 break;
401 #ifdef GNASH_DEBUG_AUDIO_DECODING
402 log_debug(" parsed frame is %d bytes (consumed +%d = %d/%d)",
403 framesize, consumed, decodedBytes+consumed, inputSize);
404 #endif
406 #if GNASH_PARANOIA_LEVEL > 1
407 if ( frame )
409 // the returned frame pointer is inside the input buffer
410 assert(frame == input+decodedBytes);
411 // the returned frame size is within the input size
412 assert(framesize <= inputSize);
414 #endif
416 // all good so far, keep going..
417 // (we might do this immediately, as we'll override decodedBytes
418 // on error anyway)
419 decodedBytes += consumed;
421 if ( ! framesize )
423 // If nothing is consumed, this will fail. It can happen if a
424 // block is passed to the decoder when nothing can be
425 // parsed from the block. This is probably a malformed SWF.
426 //assert(decodedBytes == inputSize);
428 // NOTE: If this happens the caller sent us
429 // a block of data which is not composed
430 // by complete audio frames.
431 // Could be due to an error in the caller
432 // code, or to a malformed SWF...
433 // At time of writing this (2008-11-01)
434 // it is most likely an error in caller
435 // code (streaming sound/event sound)
436 // so we log an ERROR rather then a
437 // MALFORMED input. You can uncomment the
438 // abort below to check who is the caller
439 // with gdb. When callers are checked,
440 // we may turn this into a MALFORMED
441 // kind of error (DEFINESOUND, SOUNDSTREAMBLOCK
442 // or FLV AudioTag not containing full audio frames)
445 log_error("AudioDecoderFfmpeg: "
446 "could not find a complete frame in "
447 "the last %d bytes of input"
448 " (malformed SWF or FLV?)",
449 consumed);
450 //abort();
451 continue;
455 // Now, decode the frame. We use the ::decodeFrame specialized function
456 // here so resampling is done appropriately
457 boost::uint32_t outSize = 0;
458 boost::scoped_array<boost::uint8_t> outBuf(
459 decodeFrame(frame, framesize, outSize));
461 if (!outBuf)
463 // Setting data position to data size will get the sound removed
464 // from the active sound list later on.
465 decodedBytes = inputSize;
466 break;
469 #ifdef GNASH_DEBUG_AUDIO_DECODING
470 log_debug(" decoded frame is %d bytes, would grow return "
471 "buffer size to %d bytes", outSize,
472 retBufSize+static_cast<unsigned int>(outSize));
473 #endif
476 // Now append this data to the buffer we're going to return
479 // if the new data doesn't fit, reallocate the output
480 // TODO: can use the Buffer class here.. if we return it too...
481 if ( retBufSize+(unsigned)outSize > retCapacity )
483 #ifdef GNASH_DEBUG_AUDIO_DECODING
484 log_debug(" output buffer won't be able to hold %d bytes, "
485 "capacity is only %d bytes",
486 retBufSize+(unsigned)outSize, retCapacity);
487 #endif
489 boost::uint8_t* tmp = retBuf;
490 retCapacity = std::max(retBufSize+static_cast<size_t>(outSize),
491 retCapacity * 2);
493 #ifdef GNASH_DEBUG_AUDIO_DECODING
494 log_debug(" reallocating it to hold up to %d bytes",
495 retCapacity);
496 #endif // GNASH_DEBUG_AUDIO_DECODING
498 retBuf = new boost::uint8_t[retCapacity];
499 if ( retBufSize ) std::copy(tmp, tmp+retBufSize, retBuf);
500 delete [] tmp;
502 std::copy(outBuf.get(), outBuf.get()+outSize, retBuf+retBufSize);
503 retBufSize += static_cast<unsigned int>(outSize);
507 outputSize = retBufSize;
508 return retBuf;
512 boost::uint8_t*
513 AudioDecoderFfmpeg::decode(const EncodedAudioFrame& ef,
514 boost::uint32_t& outputSize)
516 return decodeFrame(ef.data.get(), ef.dataSize, outputSize);
519 boost::uint8_t*
520 AudioDecoderFfmpeg::decodeFrame(const boost::uint8_t* input,
521 boost::uint32_t inputSize, boost::uint32_t& outputSize)
523 //GNASH_REPORT_FUNCTION;
525 assert(inputSize);
527 const size_t bufsize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
529 // TODO: make this a private member, to reuse (see NetStreamFfmpeg in 0.8.3)
530 boost::uint8_t* output;
532 output = reinterpret_cast<boost::uint8_t*>(av_malloc(bufsize));
533 if (!output) {
534 log_error(_("failed to allocate audio buffer."));
535 outputSize = 0;
536 return NULL;
539 boost::int16_t* outPtr = reinterpret_cast<boost::int16_t*>(output);
541 // We initialize output size to the full size
542 // then decoding will eventually reduce it
543 int outSize = bufsize;
545 #ifdef GNASH_DEBUG_AUDIO_DECODING
546 log_debug("AudioDecoderFfmpeg: about to decode %d bytes; "
547 "ctx->channels:%d, avctx->frame_size:%d",
548 inputSize, _audioCodecCtx->channels, _audioCodecCtx->frame_size);
549 #endif
551 // older ffmpeg versions didn't accept a const input..
552 int tmp = AVCODEC_DECODE_AUDIO(_audioCodecCtx, outPtr, &outSize,
553 input, inputSize);
555 #ifdef GNASH_DEBUG_AUDIO_DECODING
556 log_debug(" avcodec_decode_audio[2](ctx, bufptr, %d, input, %d) "
557 "returned %d; set frame_size=%d",
558 bufsize, inputSize, tmp, outSize);
559 #endif
561 if (tmp < 0) {
562 log_error(_("avcodec_decode_audio returned %d. Upgrading "
563 "ffmpeg/libavcodec might fix this issue."), tmp);
564 outputSize = 0;
566 av_free(output);
567 return NULL;
570 if (outSize < 2) {
571 log_error(_("outputSize:%d after decoding %d bytes of input audio "
572 "data. Upgrading ffmpeg/libavcodec might fix this issue."),
573 outputSize, inputSize);
574 outputSize = 0;
576 av_free(output);
577 return NULL;
580 // Resampling is needed.
581 if (_resampler.init(_audioCodecCtx)) {
582 // Resampling is needed.
584 // Compute new size based on frame_size and
585 // resampling configuration
586 double resampleFactor = (44100.0/_audioCodecCtx->sample_rate) * (2.0/_audioCodecCtx->channels);
587 bool stereo = _audioCodecCtx->channels > 1 ? true : false;
588 int inSamples = stereo ? outSize >> 2 : outSize >> 1;
590 int expectedMaxOutSamples = std::ceil(inSamples*resampleFactor);
592 // *channels *sampleSize
593 int resampledFrameSize = expectedMaxOutSamples*2*2;
595 // Allocate just the required amount of bytes
596 boost::uint8_t* resampledOutput = new boost::uint8_t[resampledFrameSize];
598 #ifdef GNASH_DEBUG_AUDIO_DECODING
599 log_debug("Calling the resampler; resampleFactor:%d; "
600 "ouput to 44100hz, 2channels, %dbytes; "
601 "input is %dhz, %dchannels, %dbytes, %dsamples",
602 resampleFactor,
603 resampledFrameSize, _audioCodecCtx->sample_rate,
604 _audioCodecCtx->channels, outSize, inSamples);
605 #endif
607 int outSamples = _resampler.resample(outPtr, // input
608 reinterpret_cast<boost::int16_t*>(resampledOutput), // output
609 inSamples); // input..
611 #ifdef GNASH_DEBUG_AUDIO_DECODING
612 log_debug("resampler returned %d samples ", outSamples);
613 #endif
615 // make sure to set outPtr *after* we use it as input to the resampler
616 outPtr = reinterpret_cast<boost::int16_t*>(resampledOutput);
618 av_free(output);
620 if (expectedMaxOutSamples < outSamples) {
621 log_error(" --- Computation of resampled samples (%d) < then the actual returned samples (%d)",
622 expectedMaxOutSamples, outSamples);
624 log_debug(" input frame size: %d", outSize);
625 log_debug(" input sample rate: %d", _audioCodecCtx->sample_rate);
626 log_debug(" input channels: %d", _audioCodecCtx->channels);
627 log_debug(" input samples: %d", inSamples);
629 log_debug(" output sample rate (assuming): %d", 44100);
630 log_debug(" output channels (assuming): %d", 2);
631 log_debug(" output samples: %d", outSamples);
633 /// Memory errors...
634 abort();
637 // Use the actual number of samples returned, multiplied
638 // to get size in bytes (not two-byte samples) and for
639 // stereo?
640 outSize = outSamples * 2 * 2;
643 else {
644 boost::uint8_t* newOutput = new boost::uint8_t[outSize];
645 std::memcpy(newOutput, output, outSize);
646 outPtr = reinterpret_cast<boost::int16_t*>(newOutput);
647 av_free(output);
650 outputSize = outSize;
651 return reinterpret_cast<uint8_t*>(outPtr);
655 AudioDecoderFfmpeg::parseInput(const boost::uint8_t* input,
656 boost::uint32_t inputSize,
657 boost::uint8_t const ** outFrame, int* outFrameSize)
659 if ( _needsParsing )
661 return av_parser_parse(_parser, _audioCodecCtx,
662 // as of 2008-10-28 SVN, ffmpeg doesn't
663 // accept a pointer to pointer to const..
664 const_cast<boost::uint8_t**>(outFrame),
665 outFrameSize,
666 input, inputSize,
667 0, 0); // pts & dts
669 else
671 // democratic value for a chunk to decode...
672 // @todo this might be constrained by codec id, check that !
674 // NOTE: AVCODEC_MAX_AUDIO_FRAME_SIZE resulted bigger
675 // than avcodec_decode_audio could handle, resulting
676 // in eventSoundTest1.swf regression.
677 //static const unsigned int maxFrameSize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
679 // NOTE: 1024 resulted too few
680 // to properly decode (or resample?) raw audio
681 // thus resulting noisy (bugs #21177 and #22284)
682 //static const unsigned int maxFrameSize = 1024;
684 // NOTE: 96000 was found to be the max returned
685 // by avcodec_decode_audio when passed anything
686 // bigger than that. Works fine with all of
687 // eventSoundTest1.swf, bug #21177 and bug #22284
689 static const unsigned int maxFrameSize = 96000;
691 int frameSize = inputSize < maxFrameSize ? inputSize : maxFrameSize;
693 // we assume the input is just a set of frames
694 // and we'll consume all
695 *outFrame = input; // frame always start on input
696 *outFrameSize = frameSize;
697 int parsed = frameSize;
698 return parsed;
703 } // gnash.media.ffmpeg namespace
704 } // gnash.media namespace
705 } // gnash namespace