summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreddyg <[email protected]>2008-07-02 00:00:02 +0000
committereddyg <[email protected]>2008-07-02 00:00:02 +0000
commit9da96ff4400c93e5559204e96552f8d777ac7dda (patch)
tree80f113048520d22734f1a6075a97c257c77b32ff
parent23b08913469981587d91e628ca9331d2693fffdf (diff)
Added Paul Kendalls ffmpeg AAC-LATM codec. Allows HB to decode AAC-LATM
MPEG-TS DVB streams. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@1550 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r--contrib/Jamfile1
-rw-r--r--contrib/patch-ffmpeg-latm.patch895
-rwxr-xr-xlibhb/stream.c2
3 files changed, 897 insertions, 1 deletions
diff --git a/contrib/Jamfile b/contrib/Jamfile
index 9e226769a..a723f1b7b 100644
--- a/contrib/Jamfile
+++ b/contrib/Jamfile
@@ -78,6 +78,7 @@ LibFaad2 $(SUBDIR)/lib/libfaad.a : $(SUBDIR)/faad2.tar.gz ;
rule LibAvCodec
{
FFMPEG_PATCH = "$(PATCH) -p0 < ../patch-ffmpeg.patch" ;
+ FFMPEG_PATCH += " && $(PATCH) -p0 < ../patch-ffmpeg-latm.patch " ;
if $(OS) = CYGWIN
{
FFMPEG_PATCH += " && $(PATCH) -p1 < ../patch-ffmpeg-cygwin.patch " ;
diff --git a/contrib/patch-ffmpeg-latm.patch b/contrib/patch-ffmpeg-latm.patch
new file mode 100644
index 000000000..6f7c925b8
--- /dev/null
+++ b/contrib/patch-ffmpeg-latm.patch
@@ -0,0 +1,895 @@
+Index: libavcodec/Makefile
+===================================================================
+--- libavcodec/Makefile (revision 14016)
++++ libavcodec/Makefile (working copy)
+@@ -322,7 +322,7 @@
+ OBJS-$(CONFIG_LIBDIRAC_DECODER) += libdiracdec.o
+ OBJS-$(CONFIG_LIBDIRAC_ENCODER) += libdiracenc.o libdirac_libschro.o
+ OBJS-$(CONFIG_LIBFAAC) += libfaac.o
+-OBJS-$(CONFIG_LIBFAAD) += libfaad.o
++OBJS-$(CONFIG_LIBFAAD) += libfaad.o latmaac.o
+ OBJS-$(CONFIG_LIBGSM) += libgsm.o
+ OBJS-$(CONFIG_LIBMP3LAME) += libmp3lame.o
+ OBJS-$(CONFIG_LIBSCHROEDINGER_DECODER) += libschroedingerdec.o libschroedinger.o libdirac_libschro.o
+@@ -333,7 +333,7 @@
+ OBJS-$(CONFIG_LIBXVID) += libxvidff.o libxvid_rc.o
+
+
+-OBJS-$(CONFIG_AAC_PARSER) += aac_parser.o aac_ac3_parser.o mpeg4audio.o
++OBJS-$(CONFIG_AAC_PARSER) += aac_parser.o aac_ac3_parser.o mpeg4audio.o latm_parser.o
+ OBJS-$(CONFIG_AC3_PARSER) += ac3_parser.o ac3tab.o aac_ac3_parser.o
+ OBJS-$(CONFIG_CAVSVIDEO_PARSER) += cavs_parser.o
+ OBJS-$(CONFIG_DCA_PARSER) += dca_parser.o
+Index: libavcodec/latmaac.c
+===================================================================
+--- libavcodec/latmaac.c (revision 0)
++++ libavcodec/latmaac.c (revision 0)
+@@ -0,0 +1,624 @@
++/*
++ * copyright (c) 2008 Paul Kendall <[email protected]>
++ *
++ * 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>
++#include <stdlib.h>
++#include <string.h>
++#include <math.h>
++#include <sys/types.h>
++
++#include "parser.h"
++#include "bitstream.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 are only supposed to contain one program.
++ To do a more complex LATM demuxing a separate LATM demuxer should be used.
++*/
++
++#define AAC_NONE 0 // mode not detected (or indicated in mediatype)
++#define AAC_LATM 1 // LATM packets (ISO/IEC 14496-3 1.7.3 Multiplex layer)
++
++#define SYNC_LATM 0x2b7 // 11 bits
++
++#define MAX_SIZE 8*1024
++
++typedef struct AACConfig
++{
++ uint8_t extra[64]; // should be way enough
++ int extrasize;
++
++ int audioObjectType;
++ int samplingFrequencyIndex;
++ int samplingFrequency;
++ int channelConfiguration;
++ int channels;
++} AACConfig;
++
++typedef struct AACParser
++{
++ AACConfig config;
++ uint8_t frameLengthType;
++ uint16_t muxSlotLengthBytes;
++
++ uint8_t audio_mux_version;
++ uint8_t audio_mux_version_A;
++ int taraFullness;
++ uint8_t config_crc;
++ int64_t other_data_bits;
++
++ int mode;
++ int offset; // byte offset in "buf" buffer
++ uint8_t buf[MAX_SIZE]; // allocated buffer
++ int count; // number of bytes written in buffer
++} AACParser;
++
++typedef struct AACDecoder
++{
++ AACParser *parser;
++ faacDecHandle aac_decoder;
++ int open;
++ uint32_t in_samplerate;
++ uint8_t in_channels;
++} AACDecoder;
++
++typedef struct {
++ AACDecoder* decoder;
++} FAACContext;
++
++static inline int64_t latm_get_value(GetBitContext *b)
++{
++ 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(struct AACConfig *cfg, GetBitContext *b, PutBitContext *o)
++{
++ int framelen_flag = get_bits(b, 1);
++ put_bits(o, 1, framelen_flag);
++ int dependsOnCoder = get_bits(b, 1);
++ put_bits(o, 1, dependsOnCoder);
++ int ext_flag;
++ int delay;
++ int layerNr;
++
++ if (dependsOnCoder) {
++ delay = get_bits(b, 14);
++ put_bits(o, 14, delay);
++ }
++ ext_flag = get_bits(b, 1);
++ put_bits(o, 1, ext_flag);
++ if (!cfg->channelConfiguration) {
++ // program config element
++ // TODO:
++ }
++
++ if (cfg->audioObjectType == 6 || cfg->audioObjectType == 20) {
++ layerNr = get_bits(b, 3);
++ put_bits(o, 3, layerNr);
++ }
++ if (ext_flag) {
++ if (cfg->audioObjectType == 22) {
++ skip_bits(b, 5); // numOfSubFrame
++ skip_bits(b, 11); // layer_length
++
++ put_bits(o, 16, 0);
++ }
++ if (cfg->audioObjectType == 17 ||
++ cfg->audioObjectType == 19 ||
++ cfg->audioObjectType == 20 ||
++ cfg->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 AACConfig *cfg, GetBitContext *b)
++{
++ PutBitContext o;
++ init_put_bits(&o, cfg->extra, sizeof(cfg->extra));
++
++ // returns the number of bits read
++ int ret = 0;
++ int sbr_present = -1;
++
++ // object
++ cfg->audioObjectType = get_bits(b, 5);
++ put_bits(&o, 5, cfg->audioObjectType);
++ if (cfg->audioObjectType == 31) {
++ uint8_t n = get_bits(b, 6);
++ put_bits(&o, 6, n);
++ cfg->audioObjectType = 32 + n;
++ }
++
++ cfg->samplingFrequencyIndex = get_bits(b, 4);
++ cfg->samplingFrequency = ff_mpeg4audio_sample_rates[cfg->samplingFrequencyIndex];
++ put_bits(&o, 4, cfg->samplingFrequencyIndex);
++ if (cfg->samplingFrequencyIndex == 0x0f) {
++ uint32_t f = get_bits_long(b, 24);
++ put_bits(&o, 24, f);
++ cfg->samplingFrequency = f;
++ }
++ cfg->channelConfiguration = get_bits(b, 4);
++ put_bits(&o, 4, cfg->channelConfiguration);
++ cfg->channels = ff_mpeg4audio_channels[cfg->channelConfiguration];
++
++ if (cfg->audioObjectType == 5) {
++ sbr_present = 1;
++
++ // TODO: parsing !!!!!!!!!!!!!!!!
++ }
++
++ switch (cfg->audioObjectType) {
++ case 1:
++ case 2:
++ case 3:
++ case 4:
++ case 6:
++ case 7:
++ case 17:
++ case 19:
++ case 20:
++ case 21:
++ case 22:
++ case 23:
++ readGASpecificConfig(cfg, b, &o);
++ break;
++ }
++
++ if (sbr_present == -1) {
++ if (cfg->samplingFrequency <= 24000) {
++ cfg->samplingFrequency *= 2;
++ }
++ }
++
++ // count the extradata
++ ret = put_bits_count(&o);
++ align_put_bits(&o);
++ flush_put_bits(&o);
++ cfg->extrasize = (ret + 7) >> 3;
++ return ret;
++}
++
++static void readStreamMuxConfig(struct AACParser *parser, GetBitContext *b)
++{
++ parser->audio_mux_version_A = 0;
++ parser->audio_mux_version = get_bits(b, 1);
++ if (parser->audio_mux_version == 1) { // audioMuxVersion
++ parser->audio_mux_version_A = get_bits(b, 1);
++ }
++
++ if (parser->audio_mux_version_A == 0) {
++ if (parser->audio_mux_version == 1) {
++ parser->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
++ get_bits(b, 3); // numLayer = 0
++
++ // for each layer
++ if (parser->audio_mux_version == 0) {
++ // audio specific config.
++ readAudioSpecificConfig(&parser->config, b);
++ } else {
++ int ascLen = latm_get_value(b);
++ ascLen -= readAudioSpecificConfig(&parser->config, b);
++
++ // fill bits
++ while (ascLen > 16) {
++ skip_bits(b, 16);
++ ascLen -= 16;
++ }
++ skip_bits(b, ascLen);
++ }
++
++ // these are not needed... perhaps
++ int 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) {
++ int celp_table_index = get_bits(b, 6);
++ } else if (frame_length_type == 6 ||
++ frame_length_type == 7) {
++ int hvxc_table_index = get_bits(b, 1);
++ }
++
++ // other data
++ parser->other_data_bits = 0;
++ if (get_bits(b, 1)) {
++ // other data present
++ if (parser->audio_mux_version == 1) {
++ parser->other_data_bits = latm_get_value(b);
++ } else {
++ // other data not present
++ parser->other_data_bits = 0;
++ int esc, tmp;
++ do {
++ parser->other_data_bits <<= 8;
++ esc = get_bits(b, 1);
++ tmp = get_bits(b, 8);
++ parser->other_data_bits |= tmp;
++ } while (esc);
++ }
++ }
++
++ // CRC
++ if (get_bits(b, 1)) {
++ parser->config_crc = get_bits(b, 8);
++ }
++ } else {
++ // tbd
++ }
++}
++
++static void readPayloadLengthInfo(struct AACParser *parser, GetBitContext *b)
++{
++ uint8_t tmp;
++ if (parser->frameLengthType == 0) {
++ parser->muxSlotLengthBytes = 0;
++ do {
++ tmp = get_bits(b, 8);
++ parser->muxSlotLengthBytes += tmp;
++ } while (tmp == 255);
++ } else {
++ if (parser->frameLengthType == 5 ||
++ parser->frameLengthType == 7 ||
++ parser->frameLengthType == 3) {
++ get_bits(b, 2);
++ }
++ }
++}
++
++static void readAudioMuxElement(struct AACParser *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;
++
++ readPayloadLengthInfo(parser, b);
++
++ // copy data
++ for (j=0; j<parser->muxSlotLengthBytes; j++) {
++ *payload++ = get_bits(b, 8);
++ }
++ *payloadsize = parser->muxSlotLengthBytes;
++
++ // ignore otherdata
++ } else {
++ // TBD
++ }
++}
++
++static int readAudioSyncStream(struct AACParser *parser, GetBitContext *b, int size, uint8_t *payload, int *payloadsize)
++{
++ // ISO/IEC 14496-3 Table 1.28 - Syntax of AudioMuxElement()
++ if (get_bits(b, 11) != 0x2b7) return -1; // not LATM
++ int muxlength = get_bits(b, 13);
++
++ if (3+muxlength > size) return 0; // not enough data
++
++ readAudioMuxElement(parser, b, payload, payloadsize);
++
++ // we don't parse anything else here...
++ return (3+muxlength);
++}
++
++
++static void flush_buf(struct AACParser *parser, int offset) {
++ int bytes_to_flush = min(parser->count, offset);
++ int left = (parser->count - bytes_to_flush);
++
++ if (bytes_to_flush > 0) {
++ if (left > 0) {
++ memcpy(parser->buf, parser->buf+bytes_to_flush, left);
++ parser->count = left;
++ } else {
++ parser->count = 0;
++ }
++ }
++}
++
++static struct AACParser *latm_create_parser()
++{
++ struct AACParser *parser = (struct AACParser *)av_malloc(sizeof(struct AACParser));
++ memset(parser, 0, sizeof(struct AACParser));
++ return parser;
++}
++
++static void latm_destroy_parser(struct AACParser *parser)
++{
++ av_free(parser);
++}
++
++static void latm_flush(struct AACParser *parser)
++{
++ parser->offset = 0;
++ parser->count = 0;
++}
++
++static void latm_write_data(struct AACParser *parser, uint8_t *data, int len)
++{
++ // buffer overflow check... just ignore the data before
++ if (parser->count + len > MAX_SIZE) {
++ flush_buf(parser, parser->offset);
++ parser->offset = 0;
++ if (parser->count + len > MAX_SIZE) {
++ int to_flush = (parser->count+len) - MAX_SIZE;
++ flush_buf(parser, to_flush);
++ }
++ }
++
++ // append data
++ memcpy(parser->buf+parser->count, data, len);
++ parser->count += len;
++}
++
++static int latm_parse_packet(struct AACParser *parser, uint8_t *data, int maxsize)
++{
++ /*
++ Return value is either number of bytes parsed or
++ -1 when failed.
++ 0 = need more data.
++ */
++
++ uint8_t *start = parser->buf + parser->offset;
++ int bytes = parser->count - parser->offset;
++ GetBitContext b;
++ init_get_bits(&b, start, bytes);
++
++ if (parser->mode == AAC_LATM) {
++ int outsize = 0;
++ int ret = readAudioSyncStream(parser, &b, bytes, data, &outsize);
++
++ if (ret < 0) return -1;
++ if (ret == 0) return 0;
++
++ // update the offset
++ parser->offset += ret;
++ return outsize;
++ }
++
++ // check for syncwords
++ while (bytes > 2) {
++ if (show_bits(&b, 11) == SYNC_LATM) {
++ // we must parse config first...
++ int outsize = 0;
++
++ // check if there is a complete packet available...
++ int ret = readAudioSyncStream(parser, &b, bytes, data, &outsize);
++ if (ret < 0) return -1;
++ if (ret == 0) return 0;
++ parser->offset += ret;
++
++ parser->mode = AAC_LATM;
++ return outsize;
++ }
++ skip_bits(&b, 8);
++ parser->offset++;
++ bytes--;
++ }
++ return 0;
++}
++
++static void aac_filter_close(AACDecoder *decoder)
++{
++ if (decoder->aac_decoder) {
++ NeAACDecClose(decoder->aac_decoder);
++ decoder->aac_decoder = NULL;
++ }
++ decoder->open = 0;
++}
++
++static int aac_decoder_open(AACDecoder *decoder)
++{
++ if (decoder->aac_decoder) return 0;
++
++ decoder->aac_decoder = NeAACDecOpen();
++ if (!decoder->aac_decoder) return -1;
++
++ // are we going to initialize from decoder specific info ?
++ if (decoder->parser->config.extrasize > 0) {
++ char ret = NeAACDecInit2(decoder->aac_decoder, (unsigned char*)decoder->parser->config.extra, decoder->parser->config.extrasize, &decoder->in_samplerate, &decoder->in_channels);
++ if (ret < 0) {
++ aac_filter_close(decoder); // gone wrong ?
++ return -1;
++ }
++ decoder->open = 1;
++ } else {
++ // we'll open the decoder later...
++ decoder->open = 0;
++ }
++ return 0;
++}
++
++AACDecoder *aac_filter_create()
++{
++ AACDecoder *decoder = (AACDecoder *)av_malloc(sizeof(AACDecoder));
++ decoder->parser = latm_create_parser();
++ decoder->aac_decoder = NULL;
++ decoder->open = 0;
++ return (void *)decoder;
++}
++
++void aac_filter_destroy(AACDecoder *decoder)
++{
++ aac_filter_close(decoder);
++ latm_destroy_parser(decoder->parser);
++ av_free(decoder);
++}
++
++int aac_filter_receive(AACDecoder *decoder, void *out, int *out_size, uint8_t *data, int size)
++{
++ uint8_t tempbuf[32*1024];
++ int ret;
++ int consumed = size;
++ int decoded;
++ int max_size = *out_size;
++
++ *out_size = 0;
++
++ //-------------------------------------------------------------------------
++ // Multiplex Parsing
++ //-------------------------------------------------------------------------
++
++ latm_write_data(decoder->parser, data, size);
++
++ do {
++ ret = latm_parse_packet(decoder->parser, tempbuf, sizeof(tempbuf));
++ if (ret < 0) {
++ latm_flush(decoder->parser);
++ return consumed;
++ }
++ if (ret == 0) return consumed;
++
++ data = tempbuf;
++ size = ret;
++
++ //-------------------------------------------------------------------------
++ // Initialize decoder (if necessary)
++ //-------------------------------------------------------------------------
++ if (!decoder->open) {
++ aac_filter_close(decoder);
++ if (decoder->parser->mode == AAC_LATM) {
++ ret = aac_decoder_open(decoder);
++ if (ret < 0) return consumed;
++ }
++
++ if(!decoder->open) return consumed;
++ }
++
++ //-------------------------------------------------------------------------
++ // Decode samples
++ //-------------------------------------------------------------------------
++ NeAACDecFrameInfo info;
++ void *buf = NeAACDecDecode(decoder->aac_decoder, &info, data, size);
++
++ if (buf) {
++ decoder->in_samplerate = info.samplerate;
++ decoder->in_channels = info.channels;
++
++ //---------------------------------------------------------------------
++ // Deliver decoded samples
++ //---------------------------------------------------------------------
++
++ // kram dekoduje 16-bit. my vypustame 16-bit. takze by to malo byt okej
++ decoded = info.samples * sizeof(short);
++
++ // napraskame tam sample
++ *out_size += decoded;
++ if(*out_size > max_size) {
++ av_log(NULL, AV_LOG_ERROR, "overflow!\n");
++ } else {
++ memcpy(out, buf, decoded);
++ out = (unsigned char *)out + decoded;
++ }
++ } else {
++ // need more data
++ break;
++ }
++
++ } while (1); // decode all packets
++ return consumed;
++}
++
++void aac_filter_getinfo(AACDecoder *decoder, int *sample_rate, int *channels)
++{
++ if(!decoder->open) return;
++ *sample_rate = decoder->in_samplerate;
++ *channels = decoder->in_channels;
++}
++
++static int faac_decode_init(AVCodecContext *avctx)
++{
++ FAACContext *s = avctx->priv_data;
++ avctx->frame_size = 360;
++ avctx->sample_rate = 48000;
++ avctx->channels = 2;
++ avctx->bit_rate = 8192 * 8 * avctx->sample_rate / avctx->frame_size;
++ s->decoder = aac_filter_create();
++ return 0;
++}
++
++static int faac_decode_frame(AVCodecContext *avctx,
++ void *data, int *data_size,
++ uint8_t *buf, int buf_size)
++{
++ FAACContext *s = avctx->priv_data;
++ int ret;
++
++ if (s->decoder == NULL) faac_decode_init(avctx);
++ ret = aac_filter_receive(s->decoder, data, data_size, buf, buf_size);
++ aac_filter_getinfo(s->decoder, &(avctx->sample_rate), &(avctx->channels));
++ return ret;
++}
++
++static int faac_decode_end(AVCodecContext *avctx)
++{
++ FAACContext *s = avctx->priv_data;
++ if(s->decoder != NULL) {
++ aac_filter_destroy(s->decoder);
++ }
++ return 0;
++}
++
++AVCodec libfaad2_decoder = {
++ .name = "AAC_LATM",
++ .type = CODEC_TYPE_AUDIO,
++ .id = CODEC_ID_AAC_LATM,
++ .priv_data_size = sizeof (FAACContext),
++ .init = faac_decode_init,
++ .close = faac_decode_end,
++ .decode = faac_decode_frame,
++ .long_name = "AAC over LATM",
++};
++
+Index: libavcodec/latm_parser.c
+===================================================================
+--- libavcodec/latm_parser.c (revision 0)
++++ libavcodec/latm_parser.c (revision 0)
+@@ -0,0 +1,128 @@
++/*
++ * LATM parser
++ * Copyright (c) 2008 Paul Kendall <[email protected]>
++ *
++ * 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 latm_parser.c
++ * LATM parser
++ */
++
++#include "parser.h"
++
++#define LATM_HEADER 0x56e000 // 0x2b7 (11 bits)
++#define LATM_MASK 0xFFE000 // top 11 bits
++#define LATM_SIZE_MASK 0x001FFF // bottom 13 bits
++
++typedef struct LATMParseContext{
++ ParseContext pc;
++ int count;
++} LATMParseContext;
++
++/**
++ * finds the end of the current frame in the bitstream.
++ * @return the position of the first byte of the next frame, or -1
++ */
++static int latm_find_frame_end(AVCodecParserContext *s1, const uint8_t *buf,
++ int buf_size) {
++ LATMParseContext *s = s1->priv_data;
++ ParseContext *pc = &s->pc;
++ int pic_found, i;
++ uint32_t state;
++
++ pic_found = pc->frame_start_found;
++ state = pc->state;
++
++ i = 0;
++ if(!pic_found){
++ for(i=0; i<buf_size; i++){
++ state = (state<<8) | buf[i];
++ if((state & LATM_MASK) == LATM_HEADER){
++ i++;
++ s->count = - i;
++ pic_found=1;
++ break;
++ }
++ }
++ }
++
++ if(pic_found){
++ /* EOF considered as end of frame */
++ if (buf_size == 0)
++ return 0;
++ if((state & LATM_SIZE_MASK) - s->count <= buf_size) {
++ pc->frame_start_found = 0;
++ pc->state = -1;
++ return (state & LATM_SIZE_MASK) - s->count;
++ }
++ }
++
++ s->count += buf_size;
++ pc->frame_start_found = pic_found;
++ pc->state = state;
++ return END_NOT_FOUND;
++}
++
++static int latm_parse(AVCodecParserContext *s1,
++ AVCodecContext *avctx,
++ const uint8_t **poutbuf, int *poutbuf_size,
++ const uint8_t *buf, int buf_size)
++{
++ LATMParseContext *s = s1->priv_data;
++ ParseContext *pc = &s->pc;
++ int next;
++
++ if(s1->flags & PARSER_FLAG_COMPLETE_FRAMES){
++ next = buf_size;
++ }else{
++ next = latm_find_frame_end(s1, buf, buf_size);
++
++ if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
++ *poutbuf = NULL;
++ *poutbuf_size = 0;
++ return buf_size;
++ }
++ }
++ *poutbuf = buf;
++ *poutbuf_size = buf_size;
++ return next;
++}
++
++static int latm_split(AVCodecContext *avctx,
++ const uint8_t *buf, int buf_size)
++{
++ int i;
++ uint32_t state= -1;
++
++ for(i=0; i<buf_size; i++){
++ state= (state<<8) | buf[i];
++ if((state & LATM_MASK) == LATM_HEADER)
++ return i-2;
++ }
++ return 0;
++}
++
++AVCodecParser aac_latm_parser = {
++ { CODEC_ID_AAC_LATM },
++ sizeof(LATMParseContext),
++ NULL,
++ latm_parse,
++ ff_parse_close,
++ latm_split,
++};
+Index: libavcodec/allcodecs.c
+===================================================================
+--- libavcodec/allcodecs.c (revision 14016)
++++ libavcodec/allcodecs.c (working copy)
+@@ -280,6 +280,7 @@
+ REGISTER_ENCDEC (LIBDIRAC, libdirac);
+ REGISTER_ENCODER (LIBFAAC, libfaac);
+ REGISTER_DECODER (LIBFAAD, libfaad);
++ REGISTER_DECODER (LIBFAAD, libfaad2);
+ REGISTER_ENCDEC (LIBGSM, libgsm);
+ REGISTER_ENCDEC (LIBGSM_MS, libgsm_ms);
+ REGISTER_ENCODER (LIBMP3LAME, libmp3lame);
+@@ -294,6 +295,7 @@
+
+ /* parsers */
+ REGISTER_PARSER (AAC, aac);
++ REGISTER_PARSER (AAC, aac_latm);
+ REGISTER_PARSER (AC3, ac3);
+ REGISTER_PARSER (CAVSVIDEO, cavsvideo);
+ REGISTER_PARSER (DCA, dca);
+Index: libavcodec/avcodec.h
+===================================================================
+--- libavcodec/avcodec.h (revision 14016)
++++ libavcodec/avcodec.h (working copy)
+@@ -259,6 +259,7 @@
+ #if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0)
+ CODEC_ID_MPEG4AAC,
+ #endif
++ CODEC_ID_AAC_LATM,
+ CODEC_ID_AC3,
+ CODEC_ID_DTS,
+ CODEC_ID_VORBIS,
+Index: libavformat/mpegts.c
+===================================================================
+--- libavformat/mpegts.c (revision 14016)
++++ libavformat/mpegts.c (working copy)
+@@ -611,6 +611,7 @@
+ case STREAM_TYPE_VIDEO_H264:
+ case STREAM_TYPE_VIDEO_VC1:
+ case STREAM_TYPE_AUDIO_AAC:
++ case STREAM_TYPE_AUDIO_AAC_LATM:
+ case STREAM_TYPE_AUDIO_AC3:
+ case STREAM_TYPE_AUDIO_DTS:
+ case STREAM_TYPE_AUDIO_HDMV_DTS:
+@@ -832,7 +833,7 @@
+ code = pes->header[3] | 0x100;
+ if (!((code >= 0x1c0 && code <= 0x1df) ||
+ (code >= 0x1e0 && code <= 0x1ef) ||
+- (code == 0x1bd) || (code == 0x1fd)))
++ (code == 0x1bd) || (code == 0x1fa) || (code == 0x1fd)))
+ goto skip;
+ if (!pes->st) {
+ /* allocate stream */
+@@ -948,6 +949,10 @@
+ codec_type = CODEC_TYPE_AUDIO;
+ codec_id = CODEC_ID_AAC;
+ break;
++ case STREAM_TYPE_AUDIO_AAC_LATM:
++ codec_type = CODEC_TYPE_AUDIO;
++ codec_id = CODEC_ID_AAC_LATM;
++ break;
+ case STREAM_TYPE_AUDIO_AC3:
+ codec_type = CODEC_TYPE_AUDIO;
+ codec_id = CODEC_ID_AC3;
+Index: libavformat/mpegts.h
+===================================================================
+--- libavformat/mpegts.h (revision 14016)
++++ libavformat/mpegts.h (working copy)
+@@ -50,6 +50,7 @@
+ #define STREAM_TYPE_PRIVATE_DATA 0x06
+ #define STREAM_TYPE_AUDIO_AAC 0x0f
+ #define STREAM_TYPE_VIDEO_MPEG4 0x10
++#define STREAM_TYPE_AUDIO_AAC_LATM 0x11
+ #define STREAM_TYPE_VIDEO_H264 0x1b
+ #define STREAM_TYPE_VIDEO_VC1 0xea
+
+Index: libavformat/mpeg.c
+===================================================================
+--- libavformat/mpeg.c (revision 14016)
++++ libavformat/mpeg.c (working copy)
+@@ -281,7 +281,7 @@
+ /* find matching stream */
+ if (!((startcode >= 0x1c0 && startcode <= 0x1df) ||
+ (startcode >= 0x1e0 && startcode <= 0x1ef) ||
+- (startcode == 0x1bd) || (startcode == 0x1fd)))
++ (startcode == 0x1bd) || (startcode == 0x1fa) || (startcode == 0x1fd)))
+ goto redo;
+ if (ppos) {
+ *ppos = url_ftell(s->pb) - 4;
+@@ -439,6 +439,9 @@
+ } else if(es_type == STREAM_TYPE_AUDIO_AAC){
+ codec_id = CODEC_ID_AAC;
+ type = CODEC_TYPE_AUDIO;
++ } else if(es_type == STREAM_TYPE_AUDIO_AAC_LATM){
++ codec_id = CODEC_ID_AAC_LATM;
++ type = CODEC_TYPE_AUDIO;
+ } else if(es_type == STREAM_TYPE_VIDEO_MPEG4){
+ codec_id = CODEC_ID_MPEG4;
+ type = CODEC_TYPE_VIDEO;
+Index: libavformat/mpeg.h
+===================================================================
+--- libavformat/mpeg.h (revision 14016)
++++ libavformat/mpeg.h (working copy)
+@@ -53,6 +53,7 @@
+ #define STREAM_TYPE_PRIVATE_DATA 0x06
+ #define STREAM_TYPE_AUDIO_AAC 0x0f
+ #define STREAM_TYPE_VIDEO_MPEG4 0x10
++#define STREAM_TYPE_AUDIO_AAC_LATM 0x11
+ #define STREAM_TYPE_VIDEO_H264 0x1b
+
+ #define STREAM_TYPE_AUDIO_AC3 0x81
diff --git a/libhb/stream.c b/libhb/stream.c
index 019475d1b..d4d1ea683 100755
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -51,7 +51,7 @@ static const stream2codec_t st2codec[256] = {
st(0x0e, U, 0, 0, "ISO 13818-1 auxiliary"),
st(0x0f, A, HB_ACODEC_MPGA, CODEC_ID_AAC, "ISO 13818-7 AAC Audio"),
st(0x10, V, WORK_DECAVCODECV, CODEC_ID_MPEG4, "MPEG4"),
- st(0x11, A, HB_ACODEC_MPGA, CODEC_ID_AAC, "MPEG4 LATM AAC"),
+ st(0x11, A, HB_ACODEC_MPGA, CODEC_ID_AAC_LATM, "MPEG4 LATM AAC"),
st(0x12, U, 0, 0, "MPEG4 generic"),
st(0x14, U, 0, 0, "ISO 13818-6 DSM-CC download"),