In ts demuxer, support aac flexmux using extradata in iods, issue #2346
authorBaptiste Coudurier <baptiste.coudurier@gmail.com>
Tue, 23 Nov 2010 00:51:12 +0000 (00:51 +0000)
committerBaptiste Coudurier <baptiste.coudurier@gmail.com>
Tue, 23 Nov 2010 00:51:12 +0000 (00:51 +0000)
Originally committed as revision 25806 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavformat/Makefile
libavformat/isom.c
libavformat/isom.h
libavformat/mov.c
libavformat/mpegts.c

index 1f63fee..f615481 100644 (file)
@@ -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
index 34404ad..bf01401 100644 (file)
  * 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;
+}
index 6c6ad54..2990c9c 100644 (file)
@@ -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);
 
index cdaf6d3..1fc86ea 100644 (file)
@@ -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;
 }
 
index 64f7604..bceef6f 100644 (file)
@@ -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);