[FFmpeg-devel] [PATCH] LATM Parser & LATM/AAC Decoder

Alex Converse alex.converse
Mon Apr 20 17:59:56 CEST 2009


On Mon, Apr 20, 2009 at 3:11 AM, Paul Kendall <paul at kcbbs.gen.nz> wrote:
> After a long delay and some thinking...
> The first patch is for a LATM Parser and LATM/AAC Decoder using
> libfaad2. The second patch is to add support for LATM to mpegts &
> mpeg.
>
> Please comment and I'll endeavor to to get any fixes done ASAP.
>
[...]
> Index: libavcodec/latmaac.c
> ===================================================================
> --- libavcodec/latmaac.c	(revision 0)
> +++ libavcodec/latmaac.c	(revision 0)
> @@ -0,0 +1,398 @@
> +/*
> + * copyright (c) 2008 Paul Kendall <paul at kcbbs.gen.nz>
> + *
> + * 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
> + */
> +
> +/**
> + * @file latmaac.c
> + * LATM wrapped AAC decoder
> + */
> +
> +#include <stdio.h>

What for?

> +#include <stdlib.h>
> +#include <string.h>
> +#include <math.h>
> +#include <sys/types.h>
> +
> +#include "parser.h"
> +#include "get_bits.h"
> +#include "put_bits.h"
> +#include "mpeg4audio.h"
> +#include "neaacdec.h"
> +
> +#define min(a,b) ((a)<(b) ? (a) : (b))
> +
> +/*
> +    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.
> +*/
> +
> +#define SYNC_LATM   0x2b7       // 11 bits
> +#define MAX_SIZE    8*1024
> +
> +typedef struct AACDecoder
> +{
> +    faacDecHandle   aac_decoder;
> +    uint8_t         initialized;
> +
> +    // parser data
> +    uint8_t         audio_mux_version_A;
> +    uint8_t         frameLengthType;
> +    uint8_t         extra[64];            // should be way enough
> +    int             extrasize;
> +} AACDecoder;
> +
> +static inline int64_t latm_get_value(GetBitContext *b)

Seems like this can fit in an unsigned 32-bit int.

> +{
> +    uint8_t bytesForValue = get_bits(b, 2);
> +    int64_t value = 0;
> +    int i;
> +    for (i=0; i<=bytesForValue; i++) {
> +        value <<= 8;
> +        value |= get_bits(b, 8);
> +    }
> +    return value;
> +}
> +
> +static void readGASpecificConfig(int audioObjectType, GetBitContext *b, PutBitContext *o)
> +{
> +    int framelen_flag;
> +    int dependsOnCoder;
> +    int ext_flag;
> +
> +    framelen_flag = get_bits(b, 1);
> +    put_bits(o, 1, framelen_flag);
> +    dependsOnCoder = get_bits(b, 1);
> +    put_bits(o, 1, dependsOnCoder);
> +    if (dependsOnCoder) {
> +        int delay = get_bits(b, 14);
> +        put_bits(o, 14, delay);
> +    }
> +    ext_flag = get_bits(b, 1);
> +    put_bits(o, 1, ext_flag);
> +
> +    if (audioObjectType == 6 || audioObjectType == 20) {

There is an AOT enum in mpeg4audio.h

> +        int layerNr = get_bits(b, 3);
> +        put_bits(o, 3, layerNr);
> +    }
> +    if (ext_flag) {
> +        if (audioObjectType == 22) {
> +            skip_bits(b, 5);                    // numOfSubFrame
> +            skip_bits(b, 11);                   // layer_length
> +
> +            put_bits(o, 16, 0);
> +        }
> +        if (audioObjectType == 17 ||
> +                audioObjectType == 19 ||
> +                audioObjectType == 20 ||
> +                audioObjectType == 23) {
> +
> +            skip_bits(b, 3);                    // stuff
> +            put_bits(o, 3, 0);
> +        }
> +
> +        skip_bits(b, 1);                        // extflag3
> +        put_bits(o, 1, 0);
> +    }
> +}
> +
> +static int readAudioSpecificConfig(struct AACDecoder *decoder, GetBitContext *b)
> +{
> +    PutBitContext o;
> +    int ret = 0;
> +    int audioObjectType;
> +    int samplingFrequencyIndex;
> +    int channelConfiguration;
> +
> +    init_put_bits(&o, decoder->extra, sizeof(decoder->extra));
> +
> +    audioObjectType = get_bits(b, 5);
> +    put_bits(&o, 5, audioObjectType);
> +    if (audioObjectType == 31) {
> +        uint8_t extended = get_bits(b, 6);
> +        put_bits(&o, 6, extended);
> +        audioObjectType = 32 + extended;
> +    }
> +
> +    samplingFrequencyIndex = get_bits(b, 4);
> +    put_bits(&o, 4, samplingFrequencyIndex);
> +    if (samplingFrequencyIndex == 0x0f) {
> +        uint32_t f = get_bits_long(b, 24);
> +        put_bits(&o, 24, f);
> +    }
> +    channelConfiguration = get_bits(b, 4);
> +    put_bits(&o, 4, channelConfiguration);
> +
> +    if (audioObjectType == 1 || audioObjectType == 2 || audioObjectType == 3
> +            || audioObjectType == 4 || audioObjectType == 6 || audioObjectType == 7) {
> +        readGASpecificConfig(audioObjectType, b, &o);
> +    } else if (audioObjectType == 5) {
> +        int sbr_present = 1;
> +        samplingFrequencyIndex = get_bits(b, 4);
> +        if (samplingFrequencyIndex == 0x0f) {
> +            uint32_t f = get_bits_long(b, 24);
> +            put_bits(&o, 24, f);
> +        }
> +        audioObjectType = get_bits(b, 5);
> +        put_bits(&o, 5, audioObjectType);
> +    } else if (audioObjectType >= 17) {
> +        int epConfig;
> +        readGASpecificConfig(audioObjectType, b, &o);
> +        epConfig = get_bits(b, 2);
> +        put_bits(&o, 2, epConfig);
> +    }
> +
> +    // count the extradata
> +    ret = put_bits_count(&o);
> +    decoder->extrasize = (ret + 7) / 8;
> +
> +    flush_put_bits(&o);
> +    return ret;
> +}
> +
> +static void readStreamMuxConfig(struct AACDecoder *parser, GetBitContext *b)
> +{
> +    int audio_mux_version = get_bits(b, 1);
> +    parser->audio_mux_version_A = 0;
> +    if (audio_mux_version == 1) {                // audioMuxVersion
> +        parser->audio_mux_version_A = get_bits(b, 1);
> +    }
> +
> +    if (parser->audio_mux_version_A == 0) {
> +        int frame_length_type;
> +
> +        if (audio_mux_version == 1) {
> +            // taraFullness
> +            latm_get_value(b);
> +        }
> +        get_bits(b, 1);                    // allStreamSameTimeFraming = 1
> +        get_bits(b, 6);                    // numSubFrames = 0
> +        get_bits(b, 4);                    // numPrograms = 0
> +
> +        // for each program (which there is only on in DVB)
> +        get_bits(b, 3);                    // numLayer = 0
> +
> +        // for each layer (which there is only on in DVB)
> +        if (audio_mux_version == 0) {
> +            readAudioSpecificConfig(parser, b);
> +        } else {
> +            int ascLen = latm_get_value(b);
> +            ascLen -= readAudioSpecificConfig(parser, b);
> +
> +            // skip left over bits
> +            while (ascLen > 16) {
> +                skip_bits(b, 16);
> +                ascLen -= 16;
> +            }
> +            skip_bits(b, ascLen);
> +        }
> +
> +        // these are not needed... perhaps
> +        frame_length_type = get_bits(b, 3);
> +        parser->frameLengthType = frame_length_type;
> +        if (frame_length_type == 0) {
> +            get_bits(b, 8);
> +        } else if (frame_length_type == 1) {
> +            get_bits(b, 9);
> +        } else if (frame_length_type == 3 || frame_length_type == 4 || frame_length_type == 5) {
> +            // celp_table_index
> +            get_bits(b, 6);
> +        } else if (frame_length_type == 6 || frame_length_type == 7) {
> +            // hvxc_table_index
> +            get_bits(b, 1);
> +        }
> +
> +        // other data
> +        if (get_bits(b, 1)) {
> +            // other data present
> +            if (audio_mux_version == 1) {
> +                // other_data_bits
> +                latm_get_value(b);
> +            } else {
> +                int esc, tmp;
> +                // other data bits
> +                int64_t other_data_bits = 0;
> +                do {
> +                    esc = get_bits(b, 1);
> +                    tmp = get_bits(b, 8);
> +                    other_data_bits = other_data_bits << 8 | tmp;
> +                } while (esc);
> +            }
> +        }
> +
> +        // CRC if necessary
> +        if (get_bits(b, 1)) {
> +            // config_crc
> +            get_bits(b, 8);
> +        }
> +    } else {
> +        // TBD
> +    }
> +}
> +
> +static int readPayloadLengthInfo(struct AACDecoder *parser, GetBitContext *b)
> +{
> +    uint8_t tmp;
> +    if (parser->frameLengthType == 0) {
> +        int muxSlotLengthBytes = 0;
> +        do {
> +            tmp = get_bits(b, 8);
> +            muxSlotLengthBytes += tmp;
> +        } while (tmp == 255);
> +        return muxSlotLengthBytes;
> +    } else {
> +        if (parser->frameLengthType == 3 ||
> +                parser->frameLengthType == 5 ||
> +                parser->frameLengthType == 7) {
> +            get_bits(b, 2);
> +        }
> +        return 0;
> +    }
> +}
> +
> +static void readAudioMuxElement(struct AACDecoder *parser, GetBitContext *b, uint8_t *payload, int *payloadsize)
> +{
> +    uint8_t use_same_mux = get_bits(b, 1);
> +    if (!use_same_mux) {
> +        readStreamMuxConfig(parser, b);
> +    }
> +    if (parser->audio_mux_version_A == 0) {
> +        int j;
> +        int muxSlotLengthBytes = readPayloadLengthInfo(parser, b);
> +        muxSlotLengthBytes = min(muxSlotLengthBytes, *payloadsize);
> +        for (j=0; j<muxSlotLengthBytes; j++) {
> +            *payload++ = get_bits(b, 8);
> +        }
> +        *payloadsize = muxSlotLengthBytes;
> +    }
> +}
> +
> +static int readAudioSyncStream(struct AACDecoder *parser, GetBitContext *b, int size, uint8_t *payload, int *payloadsize)
> +{
> +    int muxlength;
> +
> +    if (get_bits(b, 11) != SYNC_LATM) return -1;    // not LATM
> +
> +    muxlength = get_bits(b, 13);
> +    if (muxlength+3 > size) return -1;          // not enough data, the parser should have sorted this
> +
> +    readAudioMuxElement(parser, b, payload, payloadsize);
> +
> +    return 0;
> +}
> +
> +static void channel_setup(AVCodecContext *avctx)
> +{
> +    AACDecoder *decoder = avctx->priv_data;
> +    if (avctx->request_channels == 2 && avctx->channels > 2) {
> +        NeAACDecConfigurationPtr faac_cfg;
> +        avctx->channels = 2;
> +        faac_cfg = NeAACDecGetCurrentConfiguration(decoder->aac_decoder);
> +        if (faac_cfg) {
> +            faac_cfg->downMatrix = 1;
> +            faac_cfg->defSampleRate = (!avctx->sample_rate) ? 44100 : avctx->sample_rate;
> +            NeAACDecSetConfiguration(decoder->aac_decoder, faac_cfg);
> +        }
> +    }
> +}
> +
> +static int faac_decode_frame(AVCodecContext *avctx, void *out, int *out_size, uint8_t *data, int size)
> +{
> +    AACDecoder      *decoder = avctx->priv_data;
> +    GetBitContext   b;
> +    uint8_t         tempbuf[MAX_SIZE];
> +    int             bufsize = sizeof(tempbuf);
> +    int             max_size = *out_size;
> +
> +    //-------------------------------------------------------------------------

These big separators are generally frowned upon.

> +    // Multiplex Parsing
> +    //-------------------------------------------------------------------------
> +    init_get_bits(&b, data, size * 8);
> +    if (readAudioSyncStream(decoder, &b, size, tempbuf, &bufsize)) {
> +        return -1;
> +    }
> +
> +    //-------------------------------------------------------------------------
> +    // Initialize decoder (if necessary)
> +    //-------------------------------------------------------------------------
> +    if (!decoder->initialized) {
> +        // we are going to initialize from decoder specific info when available
> +        if (decoder->extrasize > 0) {
> +            if (NeAACDecInit2(decoder->aac_decoder, decoder->extra, decoder->extrasize, &avctx->sample_rate, &avctx->channels)) {
> +                return -1;
> +            }
> +            channel_setup(avctx);
> +            decoder->initialized = 1;
> +        } else {
> +            *out_size = 0;
> +            return size;
> +        }
> +    }
> +
> +    //-------------------------------------------------------------------------
> +    // Decode samples
> +    //-------------------------------------------------------------------------
> +    NeAACDecFrameInfo    info;

Should be declared at the top of its scope.

> +    if (!NeAACDecDecode2(decoder->aac_decoder, &info, tempbuf, bufsize, &out, max_size)) {
> +        return -1;
> +    }
> +    *out_size = info.samples * sizeof(short);
> +    return size;
> +}
> +
> +static int faac_decode_init(AVCodecContext *avctx)
> +{
> +    AACDecoder *decoder = avctx->priv_data;
> +    NeAACDecConfigurationPtr faac_cfg;
> +
> +    avctx->bit_rate = 0;
> +    decoder->aac_decoder = NeAACDecOpen();
> +    if (!decoder->aac_decoder) {
> +        return -1;
> +    }
> +
> +    faac_cfg = NeAACDecGetCurrentConfiguration(decoder->aac_decoder);
> +    if (faac_cfg) {
> +        faac_cfg->outputFormat = FAAD_FMT_16BIT;
> +        faac_cfg->defSampleRate = (!avctx->sample_rate) ? 44100 : avctx->sample_rate;
> +        faac_cfg->defObjectType = LC;
This should use the AOT fished out of the AudioSpecificConfig
> +        NeAACDecSetConfiguration(decoder->aac_decoder, faac_cfg);
> +    }
> +
> +    decoder->initialized = 0;
> +    return 0;
> +}
> +
> +static int faac_decode_end(AVCodecContext *avctx)
> +{
> +    AACDecoder *decoder = avctx->priv_data;
> +    NeAACDecClose(decoder->aac_decoder);
> +    return 0;
> +}
> +
> +AVCodec libfaad_latm_decoder = {
> +    .name = "AAC/LATM",
> +    .type = CODEC_TYPE_AUDIO,
> +    .id = CODEC_ID_AAC_LATM,
> +    .priv_data_size = sizeof (AACDecoder),
> +    .init = faac_decode_init,
> +    .close = faac_decode_end,
> +    .decode = faac_decode_frame,
> +    .long_name = "AAC over LATM",
> +};
[...]

Regards,
Alex Converse



More information about the ffmpeg-devel mailing list