diff options
author | eddyg <[email protected]> | 2008-07-02 00:00:02 +0000 |
---|---|---|
committer | eddyg <[email protected]> | 2008-07-02 00:00:02 +0000 |
commit | 9da96ff4400c93e5559204e96552f8d777ac7dda (patch) | |
tree | 80f113048520d22734f1a6075a97c257c77b32ff | |
parent | 23b08913469981587d91e628ca9331d2693fffdf (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/Jamfile | 1 | ||||
-rw-r--r-- | contrib/patch-ffmpeg-latm.patch | 895 | ||||
-rwxr-xr-x | libhb/stream.c | 2 |
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"), |