diff options
author | Lynne <dev@lynne.ee> | 2024-03-16 23:34:46 +0100 |
---|---|---|
committer | Lynne <dev@lynne.ee> | 2024-04-23 08:31:39 +0200 |
commit | ce740618d194e6c8523466ba15be2d662da37105 (patch) | |
tree | ebf6e6809f3277426be16510b5cf0467b1005612 /libavcodec | |
parent | e93793bf3cf15968c34b0e7bf0c677fad3032f5d (diff) | |
download | ffmpeg-ce740618d194e6c8523466ba15be2d662da37105.tar.gz |
aacdec: move LATM decode functions into a separate file
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/aac/aacdec_latm.h | 350 | ||||
-rw-r--r-- | libavcodec/aacdec.c | 315 |
2 files changed, 351 insertions, 314 deletions
diff --git a/libavcodec/aac/aacdec_latm.h b/libavcodec/aac/aacdec_latm.h new file mode 100644 index 0000000000..0226aebba4 --- /dev/null +++ b/libavcodec/aac/aacdec_latm.h @@ -0,0 +1,350 @@ +/* + * AAC decoder + * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) + * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) + * Copyright (c) 2008-2013 Alex Converse <alex.converse@gmail.com> + * + * AAC LATM decoder + * Copyright (c) 2008-2010 Paul Kendall <paul@kcbbs.gen.nz> + * Copyright (c) 2010 Janne Grunau <janne-libav@jannau.net> + * + * AAC decoder fixed-point implementation + * Copyright (c) 2013 + * MIPS Technologies, Inc., California. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AAC_AACDEC_LATM_H +#define AVCODEC_AAC_AACDEC_LATM_H + +#define LOAS_SYNC_WORD 0x2b7 ///< 11 bits LOAS sync word + +struct LATMContext { + AACDecContext aac_ctx; ///< containing AACContext + int initialized; ///< initialized after a valid extradata was seen + + // parser data + int audio_mux_version_A; ///< LATM syntax version + int frame_length_type; ///< 0/1 variable/fixed frame length + int frame_length; ///< frame length for fixed frame length +}; + +static inline uint32_t latm_get_value(GetBitContext *b) +{ + int length = get_bits(b, 2); + + return get_bits_long(b, (length+1)*8); +} + +static int latm_decode_audio_specific_config(struct LATMContext *latmctx, + GetBitContext *gb, int asclen) +{ + AACDecContext *ac = &latmctx->aac_ctx; + AVCodecContext *avctx = ac->avctx; + MPEG4AudioConfig m4ac = { 0 }; + GetBitContext gbc; + int config_start_bit = get_bits_count(gb); + int sync_extension = 0; + int bits_consumed, esize, i; + + if (asclen > 0) { + sync_extension = 1; + asclen = FFMIN(asclen, get_bits_left(gb)); + init_get_bits(&gbc, gb->buffer, config_start_bit + asclen); + skip_bits_long(&gbc, config_start_bit); + } else if (asclen == 0) { + gbc = *gb; + } else { + return AVERROR_INVALIDDATA; + } + + if (get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + + bits_consumed = decode_audio_specific_config_gb(NULL, avctx, &m4ac, + &gbc, config_start_bit, + sync_extension); + + if (bits_consumed < config_start_bit) + return AVERROR_INVALIDDATA; + bits_consumed -= config_start_bit; + + if (asclen == 0) + asclen = bits_consumed; + + if (!latmctx->initialized || + ac->oc[1].m4ac.sample_rate != m4ac.sample_rate || + ac->oc[1].m4ac.chan_config != m4ac.chan_config) { + + if (latmctx->initialized) { + av_log(avctx, AV_LOG_INFO, "audio config changed (sample_rate=%d, chan_config=%d)\n", m4ac.sample_rate, m4ac.chan_config); + } else { + av_log(avctx, AV_LOG_DEBUG, "initializing latmctx\n"); + } + latmctx->initialized = 0; + + esize = (asclen + 7) / 8; + + if (avctx->extradata_size < esize) { + av_free(avctx->extradata); + avctx->extradata = av_malloc(esize + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) + return AVERROR(ENOMEM); + } + + avctx->extradata_size = esize; + gbc = *gb; + for (i = 0; i < esize; i++) { + avctx->extradata[i] = get_bits(&gbc, 8); + } + memset(avctx->extradata+esize, 0, AV_INPUT_BUFFER_PADDING_SIZE); + } + skip_bits_long(gb, asclen); + + return 0; +} + +static int read_stream_mux_config(struct LATMContext *latmctx, + GetBitContext *gb) +{ + int ret, audio_mux_version = get_bits(gb, 1); + + latmctx->audio_mux_version_A = 0; + if (audio_mux_version) + latmctx->audio_mux_version_A = get_bits(gb, 1); + + if (!latmctx->audio_mux_version_A) { + + if (audio_mux_version) + latm_get_value(gb); // taraFullness + + skip_bits(gb, 1); // allStreamSameTimeFraming + skip_bits(gb, 6); // numSubFrames + // numPrograms + if (get_bits(gb, 4)) { // numPrograms + avpriv_request_sample(latmctx->aac_ctx.avctx, "Multiple programs"); + return AVERROR_PATCHWELCOME; + } + + // for each program (which there is only one in DVB) + + // for each layer (which there is only one in DVB) + if (get_bits(gb, 3)) { // numLayer + avpriv_request_sample(latmctx->aac_ctx.avctx, "Multiple layers"); + return AVERROR_PATCHWELCOME; + } + + // for all but first stream: use_same_config = get_bits(gb, 1); + if (!audio_mux_version) { + if ((ret = latm_decode_audio_specific_config(latmctx, gb, 0)) < 0) + return ret; + } else { + int ascLen = latm_get_value(gb); + if ((ret = latm_decode_audio_specific_config(latmctx, gb, ascLen)) < 0) + return ret; + } + + latmctx->frame_length_type = get_bits(gb, 3); + switch (latmctx->frame_length_type) { + case 0: + skip_bits(gb, 8); // latmBufferFullness + break; + case 1: + latmctx->frame_length = get_bits(gb, 9); + break; + case 3: + case 4: + case 5: + skip_bits(gb, 6); // CELP frame length table index + break; + case 6: + case 7: + skip_bits(gb, 1); // HVXC frame length table index + break; + } + + if (get_bits(gb, 1)) { // other data + if (audio_mux_version) { + latm_get_value(gb); // other_data_bits + } else { + int esc; + do { + if (get_bits_left(gb) < 9) + return AVERROR_INVALIDDATA; + esc = get_bits(gb, 1); + skip_bits(gb, 8); + } while (esc); + } + } + + if (get_bits(gb, 1)) // crc present + skip_bits(gb, 8); // config_crc + } + + return 0; +} + +static int read_payload_length_info(struct LATMContext *ctx, GetBitContext *gb) +{ + uint8_t tmp; + + if (ctx->frame_length_type == 0) { + int mux_slot_length = 0; + do { + if (get_bits_left(gb) < 8) + return AVERROR_INVALIDDATA; + tmp = get_bits(gb, 8); + mux_slot_length += tmp; + } while (tmp == 255); + return mux_slot_length; + } else if (ctx->frame_length_type == 1) { + return ctx->frame_length; + } else if (ctx->frame_length_type == 3 || + ctx->frame_length_type == 5 || + ctx->frame_length_type == 7) { + skip_bits(gb, 2); // mux_slot_length_coded + } + return 0; +} + +static int read_audio_mux_element(struct LATMContext *latmctx, + GetBitContext *gb) +{ + int err; + uint8_t use_same_mux = get_bits(gb, 1); + if (!use_same_mux) { + if ((err = read_stream_mux_config(latmctx, gb)) < 0) + return err; + } else if (!latmctx->aac_ctx.avctx->extradata) { + av_log(latmctx->aac_ctx.avctx, AV_LOG_DEBUG, + "no decoder config found\n"); + return 1; + } + if (latmctx->audio_mux_version_A == 0) { + int mux_slot_length_bytes = read_payload_length_info(latmctx, gb); + if (mux_slot_length_bytes < 0 || mux_slot_length_bytes * 8LL > get_bits_left(gb)) { + av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, "incomplete frame\n"); + return AVERROR_INVALIDDATA; + } else if (mux_slot_length_bytes * 8 + 256 < get_bits_left(gb)) { + av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, + "frame length mismatch %d << %d\n", + mux_slot_length_bytes * 8, get_bits_left(gb)); + return AVERROR_INVALIDDATA; + } + } + return 0; +} + + +static int latm_decode_frame(AVCodecContext *avctx, AVFrame *out, + int *got_frame_ptr, AVPacket *avpkt) +{ + struct LATMContext *latmctx = avctx->priv_data; + int muxlength, err; + GetBitContext gb; + + if ((err = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0) + return err; + + // check for LOAS sync word + if (get_bits(&gb, 11) != LOAS_SYNC_WORD) + return AVERROR_INVALIDDATA; + + muxlength = get_bits(&gb, 13) + 3; + // not enough data, the parser should have sorted this out + if (muxlength > avpkt->size) + return AVERROR_INVALIDDATA; + + if ((err = read_audio_mux_element(latmctx, &gb))) + return (err < 0) ? err : avpkt->size; + + if (!latmctx->initialized) { + if (!avctx->extradata) { + *got_frame_ptr = 0; + return avpkt->size; + } else { + push_output_configuration(&latmctx->aac_ctx); + if ((err = decode_audio_specific_config( + &latmctx->aac_ctx, avctx, &latmctx->aac_ctx.oc[1].m4ac, + avctx->extradata, avctx->extradata_size*8LL, 1)) < 0) { + pop_output_configuration(&latmctx->aac_ctx); + return err; + } + latmctx->initialized = 1; + } + } + + if (show_bits(&gb, 12) == 0xfff) { + av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, + "ADTS header detected, probably as result of configuration " + "misparsing\n"); + return AVERROR_INVALIDDATA; + } + + switch (latmctx->aac_ctx.oc[1].m4ac.object_type) { + case AOT_ER_AAC_LC: + case AOT_ER_AAC_LTP: + case AOT_ER_AAC_LD: + case AOT_ER_AAC_ELD: + err = aac_decode_er_frame(avctx, out, got_frame_ptr, &gb); + break; + default: + err = aac_decode_frame_int(avctx, out, got_frame_ptr, &gb, avpkt); + } + if (err < 0) + return err; + + return muxlength; +} + +static av_cold int latm_decode_init(AVCodecContext *avctx) +{ + struct LATMContext *latmctx = avctx->priv_data; + int ret = aac_decode_init(avctx); + + if (avctx->extradata_size > 0) + latmctx->initialized = !ret; + + return ret; +} + +/* + Note: This decoder filter is intended to decode LATM streams transferred + in MPEG transport streams which only contain one program. + To do a more complex LATM demuxing a separate LATM demuxer should be used. +*/ +const FFCodec ff_aac_latm_decoder = { + .p.name = "aac_latm", + CODEC_LONG_NAME("AAC LATM (Advanced Audio Coding LATM syntax)"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_AAC_LATM, + .priv_data_size = sizeof(struct LATMContext), + .init = latm_decode_init, + .close = ff_aac_decode_close, + FF_CODEC_DECODE_CB(latm_decode_frame), + .p.sample_fmts = (const enum AVSampleFormat[]) { + AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE + }, + .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .p.ch_layouts = ff_aac_ch_layout, + .flush = flush, + .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), +}; + +#endif /* AVCODEC_AAC_AACDEC_LATM_H */ diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c index 1e7bdb6416..bf1b1c29c7 100644 --- a/libavcodec/aacdec.c +++ b/libavcodec/aacdec.c @@ -65,296 +65,7 @@ #include "aacdec_template.c" -#define LOAS_SYNC_WORD 0x2b7 ///< 11 bits LOAS sync word - -struct LATMContext { - AACDecContext aac_ctx; ///< containing AACContext - int initialized; ///< initialized after a valid extradata was seen - - // parser data - int audio_mux_version_A; ///< LATM syntax version - int frame_length_type; ///< 0/1 variable/fixed frame length - int frame_length; ///< frame length for fixed frame length -}; - -static inline uint32_t latm_get_value(GetBitContext *b) -{ - int length = get_bits(b, 2); - - return get_bits_long(b, (length+1)*8); -} - -static int latm_decode_audio_specific_config(struct LATMContext *latmctx, - GetBitContext *gb, int asclen) -{ - AACDecContext *ac = &latmctx->aac_ctx; - AVCodecContext *avctx = ac->avctx; - MPEG4AudioConfig m4ac = { 0 }; - GetBitContext gbc; - int config_start_bit = get_bits_count(gb); - int sync_extension = 0; - int bits_consumed, esize, i; - - if (asclen > 0) { - sync_extension = 1; - asclen = FFMIN(asclen, get_bits_left(gb)); - init_get_bits(&gbc, gb->buffer, config_start_bit + asclen); - skip_bits_long(&gbc, config_start_bit); - } else if (asclen == 0) { - gbc = *gb; - } else { - return AVERROR_INVALIDDATA; - } - - if (get_bits_left(gb) <= 0) - return AVERROR_INVALIDDATA; - - bits_consumed = decode_audio_specific_config_gb(NULL, avctx, &m4ac, - &gbc, config_start_bit, - sync_extension); - - if (bits_consumed < config_start_bit) - return AVERROR_INVALIDDATA; - bits_consumed -= config_start_bit; - - if (asclen == 0) - asclen = bits_consumed; - - if (!latmctx->initialized || - ac->oc[1].m4ac.sample_rate != m4ac.sample_rate || - ac->oc[1].m4ac.chan_config != m4ac.chan_config) { - - if (latmctx->initialized) { - av_log(avctx, AV_LOG_INFO, "audio config changed (sample_rate=%d, chan_config=%d)\n", m4ac.sample_rate, m4ac.chan_config); - } else { - av_log(avctx, AV_LOG_DEBUG, "initializing latmctx\n"); - } - latmctx->initialized = 0; - - esize = (asclen + 7) / 8; - - if (avctx->extradata_size < esize) { - av_free(avctx->extradata); - avctx->extradata = av_malloc(esize + AV_INPUT_BUFFER_PADDING_SIZE); - if (!avctx->extradata) - return AVERROR(ENOMEM); - } - - avctx->extradata_size = esize; - gbc = *gb; - for (i = 0; i < esize; i++) { - avctx->extradata[i] = get_bits(&gbc, 8); - } - memset(avctx->extradata+esize, 0, AV_INPUT_BUFFER_PADDING_SIZE); - } - skip_bits_long(gb, asclen); - - return 0; -} - -static int read_stream_mux_config(struct LATMContext *latmctx, - GetBitContext *gb) -{ - int ret, audio_mux_version = get_bits(gb, 1); - - latmctx->audio_mux_version_A = 0; - if (audio_mux_version) - latmctx->audio_mux_version_A = get_bits(gb, 1); - - if (!latmctx->audio_mux_version_A) { - - if (audio_mux_version) - latm_get_value(gb); // taraFullness - - skip_bits(gb, 1); // allStreamSameTimeFraming - skip_bits(gb, 6); // numSubFrames - // numPrograms - if (get_bits(gb, 4)) { // numPrograms - avpriv_request_sample(latmctx->aac_ctx.avctx, "Multiple programs"); - return AVERROR_PATCHWELCOME; - } - - // for each program (which there is only one in DVB) - - // for each layer (which there is only one in DVB) - if (get_bits(gb, 3)) { // numLayer - avpriv_request_sample(latmctx->aac_ctx.avctx, "Multiple layers"); - return AVERROR_PATCHWELCOME; - } - - // for all but first stream: use_same_config = get_bits(gb, 1); - if (!audio_mux_version) { - if ((ret = latm_decode_audio_specific_config(latmctx, gb, 0)) < 0) - return ret; - } else { - int ascLen = latm_get_value(gb); - if ((ret = latm_decode_audio_specific_config(latmctx, gb, ascLen)) < 0) - return ret; - } - - latmctx->frame_length_type = get_bits(gb, 3); - switch (latmctx->frame_length_type) { - case 0: - skip_bits(gb, 8); // latmBufferFullness - break; - case 1: - latmctx->frame_length = get_bits(gb, 9); - break; - case 3: - case 4: - case 5: - skip_bits(gb, 6); // CELP frame length table index - break; - case 6: - case 7: - skip_bits(gb, 1); // HVXC frame length table index - break; - } - - if (get_bits(gb, 1)) { // other data - if (audio_mux_version) { - latm_get_value(gb); // other_data_bits - } else { - int esc; - do { - if (get_bits_left(gb) < 9) - return AVERROR_INVALIDDATA; - esc = get_bits(gb, 1); - skip_bits(gb, 8); - } while (esc); - } - } - - if (get_bits(gb, 1)) // crc present - skip_bits(gb, 8); // config_crc - } - - return 0; -} - -static int read_payload_length_info(struct LATMContext *ctx, GetBitContext *gb) -{ - uint8_t tmp; - - if (ctx->frame_length_type == 0) { - int mux_slot_length = 0; - do { - if (get_bits_left(gb) < 8) - return AVERROR_INVALIDDATA; - tmp = get_bits(gb, 8); - mux_slot_length += tmp; - } while (tmp == 255); - return mux_slot_length; - } else if (ctx->frame_length_type == 1) { - return ctx->frame_length; - } else if (ctx->frame_length_type == 3 || - ctx->frame_length_type == 5 || - ctx->frame_length_type == 7) { - skip_bits(gb, 2); // mux_slot_length_coded - } - return 0; -} - -static int read_audio_mux_element(struct LATMContext *latmctx, - GetBitContext *gb) -{ - int err; - uint8_t use_same_mux = get_bits(gb, 1); - if (!use_same_mux) { - if ((err = read_stream_mux_config(latmctx, gb)) < 0) - return err; - } else if (!latmctx->aac_ctx.avctx->extradata) { - av_log(latmctx->aac_ctx.avctx, AV_LOG_DEBUG, - "no decoder config found\n"); - return 1; - } - if (latmctx->audio_mux_version_A == 0) { - int mux_slot_length_bytes = read_payload_length_info(latmctx, gb); - if (mux_slot_length_bytes < 0 || mux_slot_length_bytes * 8LL > get_bits_left(gb)) { - av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, "incomplete frame\n"); - return AVERROR_INVALIDDATA; - } else if (mux_slot_length_bytes * 8 + 256 < get_bits_left(gb)) { - av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, - "frame length mismatch %d << %d\n", - mux_slot_length_bytes * 8, get_bits_left(gb)); - return AVERROR_INVALIDDATA; - } - } - return 0; -} - - -static int latm_decode_frame(AVCodecContext *avctx, AVFrame *out, - int *got_frame_ptr, AVPacket *avpkt) -{ - struct LATMContext *latmctx = avctx->priv_data; - int muxlength, err; - GetBitContext gb; - - if ((err = init_get_bits8(&gb, avpkt->data, avpkt->size)) < 0) - return err; - - // check for LOAS sync word - if (get_bits(&gb, 11) != LOAS_SYNC_WORD) - return AVERROR_INVALIDDATA; - - muxlength = get_bits(&gb, 13) + 3; - // not enough data, the parser should have sorted this out - if (muxlength > avpkt->size) - return AVERROR_INVALIDDATA; - - if ((err = read_audio_mux_element(latmctx, &gb))) - return (err < 0) ? err : avpkt->size; - - if (!latmctx->initialized) { - if (!avctx->extradata) { - *got_frame_ptr = 0; - return avpkt->size; - } else { - push_output_configuration(&latmctx->aac_ctx); - if ((err = decode_audio_specific_config( - &latmctx->aac_ctx, avctx, &latmctx->aac_ctx.oc[1].m4ac, - avctx->extradata, avctx->extradata_size*8LL, 1)) < 0) { - pop_output_configuration(&latmctx->aac_ctx); - return err; - } - latmctx->initialized = 1; - } - } - - if (show_bits(&gb, 12) == 0xfff) { - av_log(latmctx->aac_ctx.avctx, AV_LOG_ERROR, - "ADTS header detected, probably as result of configuration " - "misparsing\n"); - return AVERROR_INVALIDDATA; - } - - switch (latmctx->aac_ctx.oc[1].m4ac.object_type) { - case AOT_ER_AAC_LC: - case AOT_ER_AAC_LTP: - case AOT_ER_AAC_LD: - case AOT_ER_AAC_ELD: - err = aac_decode_er_frame(avctx, out, got_frame_ptr, &gb); - break; - default: - err = aac_decode_frame_int(avctx, out, got_frame_ptr, &gb, avpkt); - } - if (err < 0) - return err; - - return muxlength; -} - -static av_cold int latm_decode_init(AVCodecContext *avctx) -{ - struct LATMContext *latmctx = avctx->priv_data; - int ret = aac_decode_init(avctx); - - if (avctx->extradata_size > 0) - latmctx->initialized = !ret; - - return ret; -} +#include "libavcodec/aac/aacdec_latm.h" const FFCodec ff_aac_decoder = { .p.name = "aac", @@ -376,30 +87,6 @@ const FFCodec ff_aac_decoder = { .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), }; -/* - Note: This decoder filter is intended to decode LATM streams transferred - in MPEG transport streams which only contain one program. - To do a more complex LATM demuxing a separate LATM demuxer should be used. -*/ -const FFCodec ff_aac_latm_decoder = { - .p.name = "aac_latm", - CODEC_LONG_NAME("AAC LATM (Advanced Audio Coding LATM syntax)"), - .p.type = AVMEDIA_TYPE_AUDIO, - .p.id = AV_CODEC_ID_AAC_LATM, - .priv_data_size = sizeof(struct LATMContext), - .init = latm_decode_init, - .close = ff_aac_decode_close, - FF_CODEC_DECODE_CB(latm_decode_frame), - .p.sample_fmts = (const enum AVSampleFormat[]) { - AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE - }, - .p.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1, - .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - .p.ch_layouts = ff_aac_ch_layout, - .flush = flush, - .p.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), -}; - const FFCodec ff_aac_fixed_decoder = { .p.name = "aac_fixed", CODEC_LONG_NAME("AAC (Advanced Audio Coding)"), |