From da46276ff8b1aefbc83917b34c19a676699f5b0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5ns=20Rullg=C3=A5rd?= Date: Wed, 8 Feb 2006 00:50:22 +0000 Subject: [PATCH] adts aac parser Originally committed as revision 4954 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/parser.c | 99 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 92 insertions(+), 9 deletions(-) diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index bef0373b73..2b73d1b88c 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -622,5 +622,6 @@ PCM_CODEC(CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha); #ifdef CONFIG_DVBSUB_DECODER av_register_codec_parser(&dvbsub_parser); #endif + av_register_codec_parser(&aac_parser); } diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 854c3db1df..e6f79533e1 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -2516,6 +2516,7 @@ extern AVCodecParser mpegaudio_parser; extern AVCodecParser ac3_parser; extern AVCodecParser dvdsub_parser; extern AVCodecParser dvbsub_parser; +extern AVCodecParser aac_parser; /* memory */ void *av_malloc(unsigned int size); diff --git a/libavcodec/parser.c b/libavcodec/parser.c index 412cd83594..2c896d85c8 100644 --- a/libavcodec/parser.c +++ b/libavcodec/parser.c @@ -727,13 +727,18 @@ static int mpegaudio_parse(AVCodecParserContext *s1, return buf_ptr - buf; } +/* also used for ADTS AAC */ typedef struct AC3ParseContext { uint8_t inbuf[4096]; /* input buffer */ uint8_t *inbuf_ptr; int frame_size; + int header_size; + int (*sync)(const uint8_t *buf, int *channels, int *sample_rate, + int *bit_rate, int *samples); } AC3ParseContext; #define AC3_HEADER_SIZE 7 +#define AAC_HEADER_SIZE 8 static const int ac3_sample_rates[4] = { 48000, 44100, 32000, 0 @@ -790,8 +795,17 @@ static const int ac3_channels[8] = { 2, 1, 2, 3, 3, 4, 4, 5 }; +static int aac_sample_rates[16] = { + 96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000, 7350 +}; + +static int aac_channels[8] = { + 0, 1, 2, 3, 4, 5, 6, 8 +}; + static int ac3_sync(const uint8_t *buf, int *channels, int *sample_rate, - int *bit_rate) + int *bit_rate, int *samples) { unsigned int fscod, frmsizecod, acmod, bsid, lfeon; GetBitContext bits; @@ -824,17 +838,70 @@ static int ac3_sync(const uint8_t *buf, int *channels, int *sample_rate, *sample_rate = ac3_sample_rates[fscod]; *bit_rate = ac3_bitrates[frmsizecod] * 1000; *channels = ac3_channels[acmod] + lfeon; + *samples = 6 * 256; return ac3_frame_sizes[frmsizecod][fscod] * 2; } +static int aac_sync(const uint8_t *buf, int *channels, int *sample_rate, + int *bit_rate, int *samples) +{ + GetBitContext bits; + int size, rdb, ch, sr; + + init_get_bits(&bits, buf, AAC_HEADER_SIZE * 8); + + if(get_bits(&bits, 12) != 0xfff) + return 0; + + get_bits(&bits, 1); + get_bits(&bits, 2); + get_bits(&bits, 1); /* protection_absent */ + get_bits(&bits, 2); + sr = get_bits(&bits, 4); + if(!aac_sample_rates[sr]) + return 0; + get_bits(&bits, 1); /* private_bit */ + ch = get_bits(&bits, 3); + if(!aac_channels[ch]) + return 0; + get_bits(&bits, 1); /* original/copy */ + get_bits(&bits, 1); /* home */ + + /* adts_variable_header */ + get_bits(&bits, 1); /* copyright_identification_bit */ + get_bits(&bits, 1); /* copyright_identification_start */ + size = get_bits(&bits, 13); + get_bits(&bits, 11); /* adts_buffer_fullness */ + rdb = get_bits(&bits, 2); + + *channels = aac_channels[ch]; + *sample_rate = aac_sample_rates[sr]; + *samples = (rdb + 1) * 1024; + *bit_rate = size * 8 * *sample_rate / *samples; + + return size; +} + static int ac3_parse_init(AVCodecParserContext *s1) { AC3ParseContext *s = s1->priv_data; s->inbuf_ptr = s->inbuf; + s->header_size = AC3_HEADER_SIZE; + s->sync = ac3_sync; return 0; } +static int aac_parse_init(AVCodecParserContext *s1) +{ + AC3ParseContext *s = s1->priv_data; + s->inbuf_ptr = s->inbuf; + s->header_size = AAC_HEADER_SIZE; + s->sync = aac_sync; + return 0; +} + +/* also used for ADTS AAC */ static int ac3_parse(AVCodecParserContext *s1, AVCodecContext *avctx, uint8_t **poutbuf, int *poutbuf_size, @@ -842,7 +909,7 @@ static int ac3_parse(AVCodecParserContext *s1, { AC3ParseContext *s = s1->priv_data; const uint8_t *buf_ptr; - int len, sample_rate, bit_rate, channels; + int len, sample_rate, bit_rate, channels, samples; *poutbuf = NULL; *poutbuf_size = 0; @@ -851,29 +918,35 @@ static int ac3_parse(AVCodecParserContext *s1, while (buf_size > 0) { len = s->inbuf_ptr - s->inbuf; if (s->frame_size == 0) { - /* no header seen : find one. We need at least 7 bytes to parse it */ - len = FFMIN(AC3_HEADER_SIZE - len, buf_size); + /* no header seen : find one. We need at least s->header_size + bytes to parse it */ + len = FFMIN(s->header_size - len, buf_size); memcpy(s->inbuf_ptr, buf_ptr, len); buf_ptr += len; s->inbuf_ptr += len; buf_size -= len; - if ((s->inbuf_ptr - s->inbuf) == AC3_HEADER_SIZE) { - len = ac3_sync(s->inbuf, &channels, &sample_rate, &bit_rate); + if ((s->inbuf_ptr - s->inbuf) == s->header_size) { + len = s->sync(s->inbuf, &channels, &sample_rate, &bit_rate, + &samples); if (len == 0) { /* no sync found : move by one byte (inefficient, but simple!) */ - memmove(s->inbuf, s->inbuf + 1, AC3_HEADER_SIZE - 1); + memmove(s->inbuf, s->inbuf + 1, s->header_size - 1); s->inbuf_ptr--; } else { s->frame_size = len; /* update codec info */ avctx->sample_rate = sample_rate; /* set channels,except if the user explicitly requests 1 or 2 channels, XXX/FIXME this is a bit ugly */ - if(avctx->channels!=1 && avctx->channels!=2){ + if(avctx->codec_id == CODEC_ID_AC3){ + if(avctx->channels!=1 && avctx->channels!=2){ + avctx->channels = channels; + } + } else { avctx->channels = channels; } avctx->bit_rate = bit_rate; - avctx->frame_size = 6 * 256; + avctx->frame_size = samples; } } } else { @@ -929,3 +1002,11 @@ AVCodecParser ac3_parser = { ac3_parse, NULL, }; + +AVCodecParser aac_parser = { + { CODEC_ID_AAC }, + sizeof(AC3ParseContext), + aac_parse_init, + ac3_parse, + NULL, +};