diff options
author | Petri Hintukainen <phintuka@users.sourceforge.net> | 2011-11-02 14:46:49 +0200 |
---|---|---|
committer | Petri Hintukainen <phintuka@users.sourceforge.net> | 2011-11-02 14:46:49 +0200 |
commit | 95c6251f6c41b60adb6e5210fc13a69b35e582e1 (patch) | |
tree | be32cac28b5bd4d0cc1d3efadae9f0300535126c /src | |
parent | 463a6b08b823abb04e834f9e5a6a535b868f4b97 (diff) | |
download | xine-lib-95c6251f6c41b60adb6e5210fc13a69b35e582e1.tar.gz xine-lib-95c6251f6c41b60adb6e5210fc13a69b35e582e1.tar.bz2 |
ff_audio_decoder: Use parser for AAC LATM and MPEG. Fixes streams with multiple audio packets in single PES packet and audio packets splitted to multiple PES packets.
Diffstat (limited to 'src')
-rw-r--r-- | src/combined/ffmpeg/ff_audio_decoder.c | 88 |
1 files changed, 86 insertions, 2 deletions
diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index a078821f9..3b810a3fa 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -76,6 +76,8 @@ typedef struct ff_audio_decoder_s { char *decode_buffer; int decoder_ok; + AVCodecParserContext *parser_context; + } ff_audio_decoder_t; @@ -165,6 +167,24 @@ static void ff_audio_init_codec(ff_audio_decoder_t *this, unsigned int codec_typ this->context->codec_id = this->codec->id; this->context->codec_type = this->codec->type; this->context->codec_tag = _x_stream_info_get(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC); + + /* Use parser for AAC LATM and MPEG. + * Fixes: + * - DVB streams where multiple AAC LATM frames are packed to single PES + * - DVB streams where MPEG audio frames do not follow PES packet boundaries + */ + if (codec_type == BUF_AUDIO_AAC_LATM || + codec_type == BUF_AUDIO_MPEG) { + + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "ffmpeg_audio_dec: using parser\n"); + + this->parser_context = av_parser_init(this->codec->id); + if (!this->parser_context) { + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, + "ffmpeg_audio_dec: couldn't init parser\n"); + } + } } static int ff_audio_open_codec(ff_audio_decoder_t *this, unsigned int codec_type) { @@ -311,12 +331,55 @@ static void ff_handle_header_buffer(ff_audio_decoder_t *this, buf_element_t *buf this->size = 0; } +static void ff_audio_reset_parser(ff_audio_decoder_t *this) +{ + /* reset parser */ + if (this->parser_context) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "ffmpeg_audio_dec: resetting parser\n"); + + pthread_mutex_lock (&ffmpeg_lock); + av_parser_close(this->parser_context); + this->parser_context = av_parser_init(this->codec->id); + pthread_mutex_unlock (&ffmpeg_lock); + } +} + static int ff_audio_decode(xine_t *xine, AVCodecContext *ctx, + AVCodecParserContext *parser_ctx, int16_t *decode_buffer, int *decode_buffer_size, uint8_t *buf, int size) { int consumed; + int parser_consumed = 0; + + if (parser_ctx) { + uint8_t *outbuf; + int outsize; + + do { + int ret = av_parser_parse2(parser_ctx, ctx, + &outbuf, &outsize, + buf, size, + 0, 0, 0); + parser_consumed += ret; + buf += ret; + size -= ret; + } while (size > 0 && outsize <= 0); + + /* nothing to decode ? */ + if (outsize <= 0) { + *decode_buffer_size = 0; + xprintf (xine, XINE_VERBOSITY_DEBUG, + "ffmpeg_audio_dec: not enough data to decode\n"); + return parser_consumed; + } + + /* decode next packet */ + buf = outbuf; + size = outsize; + } #if AVAUDIO > 2 AVPacket avpkt; @@ -336,9 +399,13 @@ static int ff_audio_decode(xine_t *xine, if (consumed < 0) { xprintf (xine, XINE_VERBOSITY_DEBUG, "ffmpeg_audio_dec: error decompressing audio frame (%d)\n", consumed); + } else if (parser_consumed && consumed != size) { + + xprintf (xine, XINE_VERBOSITY_DEBUG, + "ffmpeg_audio_dec: decoder didn't consume all data\n"); } - return consumed; + return parser_consumed ? parser_consumed : consumed; } static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { @@ -376,7 +443,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size); this->size += buf->size; - if (buf->decoder_flags & BUF_FLAG_FRAME_END) { /* time to decode a frame */ + if (this->parser_context || buf->decoder_flags & BUF_FLAG_FRAME_END) { /* time to decode a frame */ offset = 0; @@ -388,6 +455,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) bytes_consumed = ff_audio_decode(this->stream->xine, this->context, + this->parser_context, (int16_t *)this->decode_buffer, &decode_buffer_size, &this->buf[offset], this->size); @@ -479,6 +547,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) audio_buffer->num_frames = bytes_to_send / 2 / this->audio_channels; audio_buffer->vpts = buf->pts; + buf->pts = 0; /* only first buffer gets the real pts */ this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); @@ -507,15 +576,30 @@ static void ff_audio_reset (audio_decoder_t *this_gen) { this->decoder_ok = 0; pthread_mutex_unlock (&ffmpeg_lock); } + + ff_audio_reset_parser(this); } static void ff_audio_discontinuity (audio_decoder_t *this_gen) { + + ff_audio_decoder_t *this = (ff_audio_decoder_t *) this_gen; + + this->size = 0; + + ff_audio_reset_parser(this); } static void ff_audio_dispose (audio_decoder_t *this_gen) { ff_audio_decoder_t *this = (ff_audio_decoder_t *) this_gen; + if (this->parser_context) { + pthread_mutex_lock (&ffmpeg_lock); + av_parser_close(this->parser_context); + this->parser_context = NULL; + pthread_mutex_unlock (&ffmpeg_lock); + } + if( this->context && this->decoder_ok ) { pthread_mutex_lock (&ffmpeg_lock); avcodec_close (this->context); |