From 798c6facb7bd3ad5b46baf0e12ff02bc9c6e1bb6 Mon Sep 17 00:00:00 2001 From: Baptiste Coudurier Date: Tue, 23 Nov 2010 00:51:12 +0000 Subject: [PATCH] In ts demuxer, support aac flexmux using extradata in iods, issue #2346 Originally committed as revision 25806 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/Makefile | 2 +- libavformat/isom.c | 81 ++++++++++++++++++++++++++++++++++++++++++ libavformat/isom.h | 8 +++++ libavformat/mov.c | 84 +++----------------------------------------- libavformat/mpegts.c | 64 ++++++++++++++++++++++++++++++++- 5 files changed, 157 insertions(+), 82 deletions(-) diff --git a/libavformat/Makefile b/libavformat/Makefile index 1f63feee94..f61548123d 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -138,7 +138,7 @@ OBJS-$(CONFIG_MPEG2SVCD_MUXER) += mpegenc.o OBJS-$(CONFIG_MPEG1VIDEO_MUXER) += rawenc.o OBJS-$(CONFIG_MPEG2VIDEO_MUXER) += rawenc.o OBJS-$(CONFIG_MPEGPS_DEMUXER) += mpeg.o -OBJS-$(CONFIG_MPEGTS_DEMUXER) += mpegts.o +OBJS-$(CONFIG_MPEGTS_DEMUXER) += mpegts.o isom.o OBJS-$(CONFIG_MPEGTS_MUXER) += mpegtsenc.o adtsenc.o OBJS-$(CONFIG_MPEGVIDEO_DEMUXER) += mpegvideodec.o rawdec.o OBJS-$(CONFIG_MPJPEG_MUXER) += mpjpeg.o diff --git a/libavformat/isom.c b/libavformat/isom.c index 34404ad022..bf0140103a 100644 --- a/libavformat/isom.c +++ b/libavformat/isom.c @@ -21,9 +21,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +//#define DEBUG + #include "avformat.h" #include "internal.h" #include "isom.h" +#include "riff.h" +#include "libavcodec/mpeg4audio.h" +#include "libavcodec/mpegaudiodata.h" /* http://www.mp4ra.org */ /* ordered by muxing preference */ @@ -326,3 +331,79 @@ int ff_mov_lang_to_iso639(unsigned code, char to[4]) memcpy(to, mov_mdhd_language_map[code], 4); return 1; } + +int ff_mp4_read_descr_len(ByteIOContext *pb) +{ + int len = 0; + int count = 4; + while (count--) { + int c = get_byte(pb); + len = (len << 7) | (c & 0x7f); + if (!(c & 0x80)) + break; + } + return len; +} + +int ff_mp4_read_descr(AVFormatContext *fc, ByteIOContext *pb, int *tag) +{ + int len; + *tag = get_byte(pb); + len = ff_mp4_read_descr_len(pb); + dprintf(fc, "MPEG4 description: tag=0x%02x len=%d\n", *tag, len); + return len; +} + +static const AVCodecTag mp4_audio_types[] = { + { CODEC_ID_MP3ON4, AOT_PS }, /* old mp3on4 draft */ + { CODEC_ID_MP3ON4, AOT_L1 }, /* layer 1 */ + { CODEC_ID_MP3ON4, AOT_L2 }, /* layer 2 */ + { CODEC_ID_MP3ON4, AOT_L3 }, /* layer 3 */ + { CODEC_ID_MP4ALS, AOT_ALS }, /* MPEG-4 ALS */ + { CODEC_ID_NONE, AOT_NULL }, +}; + +int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, ByteIOContext *pb) +{ + int len, tag; + int object_type_id = get_byte(pb); + get_byte(pb); /* stream type */ + get_be24(pb); /* buffer size db */ + get_be32(pb); /* max bitrate */ + get_be32(pb); /* avg bitrate */ + + st->codec->codec_id= ff_codec_get_id(ff_mp4_obj_type, object_type_id); + dprintf(fc, "esds object type id 0x%02x\n", object_type_id); + len = ff_mp4_read_descr(fc, pb, &tag); + if (tag == MP4DecSpecificDescrTag) { + dprintf(fc, "Specific MPEG4 header len=%d\n", len); + if((uint64_t)len > (1<<30)) + return -1; + av_free(st->codec->extradata); + st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + get_buffer(pb, st->codec->extradata, len); + st->codec->extradata_size = len; + if (st->codec->codec_id == CODEC_ID_AAC) { + MPEG4AudioConfig cfg; + ff_mpeg4audio_get_config(&cfg, st->codec->extradata, + st->codec->extradata_size); + st->codec->channels = cfg.channels; + if (cfg.object_type == 29 && cfg.sampling_index < 3) // old mp3on4 + st->codec->sample_rate = ff_mpa_freq_tab[cfg.sampling_index]; + else if (cfg.ext_sample_rate) + st->codec->sample_rate = cfg.ext_sample_rate; + else + st->codec->sample_rate = cfg.sample_rate; + dprintf(fc, "mp4a config channels %d obj %d ext obj %d " + "sample rate %d ext sample rate %d\n", st->codec->channels, + cfg.object_type, cfg.ext_object_type, + cfg.sample_rate, cfg.ext_sample_rate); + if (!(st->codec->codec_id = ff_codec_get_id(mp4_audio_types, + cfg.object_type))) + st->codec->codec_id = CODEC_ID_AAC; + } + } + return 0; +} diff --git a/libavformat/isom.h b/libavformat/isom.h index 6c6ad5459f..2990c9ce82 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -142,6 +142,14 @@ typedef struct MOVContext { } MOVContext; int ff_mp4_read_descr_len(ByteIOContext *pb); +int ff_mp4_read_descr(AVFormatContext *fc, ByteIOContext *pb, int *tag); +int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, ByteIOContext *pb); + +#define MP4IODescrTag 0x02 +#define MP4ESDescrTag 0x03 +#define MP4DecConfigDescrTag 0x04 +#define MP4DecSpecificDescrTag 0x05 + int ff_mov_read_esds(AVFormatContext *fc, ByteIOContext *pb, MOVAtom atom); enum CodecID ff_mov_get_lpcm_codec_id(int bps, int flags); diff --git a/libavformat/mov.c b/libavformat/mov.c index cdaf6d36ba..1fc86ea332 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -31,8 +31,6 @@ #include "avformat.h" #include "riff.h" #include "isom.h" -#include "libavcodec/mpeg4audio.h" -#include "libavcodec/mpegaudiodata.h" #include "libavcodec/get_bits.h" #if CONFIG_ZLIB @@ -462,41 +460,6 @@ static int mov_read_hdlr(MOVContext *c, ByteIOContext *pb, MOVAtom atom) return 0; } -int ff_mp4_read_descr_len(ByteIOContext *pb) -{ - int len = 0; - int count = 4; - while (count--) { - int c = get_byte(pb); - len = (len << 7) | (c & 0x7f); - if (!(c & 0x80)) - break; - } - return len; -} - -static int mp4_read_descr(AVFormatContext *fc, ByteIOContext *pb, int *tag) -{ - int len; - *tag = get_byte(pb); - len = ff_mp4_read_descr_len(pb); - dprintf(fc, "MPEG4 description: tag=0x%02x len=%d\n", *tag, len); - return len; -} - -#define MP4ESDescrTag 0x03 -#define MP4DecConfigDescrTag 0x04 -#define MP4DecSpecificDescrTag 0x05 - -static const AVCodecTag mp4_audio_types[] = { - { CODEC_ID_MP3ON4, AOT_PS }, /* old mp3on4 draft */ - { CODEC_ID_MP3ON4, AOT_L1 }, /* layer 1 */ - { CODEC_ID_MP3ON4, AOT_L2 }, /* layer 2 */ - { CODEC_ID_MP3ON4, AOT_L3 }, /* layer 3 */ - { CODEC_ID_MP4ALS, AOT_ALS }, /* MPEG-4 ALS */ - { CODEC_ID_NONE, AOT_NULL }, -}; - int ff_mov_read_esds(AVFormatContext *fc, ByteIOContext *pb, MOVAtom atom) { AVStream *st; @@ -507,55 +470,16 @@ int ff_mov_read_esds(AVFormatContext *fc, ByteIOContext *pb, MOVAtom atom) st = fc->streams[fc->nb_streams-1]; get_be32(pb); /* version + flags */ - len = mp4_read_descr(fc, pb, &tag); + len = ff_mp4_read_descr(fc, pb, &tag); if (tag == MP4ESDescrTag) { get_be16(pb); /* ID */ get_byte(pb); /* priority */ } else get_be16(pb); /* ID */ - len = mp4_read_descr(fc, pb, &tag); - if (tag == MP4DecConfigDescrTag) { - int object_type_id = get_byte(pb); - get_byte(pb); /* stream type */ - get_be24(pb); /* buffer size db */ - get_be32(pb); /* max bitrate */ - get_be32(pb); /* avg bitrate */ - - st->codec->codec_id= ff_codec_get_id(ff_mp4_obj_type, object_type_id); - dprintf(fc, "esds object type id 0x%02x\n", object_type_id); - len = mp4_read_descr(fc, pb, &tag); - if (tag == MP4DecSpecificDescrTag) { - dprintf(fc, "Specific MPEG4 header len=%d\n", len); - if((uint64_t)len > (1<<30)) - return -1; - av_free(st->codec->extradata); - st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) - return AVERROR(ENOMEM); - get_buffer(pb, st->codec->extradata, len); - st->codec->extradata_size = len; - if (st->codec->codec_id == CODEC_ID_AAC) { - MPEG4AudioConfig cfg; - ff_mpeg4audio_get_config(&cfg, st->codec->extradata, - st->codec->extradata_size); - st->codec->channels = cfg.channels; - if (cfg.object_type == 29 && cfg.sampling_index < 3) // old mp3on4 - st->codec->sample_rate = ff_mpa_freq_tab[cfg.sampling_index]; - else if (cfg.ext_sample_rate) - st->codec->sample_rate = cfg.ext_sample_rate; - else - st->codec->sample_rate = cfg.sample_rate; - dprintf(fc, "mp4a config channels %d obj %d ext obj %d " - "sample rate %d ext sample rate %d\n", st->codec->channels, - cfg.object_type, cfg.ext_object_type, - cfg.sample_rate, cfg.ext_sample_rate); - if (!(st->codec->codec_id = ff_codec_get_id(mp4_audio_types, - cfg.object_type))) - st->codec->codec_id = CODEC_ID_AAC; - } - } - } + len = ff_mp4_read_descr(fc, pb, &tag); + if (tag == MP4DecConfigDescrTag) + ff_mp4_read_dec_config_descr(fc, st, pb); return 0; } diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index 64f76044a6..bceef6f210 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -30,6 +30,7 @@ #include "mpegts.h" #include "internal.h" #include "seek.h" +#include "isom.h" /* 1.0 second at 24Mbit/s */ #define MAX_SCAN_PACKETS 32000 @@ -852,6 +853,42 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid) return pes; } +static int mp4_read_iods(AVFormatContext *s, uint8_t *buf, unsigned size, + uint16_t *es_id, uint8_t **dec_config_descr, + int *dec_config_descr_size) +{ + ByteIOContext pb; + int tag; + unsigned len; + + init_put_byte(&pb, buf, size, 0, NULL, NULL, NULL, NULL); + + len = ff_mp4_read_descr(s, &pb, &tag); + if (tag == MP4IODescrTag) { + get_be16(&pb); // ID + get_byte(&pb); + get_byte(&pb); + get_byte(&pb); + get_byte(&pb); + get_byte(&pb); + len = ff_mp4_read_descr(s, &pb, &tag); + if (tag == MP4ESDescrTag) { + *es_id = get_be16(&pb); /* ES_ID */ + dprintf(s, "ES_ID %#x\n", *es_id); + get_byte(&pb); /* priority */ + len = ff_mp4_read_descr(s, &pb, &tag); + if (tag == MP4DecConfigDescrTag) { + *dec_config_descr = av_malloc(len); + if (!*dec_config_descr) + return AVERROR(ENOMEM); + *dec_config_descr_size = len; + get_buffer(&pb, *dec_config_descr, len); + } + } + } + return 0; +} + static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) { MpegTSContext *ts = filter->u.section_filter.opaque; @@ -863,6 +900,9 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len int desc_list_len, desc_len, desc_tag; char language[4]; uint32_t prog_reg_desc = 0; /* registration descriptor */ + uint8_t *mp4_dec_config_descr = NULL; + int mp4_dec_config_descr_len = 0; + int mp4_es_id = 0; #ifdef DEBUG dprintf(ts->stream, "PMT: len %i\n", section_len); @@ -895,11 +935,20 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len uint8_t tag, len; tag = get8(&p, p_end); len = get8(&p, p_end); + + dprintf(ts->stream, "program tag: 0x%02x len=%d\n", tag, len); + if(len > program_info_length - 2) //something else is broken, exit the program_descriptors_loop break; program_info_length -= len + 2; - if(tag == 0x05 && len >= 4) { // registration descriptor + if (tag == 0x1d) { // IOD descriptor + get8(&p, p_end); // scope + get8(&p, p_end); // label + len -= 2; + mp4_read_iods(ts->stream, p, len, &mp4_es_id, + &mp4_dec_config_descr, &mp4_dec_config_descr_len); + } else if (tag == 0x05 && len >= 4) { // registration descriptor prog_reg_desc = bytestream_get_le32(&p); len -= 4; } @@ -968,6 +1017,19 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len mpegts_find_stream_type(st, desc_tag, DESC_types); switch(desc_tag) { + case 0x1F: /* FMC descriptor */ + get16(&p, desc_end); + if (st->codec->codec_id == CODEC_ID_AAC_LATM && + mp4_dec_config_descr_len && mp4_es_id == pid) { + ByteIOContext pb; + init_put_byte(&pb, mp4_dec_config_descr, + mp4_dec_config_descr_len, 0, NULL, NULL, NULL, NULL); + ff_mp4_read_dec_config_descr(ts->stream, st, &pb); + if (st->codec->codec_id == CODEC_ID_AAC && + st->codec->extradata_size > 0) + st->need_parsing = 0; + } + break; case 0x56: /* DVB teletext descriptor */ language[0] = get8(&p, desc_end); language[1] = get8(&p, desc_end);