summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorsten Jager <t.jager@gmx.de>2014-12-29 17:34:25 +0100
committerTorsten Jager <t.jager@gmx.de>2014-12-29 17:34:25 +0100
commit4602e394b4d221589ef33d72cae7a2f13b42d4f7 (patch)
tree459a1b51457c9da3ddf8ecd33946cc133da7e8bf
parentdb5b495137ada187a928677d4ed0bf761be6e65d (diff)
downloadxine-lib-4602e394b4d221589ef33d72cae7a2f13b42d4f7.tar.gz
xine-lib-4602e394b4d221589ef33d72cae7a2f13b42d4f7.tar.bz2
ff_audio_decoder: add AAC ADTS probing and parsing v2.
Some MPEG-TS streams dont align ADTS to TS-PES, pad ADTS frames to (nearly) fixed bitrate, and/or wrongly flag all this as LATM. Now the probing is more safe against ambigous input. Somebody please test whether this still breaks real LATM.
-rw-r--r--src/combined/ffmpeg/ff_audio_decoder.c132
1 files changed, 131 insertions, 1 deletions
diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c
index aa8c674ab..8842b79a7 100644
--- a/src/combined/ffmpeg/ff_audio_decoder.c
+++ b/src/combined/ffmpeg/ff_audio_decoder.c
@@ -76,6 +76,15 @@ typedef struct ff_audio_decoder_s {
AVFrame *av_frame;
#endif
+ /* AAC ADTS */
+ uint32_t buftype;
+#define AAC_MODE_PROBE -8
+#define AAC_MODE_OFF 0
+#define AAC_MODE_RAW 1
+#define AAC_MODE_ADTS 2
+ int aac_mode;
+
+
/* decoder settings */
int ff_channels;
int ff_bits;
@@ -131,6 +140,109 @@ static void *realloc16 (void *m, size_t s) {
}
+static void ff_aac_mode_set (ff_audio_decoder_t *this, int reset) {
+ if ((this->buftype == BUF_AUDIO_AAC) || (this->buftype == BUF_AUDIO_AAC_LATM)) {
+ if (reset) {
+ this->aac_mode = AAC_MODE_PROBE;
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_audio_dec: looking for possible AAC ADTS syncwords...\n");
+ }
+ if ((this->aac_mode < 0) || (this->aac_mode == AAC_MODE_ADTS)) {
+ if (this->context && this->context->extradata_size) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_audio_dec: AAC raw mode with global header\n");
+ this->aac_mode = AAC_MODE_RAW;
+ }
+ }
+ } else {
+ this->aac_mode = AAC_MODE_OFF;
+ }
+}
+
+static int ff_audio_open_codec (ff_audio_decoder_t *this, unsigned int codec_type);
+
+/* return -1 (need more data), 0 (no parsing done), > 0 (offset + size of found frame) */
+static int ff_aac_mode_parse (ff_audio_decoder_t *this, uint8_t *buf, int size, int *offs) {
+ int i;
+ uint32_t v;
+ *offs = 0;
+ if (this->aac_mode < 0) {
+ /* probe */
+ v = 0;
+ for (i = 0; i < size; i++) {
+ v <<= 8;
+ v |= buf[i];
+ /* also test the "layer" bits for 0 (mpeg layer 4 audio). */
+ /* dont get fooled by 0xff padding bytes. */
+ if ((v & 0xfff6) == 0xfff0) {
+ uint32_t s;
+ /* test header size */
+ if (size - i < 7 - 1)
+ continue;
+ /* read frame size */
+ s = (_X_BE_32 (buf + i + 2) >> 13) & 0x1fff;
+ if (s < 7)
+ continue;
+ /* test for next ADTS frame following */
+ if (size - i < s + 7 - 1)
+ continue;
+ if ((((buf[i + s - 1] << 8) | buf[i + s]) & 0xfff6) != 0xfff0)
+ continue;
+ *offs = --i;
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_audio_dec: found AAC ADTS syncword after %d bytes\n", i);
+ if (this->buftype == BUF_AUDIO_AAC_LATM) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_audio_dec: stream says LATM but is ADTS -> switching decoders\n");
+ if (this->context && this->decoder_ok) {
+ pthread_mutex_lock (&ffmpeg_lock);
+ avcodec_close (this->context);
+ pthread_mutex_unlock (&ffmpeg_lock);
+ this->decoder_ok = 0;
+ }
+ this->codec = NULL;
+ ff_audio_open_codec (this, BUF_AUDIO_AAC);
+ }
+ this->aac_mode = AAC_MODE_ADTS - 1;
+ break;
+ }
+ }
+ this->aac_mode++;
+ if (this->aac_mode < 0) {
+ if (size >= 2 * 0x1fff)
+ this->aac_mode = AAC_MODE_OFF;
+ else
+ return -1;
+ }
+ if (this->aac_mode == AAC_MODE_OFF)
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "ffmpeg_audio_dec: no ADTS frames found\n");
+ }
+ if (this->aac_mode == AAC_MODE_ADTS) {
+ v = 0;
+ for (i = *offs; i < size; i++) {
+ v <<= 8;
+ v |= buf[i];
+ if ((v & 0xfff6) == 0xfff0) {
+ uint32_t s;
+ /* test header size */
+ if (size - i < 7 - 1)
+ return -1;
+ /* read frame size */
+ s = (_X_BE_32 (buf + i + 2) >> 13) & 0x1fff;
+ if (s < 7)
+ continue;
+ *offs = --i;
+ if (size - i < s)
+ return -1;
+ return i + s;
+ }
+ }
+ return -1;
+ }
+ return 0;
+}
+
static void ff_audio_ensure_buffer_size(ff_audio_decoder_t *this, int size) {
if (size > this->bufsize) {
this->bufsize = size + size / 2;
@@ -151,6 +263,8 @@ static void ff_audio_handle_special_buffer(ff_audio_decoder_t *this, buf_element
this->context->extradata = malloc (buf->decoder_info[2] + FF_INPUT_BUFFER_PADDING_SIZE);
memcpy (this->context->extradata, buf->decoder_info_ptr[2], buf->decoder_info[2]);
memset (this->context->extradata + buf->decoder_info[2], 0, FF_INPUT_BUFFER_PADDING_SIZE);
+
+ ff_aac_mode_set (this, 0);
}
}
@@ -161,6 +275,8 @@ static void ff_audio_init_codec(ff_audio_decoder_t *this, unsigned int codec_typ
for(i = 0; i < sizeof(ff_audio_lookup)/sizeof(ff_codec_t); i++)
if(ff_audio_lookup[i].type == codec_type) {
+ this->buftype = codec_type;
+ ff_aac_mode_set (this, 1);
pthread_mutex_lock (&ffmpeg_lock);
this->codec = avcodec_find_decoder(ff_audio_lookup[i].id);
pthread_mutex_unlock (&ffmpeg_lock);
@@ -551,9 +667,20 @@ static void ff_map_channels (ff_audio_decoder_t *this) {
static int ff_audio_decode (ff_audio_decoder_t *this,
int16_t *decode_buffer, int *decode_buffer_size, uint8_t *buf, int size) {
int consumed;
- int parser_consumed = 0;
+ int parser_consumed;
+ int offs;
+
+ parser_consumed = ff_aac_mode_parse (this, buf, size, &offs);
+ if (parser_consumed < 0) {
+ *decode_buffer_size = 0;
+ return offs;
+ } else if (parser_consumed > 0) {
+ buf += offs;
+ size = parser_consumed - offs;
+ }
#if AVPARSE > 1
+ else
if (this->parser_context) {
uint8_t *outbuf;
int outsize;
@@ -889,6 +1016,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf)
memset(&this->buf[this->size], 0, FF_INPUT_BUFFER_PADDING_SIZE);
while (this->size>=0) {
+
decode_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
bytes_consumed = ff_audio_decode (this, (int16_t *)this->decode_buffer, &decode_buffer_size,
@@ -1081,6 +1209,7 @@ static void ff_audio_reset (audio_decoder_t *this_gen) {
}
ff_audio_reset_parser(this);
+ ff_aac_mode_set (this, 1);
}
static void ff_audio_discontinuity (audio_decoder_t *this_gen) {
@@ -1090,6 +1219,7 @@ static void ff_audio_discontinuity (audio_decoder_t *this_gen) {
this->size = 0;
ff_audio_reset_parser(this);
+ ff_aac_mode_set (this, 0);
}
static void ff_audio_dispose (audio_decoder_t *this_gen) {