From 333a24be88d97f28712be0f899d33540c9b1b903 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Thu, 27 Oct 2011 17:29:09 +0300 Subject: ff_audio_decoder: splitted calling avcodec_decode_audio* to separate function --- src/combined/ffmpeg/ff_audio_decoder.c | 79 ++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 37 deletions(-) (limited to 'src/combined/ffmpeg') diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index 31287fd3d..01b5875fa 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -311,6 +311,36 @@ static void ff_handle_header_buffer(ff_audio_decoder_t *this, buf_element_t *buf this->size = 0; } +static int ff_audio_decode(xine_t *xine, + AVCodecContext *ctx, + int16_t *decode_buffer, int *decode_buffer_size, + uint8_t *buf, int size) +{ + int consumed; + +#if AVAUDIO > 2 + AVPacket avpkt; + av_init_packet (&avpkt); + avpkt.data = buf; + avpkt.size = size; + avpkt.flags = AV_PKT_FLAG_KEY; + consumed = avcodec_decode_audio3 (ctx, + decode_buffer, decode_buffer_size, + &avpkt); +#else + consumed = avcodec_decode_audio2 (ctx, + decode_buffer, decode_buffer_size, + buf, size); +#endif + + if (consumed < 0) { + xprintf (xine, XINE_VERBOSITY_DEBUG, + "ffmpeg_audio_dec: error decompressing audio frame (%d)\n", consumed); + } + + return consumed; +} + static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { ff_audio_decoder_t *this = (ff_audio_decoder_t *) this_gen; @@ -333,10 +363,6 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) } else { -#if AVAUDIO > 2 - AVPacket avpkt; -#endif - if( !this->decoder_ok ) { if (ff_audio_open_codec(this, codec_type) < 0) { return; @@ -355,27 +381,17 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) int ret; decode_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; -#if AVAUDIO > 2 - av_init_packet (&avpkt); - avpkt.data = (uint8_t *)&this->buf[0]; - avpkt.size = this->size; - avpkt.flags = AV_PKT_FLAG_KEY; - ret = avcodec_decode_audio3 (this->context, - (int16_t *)this->decode_buffer, - &decode_buffer_size, &avpkt); -#else - ret = avcodec_decode_audio2 (this->context, - (int16_t *)this->decode_buffer, - &decode_buffer_size, - &this->buf[0], - this->size); -#endif + + ret = ff_audio_decode(this->stream->xine, this->context, + (int16_t *)this->decode_buffer, &decode_buffer_size, + this->buf, this->size); + this->audio_bits = this->context->bits_per_sample; this->audio_sample_rate = this->context->sample_rate; this->audio_channels = this->context->channels; if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, - _("ffmpeg_audio_dec: cannot read codec parameters from packet (error=%d)\n"), ret); + _("ffmpeg_audio_dec: cannot read codec parameters from packet\n")); /* We can't use this packet, so we must discard it * and wait for another one. */ @@ -401,24 +417,13 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) while (this->size>0) { decode_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; -#if AVAUDIO > 2 - av_init_packet (&avpkt); - avpkt.data = (uint8_t *)&this->buf[offset]; - avpkt.size = this->size; - avpkt.flags = AV_PKT_FLAG_KEY; - bytes_consumed = avcodec_decode_audio3 (this->context, - (int16_t *)this->decode_buffer, - &decode_buffer_size, &avpkt); -#else - bytes_consumed = avcodec_decode_audio2 (this->context, - (int16_t *)this->decode_buffer, - &decode_buffer_size, - &this->buf[offset], - this->size); -#endif + + bytes_consumed = + ff_audio_decode(this->stream->xine, this->context, + (int16_t *)this->decode_buffer, &decode_buffer_size, + &this->buf[offset], this->size); + if (bytes_consumed<0) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "ffmpeg_audio_dec: error decompressing audio frame\n"); this->size=0; return; } else if (bytes_consumed == 0 && decode_buffer_size == 0) { -- cgit v1.2.3 From 9fa54f15e1b4b79730e2cefc089805206ec2fb38 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Wed, 2 Nov 2011 13:57:35 +0200 Subject: ff_audio_decoder: open audio out after decoding the data - Fixes detecting audio parameters when audio packet is splitted to multiple buffers - Simplifies the code (decode function is called only once for each audio frame) --- src/combined/ffmpeg/ff_audio_decoder.c | 56 +++++++++++++++------------------- 1 file changed, 24 insertions(+), 32 deletions(-) (limited to 'src/combined/ffmpeg') diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index 01b5875fa..2515d657c 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -376,38 +376,6 @@ 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 (!this->output_open) { - if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { - int ret; - - decode_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; - - ret = ff_audio_decode(this->stream->xine, this->context, - (int16_t *)this->decode_buffer, &decode_buffer_size, - this->buf, this->size); - - this->audio_bits = this->context->bits_per_sample; - this->audio_sample_rate = this->context->sample_rate; - this->audio_channels = this->context->channels; - if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { - xprintf(this->stream->xine, XINE_VERBOSITY_LOG, - _("ffmpeg_audio_dec: cannot read codec parameters from packet\n")); - - /* We can't use this packet, so we must discard it - * and wait for another one. */ - this->size = 0; - return; - } - } - this->output_open = (this->stream->audio_out->open) (this->stream->audio_out, - this->stream, this->audio_bits, this->audio_sample_rate, - _x_ao_channels2mode(this->audio_channels)); - } - - /* if the audio still isn't open, bail */ - if (!this->output_open) - return; - if (buf->decoder_flags & BUF_FLAG_FRAME_END) { /* time to decode a frame */ offset = 0; @@ -432,6 +400,30 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) return; } + if (!this->output_open) { + if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { + this->audio_bits = this->context->bits_per_sample; + this->audio_sample_rate = this->context->sample_rate; + this->audio_channels = this->context->channels; + if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + _("ffmpeg_audio_dec: cannot read codec parameters from packet\n")); + + /* We can't use this packet, so we must discard it + * and wait for another one. */ + this->size = 0; + return; + } + } + this->output_open = (this->stream->audio_out->open) (this->stream->audio_out, + this->stream, this->audio_bits, this->audio_sample_rate, + _x_ao_channels2mode(this->audio_channels)); + } + + /* if the audio still isn't open, bail */ + if (!this->output_open) + return; + /* dispatch the decoded audio */ out = 0; while (out < decode_buffer_size) { -- cgit v1.2.3 From 309bb8e81976996b87da0d4d04a8365cc5edcc1d Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Wed, 2 Nov 2011 14:12:01 +0200 Subject: ff_audio_decoder: If codec parameters can't be read from first audio packet, try next. Fixes detecting parameters when there are multiple audio packets in single PES packet. --- src/combined/ffmpeg/ff_audio_decoder.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'src/combined/ffmpeg') diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index 2515d657c..52837a54f 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -405,25 +405,27 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) this->audio_bits = this->context->bits_per_sample; this->audio_sample_rate = this->context->sample_rate; this->audio_channels = this->context->channels; - if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { + } + if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + _("ffmpeg_audio_dec: cannot read codec parameters from packet\n")); + /* try to decode next packet. */ + /* there shouldn't be any output yet */ + decode_buffer_size = 0; + /* pts applies only to first audio packet */ + buf->pts = 0; + } else { + this->output_open = (this->stream->audio_out->open) (this->stream->audio_out, + this->stream, this->audio_bits, this->audio_sample_rate, + _x_ao_channels2mode(this->audio_channels)); + if (!this->output_open) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, - _("ffmpeg_audio_dec: cannot read codec parameters from packet\n")); - - /* We can't use this packet, so we must discard it - * and wait for another one. */ - this->size = 0; + "ffmpeg_audio_dec: error opening audio output\n"); return; } } - this->output_open = (this->stream->audio_out->open) (this->stream->audio_out, - this->stream, this->audio_bits, this->audio_sample_rate, - _x_ao_channels2mode(this->audio_channels)); } - /* if the audio still isn't open, bail */ - if (!this->output_open) - return; - /* dispatch the decoded audio */ out = 0; while (out < decode_buffer_size) { -- cgit v1.2.3 From 463a6b08b823abb04e834f9e5a6a535b868f4b97 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Wed, 2 Nov 2011 14:22:16 +0200 Subject: ff_audio_decoder: do not queue any data if opening audio output fails --- src/combined/ffmpeg/ff_audio_decoder.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/combined/ffmpeg') diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index 52837a54f..a078821f9 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -421,6 +421,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) if (!this->output_open) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "ffmpeg_audio_dec: error opening audio output\n"); + this->size = 0; return; } } -- cgit v1.2.3 From 95c6251f6c41b60adb6e5210fc13a69b35e582e1 Mon Sep 17 00:00:00 2001 From: Petri Hintukainen Date: Wed, 2 Nov 2011 14:46:49 +0200 Subject: 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. --- src/combined/ffmpeg/ff_audio_decoder.c | 88 +++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 2 deletions(-) (limited to 'src/combined/ffmpeg') 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); -- cgit v1.2.3