summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPetri Hintukainen <phintuka@users.sourceforge.net>2011-11-02 14:46:49 +0200
committerPetri Hintukainen <phintuka@users.sourceforge.net>2011-11-02 14:46:49 +0200
commit95c6251f6c41b60adb6e5210fc13a69b35e582e1 (patch)
treebe32cac28b5bd4d0cc1d3efadae9f0300535126c /src
parent463a6b08b823abb04e834f9e5a6a535b868f4b97 (diff)
downloadxine-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.c88
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);