[vlc-commits] mp4 mux: write dac3 and dec3 boxes for (e)ac-3

Rafaël Carré git at videolan.org
Wed Sep 3 13:15:58 CEST 2014


vlc | branch: master | Rafaël Carré <funman at videolan.org> | Wed Sep  3 13:06:12 2014 +0200| [511da6e3ab3bca54af84ac227041bf4ceba3e15f] | committer: Rafaël Carré

mp4 mux: write dac3 and dec3 boxes for (e)ac-3

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=511da6e3ab3bca54af84ac227041bf4ceba3e15f
---

 modules/mux/mp4.c |  201 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 196 insertions(+), 5 deletions(-)

diff --git a/modules/mux/mp4.c b/modules/mux/mp4.c
index 622efbc..31624ec 100644
--- a/modules/mux/mp4.c
+++ b/modules/mux/mp4.c
@@ -152,6 +152,9 @@ typedef struct
     mtime_t      i_starttime; /* the really first packet */
     bool         b_hasbframes;
 
+    /* XXX: needed for other codecs too, see lavf */
+    block_t      *a52_frame;
+
     /* for later stco fix-up (fast start files) */
     uint64_t i_stco_pos;
     bool b_stco64;
@@ -391,6 +394,8 @@ static void Close(vlc_object_t *p_this)
         mp4_stream_t *p_stream = p_sys->pp_streams[i_trak];
 
         es_format_Clean(&p_stream->fmt);
+        if (p_stream->a52_frame)
+            block_Release(p_stream->a52_frame);
         free(p_stream->entry);
         free(p_stream);
     }
@@ -435,6 +440,8 @@ static int AddStream(sout_mux_t *p_mux, sout_input_t *p_input)
 
     switch(p_input->p_fmt->i_codec)
     {
+    case VLC_CODEC_A52:
+    case VLC_CODEC_EAC3:
     case VLC_CODEC_MP4A:
     case VLC_CODEC_MP4V:
     case VLC_CODEC_MPGA:
@@ -474,6 +481,7 @@ static int AddStream(sout_mux_t *p_mux, sout_input_t *p_input)
         calloc(p_stream->i_entry_max, sizeof(mp4_entry_t));
     p_stream->i_dts_start   = 0;
     p_stream->i_read_duration    = 0;
+    p_stream->a52_frame = NULL;
     switch( p_stream->fmt.i_cat )
     {
     case AUDIO_ES:
@@ -551,6 +559,11 @@ static int Mux(sout_mux_t *p_mux)
                 p_data = ConvertFromAnnexB(p_data);
             else if (p_stream->fmt.i_codec == VLC_CODEC_SUBT)
                 p_data = ConvertSUBT(p_data);
+            else if (p_stream->fmt.i_codec == VLC_CODEC_A52 ||
+                     p_stream->fmt.i_codec == VLC_CODEC_EAC3) {
+                if (p_stream->a52_frame == NULL && p_data->i_buffer >= 8)
+                    p_stream->a52_frame = block_Duplicate(p_data);
+            }
         } while (!p_data);
 
         /* Reset reference dts in case of discontinuity (ex: gather sout) */
@@ -870,6 +883,174 @@ static bo_t *GetWaveTag(mp4_stream_t *p_stream)
     return wave;
 }
 
+static bo_t *GetDec3Tag(mp4_stream_t *p_stream)
+{
+    if (!p_stream->a52_frame)
+        return NULL;
+
+    bs_t s;
+    bs_init(&s, p_stream->a52_frame->p_buffer, sizeof(p_stream->a52_frame->i_buffer));
+    bs_skip(&s, 16); // syncword
+
+    uint8_t fscod, bsid, bsmod, acmod, lfeon, strmtyp;
+
+    bsmod = 0;
+
+    strmtyp = bs_read(&s, 2);
+
+    if (strmtyp & 0x1) // dependant or reserved stream
+        return NULL;
+
+    if (bs_read(&s, 3) != 0x0) // substreamid: we don't support more than 1 stream
+        return NULL;
+
+    int numblkscod;
+    bs_skip(&s, 11); // frmsizecod
+    fscod = bs_read(&s, 2);
+    if (fscod == 0x03) {
+        bs_skip(&s, 2); // fscod2
+        numblkscod = 3;
+    } else {
+        numblkscod = bs_read(&s, 2);
+    }
+
+    acmod = bs_read(&s, 3);
+    lfeon = bs_read1(&s);
+
+    bsid = bs_read(&s, 5);
+
+    bs_skip(&s, 5); // dialnorm
+    if (bs_read1(&s)) // compre
+        bs_skip(&s, 5); // compr
+
+    if (acmod == 0) {
+        bs_skip(&s, 5); // dialnorm2
+        if (bs_read1(&s)) // compr2e
+            bs_skip(&s, 8); // compr2
+    }
+
+    if (strmtyp == 0x1) // dependant stream XXX: unsupported
+        if (bs_read1(&s)) // chanmape
+            bs_skip(&s, 16); // chanmap
+
+    /* we have to skip mixing info to read bsmod */
+    if (bs_read1(&s)) { // mixmdate
+        if (acmod > 0x2) // 2+ channels
+            bs_skip(&s, 2); // dmixmod
+        if ((acmod & 0x1) && (acmod > 0x2)) // 3 front channels
+            bs_skip(&s, 3 + 3); // ltrtcmixlev + lorocmixlev
+        if (acmod & 0x4) // surround channel
+            bs_skip(&s, 3 + 3); // ltrsurmixlev + lorosurmixlev
+        if (lfeon)
+            if (bs_read1(&s))
+                bs_skip(&s, 5); // lfemixlevcod
+        if (strmtyp == 0) { // independant stream
+            if (bs_read1(&s)) // pgmscle
+                bs_skip(&s, 6); // pgmscl
+            if (acmod == 0x0) // dual mono
+                if (bs_read1(&s)) // pgmscl2e
+                    bs_skip(&s, 6); // pgmscl2
+            if (bs_read1(&s)) // extpgmscle
+                bs_skip(&s, 6); // extpgmscl
+            uint8_t mixdef = bs_read(&s, 2);
+            if (mixdef == 0x1)
+                bs_skip(&s, 5);
+            else if (mixdef == 0x2)
+                bs_skip(&s, 12);
+            else if (mixdef == 0x3) {
+                uint8_t mixdeflen = bs_read(&s, 5);
+                bs_skip(&s, 8 * (mixdeflen + 2));
+            }
+            if (acmod < 0x2) { // mono or dual mono
+                if (bs_read1(&s)) // paninfoe
+                    bs_skip(&s, 14); // paninfo
+                if (acmod == 0) // dual mono
+                    if (bs_read1(&s)) // paninfo2e
+                        bs_skip(&s, 14); // paninfo2
+            }
+            if (bs_read1(&s)) { // frmmixcfginfoe
+                static const int blocks[4] = { 1, 2, 3, 6 };
+                int number_of_blocks = blocks[numblkscod];
+                if (number_of_blocks == 1)
+                    bs_skip(&s, 5); // blkmixcfginfo[0]
+                else for (int i = 0; i < number_of_blocks; i++)
+                    if (bs_read1(&s)) // blkmixcfginfoe
+                        bs_skip(&s, 5); // blkmixcfginfo[i]
+            }
+        }
+    }
+
+    if (bs_read1(&s)) // infomdate
+        bsmod = bs_read(&s, 3);
+
+    uint8_t mp4_eac3_header[5];
+    bs_init(&s, mp4_eac3_header, sizeof(mp4_eac3_header));
+
+    int data_rate = p_stream->fmt.i_bitrate / 1000;
+    bs_write(&s, 13, data_rate);
+    bs_write(&s, 3, 0); // num_ind_sub - 1
+    bs_write(&s, 2, fscod);
+    bs_write(&s, 5, bsid);
+    bs_write(&s, 5, bsmod);
+    bs_write(&s, 3, acmod);
+    bs_write(&s, 1, lfeon);
+    bs_write(&s, 3, 0); // reserved
+    bs_write(&s, 4, 0); // num_dep_sub
+    bs_write(&s, 1, 0); // reserved
+
+    bo_t *dec3 = box_new("dec3");
+
+    bo_add_mem(dec3, sizeof(mp4_eac3_header), mp4_eac3_header);
+
+    return dec3;
+}
+
+static bo_t *GetDac3Tag(mp4_stream_t *p_stream)
+{
+    if (!p_stream->a52_frame)
+        return NULL;
+
+    bo_t *dac3 = box_new("dac3");
+
+    bs_t s;
+    bs_init(&s, p_stream->a52_frame->p_buffer, sizeof(p_stream->a52_frame->i_buffer));
+
+    uint8_t fscod, bsid, bsmod, acmod, lfeon, frmsizecod;
+
+    bs_skip(&s, 16 + 16); // syncword + crc
+
+    fscod = bs_read(&s, 2);
+    frmsizecod = bs_read(&s, 6);
+    bsid = bs_read(&s, 5);
+    bsmod = bs_read(&s, 3);
+    acmod = bs_read(&s, 3);
+    if (acmod == 2)
+        bs_skip(&s, 2); // dsurmod
+    else {
+        if ((acmod & 1) && acmod != 1)
+            bs_skip(&s, 2); // cmixlev
+        if (acmod & 4)
+            bs_skip(&s, 2); // surmixlev
+    }
+
+    lfeon = bs_read1(&s);
+
+    uint8_t mp4_a52_header[3];
+    bs_init(&s, mp4_a52_header, sizeof(mp4_a52_header));
+
+    bs_write(&s, 2, fscod);
+    bs_write(&s, 5, bsid);
+    bs_write(&s, 3, bsmod);
+    bs_write(&s, 3, acmod);
+    bs_write(&s, 1, lfeon);
+    bs_write(&s, 5, frmsizecod >> 1); // bit_rate_code
+    bs_write(&s, 5, 0); // reserved
+
+    bo_add_mem(dac3, sizeof(mp4_a52_header), mp4_a52_header);
+
+    return dac3;
+}
+
 static bo_t *GetDamrTag(mp4_stream_t *p_stream)
 {
     bo_t *damr;
@@ -1151,7 +1332,7 @@ static bo_t *GetAvcCTag(mp4_stream_t *p_stream)
             }
             const int i_nal_type = p_buffer[3]&0x1f;
             int i_startcode = 0;
- 
+
             for (int i_offset = 1; i_offset+2 < i_buffer ; i_offset++)
                 if (!memcmp(&p_buffer[i_offset], &avc1_start_code[1], 3)) {
                     /* we found another startcode */
@@ -1175,7 +1356,7 @@ static bo_t *GetAvcCTag(mp4_stream_t *p_stream)
             p_buffer += i_size;
         }
     }
- 
+
     /* FIXME use better value */
     avcC = box_new("avcC");
     bo_add_8(avcC, 1);      /* configuration version */
@@ -1296,7 +1477,6 @@ static bo_t *GetSounBox(sout_mux_t *p_mux, mp4_stream_t *p_stream)
     bool b_descr = true;
     vlc_fourcc_t codec = p_stream->fmt.i_codec;
     char fcc[4];
-    vlc_fourcc_to_char(codec, fcc);
 
     if (codec == VLC_CODEC_MPGA) {
         if (p_sys->b_mov) {
@@ -1304,7 +1484,12 @@ static bo_t *GetSounBox(sout_mux_t *p_mux, mp4_stream_t *p_stream)
             memcpy(fcc, ".mp3", 4);
         } else
             memcpy(fcc, "mp4a", 4);
-    }
+    } else if (codec == VLC_CODEC_A52) {
+        memcpy(fcc, "ac-3", 4);
+    } else if (codec == VLC_CODEC_EAC3) {
+        memcpy(fcc, "ec-3", 4);
+    } else
+        vlc_fourcc_to_char(codec, fcc);
 
     bo_t *soun = box_new(fcc);
     for (int i = 0; i < 6; i++)
@@ -1346,9 +1531,15 @@ static bo_t *GetSounBox(sout_mux_t *p_mux, mp4_stream_t *p_stream)
             box = GetWaveTag(p_stream);
         else if (codec == VLC_CODEC_AMR_NB)
             box = GetDamrTag(p_stream);
+        else if (codec == VLC_CODEC_A52)
+            box = GetDac3Tag(p_stream);
+        else if (codec == VLC_CODEC_EAC3)
+            box = GetDec3Tag(p_stream);
         else
             box = GetESDS(p_stream);
-        box_gather(soun, box);
+
+        if (box)
+            box_gather(soun, box);
     }
 
     return soun;



More information about the vlc-commits mailing list