[vlc-commits] packetizer: mpeg4audio: rework

Francois Cartegnie git at videolan.org
Wed Feb 22 13:58:09 CET 2017


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Wed Feb 22 11:33:42 2017 +0100| [01ef9d34cfc3265ec243549b50f31e5112c2db5d] | committer: Francois Cartegnie

packetizer: mpeg4audio: rework

Too much confusion dealing raw AAC, multiplexing, and random cases
lead to multiple issues.

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

 modules/packetizer/mpeg4audio.c | 203 ++++++++++++++++++++++------------------
 1 file changed, 114 insertions(+), 89 deletions(-)

diff --git a/modules/packetizer/mpeg4audio.c b/modules/packetizer/mpeg4audio.c
index d231ea2..2e947e3 100644
--- a/modules/packetizer/mpeg4audio.c
+++ b/modules/packetizer/mpeg4audio.c
@@ -157,8 +157,9 @@ enum
     } while(0)
 
 enum {
-    TYPE_NONE,
-    TYPE_RAW,
+    TYPE_UNKNOWN, /* AAC samples with[out] headers */
+    TYPE_UNKNOWN_NONRAW, /* [un]packetized ADTS or LOAS */
+    TYPE_RAW,    /* RAW AAC frames */
     TYPE_ADTS,
     TYPE_LOAS
 };
@@ -178,10 +179,8 @@ static const int pi_sample_rates[16] =
 static int  OpenPacketizer(vlc_object_t *);
 static void ClosePacketizer(vlc_object_t *);
 
-static block_t *PacketizeRawBlock    (decoder_t *, block_t **);
-static void     FlushRawBlock( decoder_t * );
-static block_t *PacketizeStreamBlock(decoder_t *, block_t **);
-static void     FlushStreamBlock( decoder_t * );
+static block_t *Packetize    (decoder_t *, block_t **);
+static void     Flush( decoder_t * );
 
 /*****************************************************************************
  * Module descriptor
@@ -223,6 +222,18 @@ static int OpenPacketizer(vlc_object_t *p_this)
 
     msg_Dbg(p_dec, "running MPEG4 audio packetizer");
 
+    /*
+     * We need to handle 3 cases.
+     * Case 1 : RAW AAC samples without sync header
+     *          The demuxer shouldn't need packetizer, see next case.
+     * Case 2 : AAC samples with ADTS or LOAS/LATM header
+     *          Some mux (avi) can't distinguish the both
+     *          cases above, and then forwards to packetizer
+     *          which should check for header and rewire to case below
+     * Case 3 : Non packetized ADTS or LOAS/LATM
+     *          The demuxer needs to set original_codec for hardwiring
+     */
+
     switch (p_dec->fmt_in.i_original_fourcc)
     {
         case VLC_FOURCC('L','A','T','M'):
@@ -235,19 +246,20 @@ static int OpenPacketizer(vlc_object_t *p_this)
             msg_Dbg(p_dec, "ADTS Mode");
             break;
 
+        case VLC_FOURCC('H','E','A','D'):
+            p_sys->i_type = TYPE_UNKNOWN_NONRAW;
+            break;
+
         default:
-            if (p_dec->fmt_in.i_extra > 1)
-            {
-                msg_Dbg(p_dec, "RAW AAC Mode");
-                p_sys->i_type = TYPE_RAW;
-            } else {
-                p_sys->i_type = TYPE_NONE;
-                msg_Dbg(p_dec, "no decoder specific info, must be an ADTS or LOAS stream");
-            }
+            p_sys->i_type = TYPE_UNKNOWN;
             break;
     }
 
-    if(p_sys->i_type == TYPE_RAW)
+    /* Some mux (avi) do send RAW AAC without extradata,
+       and LATM can be sent with out-of-band audioconfig,
+       (avformat sets m4a extradata in both cases)
+       so we can't rely on extradata to guess multiplexing */
+    if(p_sys->i_type == TYPE_UNKNOWN && p_dec->fmt_in.i_extra > 1)
     {
         uint8_t *p_config = (uint8_t*)p_dec->fmt_in.p_extra;
         int     i_index;
@@ -267,12 +279,11 @@ static int OpenPacketizer(vlc_object_t *p_this)
             p_dec->fmt_out.audio.i_channels = (p_config[4] >> 3) & 0x0f;
         }
 
+        /* This is not 100% guaranteed (overriden by ext) */
         msg_Dbg(p_dec, "AAC %dHz %d samples/frame",
                  p_dec->fmt_out.audio.i_rate,
                  p_dec->fmt_out.audio.i_frame_length);
 
-        date_Init(&p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1);
-
         p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
         p_dec->fmt_out.p_extra = malloc(p_dec->fmt_in.i_extra);
         if (!p_dec->fmt_out.p_extra) {
@@ -281,24 +292,22 @@ static int OpenPacketizer(vlc_object_t *p_this)
         }
         memcpy(p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra,
                 p_dec->fmt_in.i_extra);
-
-        /* Set callbacks */
-        p_dec->pf_packetize = PacketizeRawBlock;
-        p_dec->pf_flush = FlushRawBlock;
     }
     else
     {
-        date_Init(&p_sys->end_date, p_dec->fmt_in.audio.i_rate, 1);
+        p_dec->fmt_out.audio.i_rate = p_dec->fmt_in.audio.i_rate;
 
         /* We will try to create a AAC Config from adts/loas */
         p_dec->fmt_out.i_extra = 0;
         p_dec->fmt_out.p_extra = NULL;
-
-        /* Set callbacks */
-        p_dec->pf_packetize = PacketizeStreamBlock;
-        p_dec->pf_flush = FlushStreamBlock;
     }
 
+    date_Init(&p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1);
+
+    /* Set callbacks */
+    p_dec->pf_packetize = Packetize;
+    p_dec->pf_flush = Flush;
+
     return VLC_SUCCESS;
 }
 
@@ -314,22 +323,12 @@ static void ClosePacketizer(vlc_object_t *p_this)
     free(p_sys);
 }
 
-/*****************************************************************************
- * FlushRawBlock:
- *****************************************************************************/
-static void FlushRawBlock(decoder_t *p_dec)
-{
-    decoder_sys_t *p_sys = p_dec->p_sys;
-    p_sys->b_discontuinity = true;
-    date_Set(&p_sys->end_date, 0);
-}
-
 /****************************************************************************
- * PacketizeRawBlock: the whole thing
+ * ForwardRawBlock:
  ****************************************************************************
  * This function must be fed with complete frames.
  ****************************************************************************/
-static block_t *PacketizeRawBlock(decoder_t *p_dec, block_t **pp_block)
+static block_t *ForwardRawBlock(decoder_t *p_dec, block_t **pp_block)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_block;
@@ -340,38 +339,21 @@ static block_t *PacketizeRawBlock(decoder_t *p_dec, block_t **pp_block)
     p_block = *pp_block;
     *pp_block = NULL; /* Don't reuse this block */
 
-    if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED))
+    if (p_block->i_pts > VLC_TS_INVALID &&
+        p_block->i_pts != date_Get(&p_sys->end_date))
     {
-        FlushRawBlock(p_dec);
-        if (p_block->i_flags&(BLOCK_FLAG_CORRUPTED))
-        {
-            block_Release(p_block);
-            return NULL;
-        }
-    }
-
-
-    if (!date_Get(&p_sys->end_date) && p_block->i_pts <= VLC_TS_INVALID) {
-        /* We've just started the stream, wait for the first PTS. */
-        block_Release(p_block);
-        return NULL;
-    } else if (p_block->i_pts > VLC_TS_INVALID &&
-             p_block->i_pts != date_Get(&p_sys->end_date)) {
-        if(date_Get(&p_sys->end_date) > 0)
+        if(date_Get(&p_sys->end_date) > VLC_TS_INVALID)
             p_sys->b_discontuinity = true;
         date_Set(&p_sys->end_date, p_block->i_pts);
     }
 
     p_block->i_pts = p_block->i_dts = date_Get(&p_sys->end_date);
 
-    p_block->i_length = date_Increment(&p_sys->end_date,
-        p_dec->fmt_out.audio.i_frame_length) - p_block->i_pts;
-
-    if(p_sys->b_discontuinity)
-    {
-        p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
-        p_sys->b_discontuinity = false;
-    }
+    /* Might not be known due to missing extradata,
+       will be set to block pts above */
+    if(p_dec->fmt_out.audio.i_frame_length)
+        p_block->i_length = date_Increment(&p_sys->end_date,
+            p_dec->fmt_out.audio.i_frame_length) - p_block->i_pts;
 
     return p_block;
 }
@@ -983,7 +965,7 @@ static void SetupOutput(decoder_t *p_dec, block_t *p_block)
 /*****************************************************************************
  * FlushStreamBlock:
  *****************************************************************************/
-static void FlushStreamBlock(decoder_t *p_dec)
+static void Flush(decoder_t *p_dec)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
@@ -1007,27 +989,8 @@ static block_t *PacketizeStreamBlock(decoder_t *p_dec, block_t **pp_block)
 
     if(p_block)
     {
-        if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED)) {
-            /* First always drain complete blocks before discontinuity */
-            block_t *p_drain = PacketizeStreamBlock(p_dec, NULL);
-            if(p_drain)
-                return p_drain;
-
-            FlushStreamBlock(p_dec);
-
-            if (p_block->i_flags & BLOCK_FLAG_CORRUPTED) {
-                block_Release(p_block);
-                return NULL;
-            }
-        }
-
-        if (!date_Get(&p_sys->end_date) && p_block->i_pts <= VLC_TS_INVALID) {
-            /* We've just started the stream, wait for the first PTS. */
-            block_Release(p_block);
-            return NULL;
-        }
-
         block_BytestreamPush(&p_sys->bytestream, p_block);
+        *pp_block = NULL;
     }
 
     for (;;) switch(p_sys->i_state) {
@@ -1181,14 +1144,76 @@ static block_t *PacketizeStreamBlock(decoder_t *p_dec, block_t **pp_block)
 
         p_sys->i_state = STATE_NOSYNC;
 
-        if(p_sys->b_discontuinity)
+        return p_out_buffer;
+    }
+
+    return NULL;
+}
+
+/****************************************************************************
+ * Packetize: just forwards raw blocks, or packetizes LOAS/ADTS
+ *            and strips headers
+ ****************************************************************************/
+static block_t *Packetize(decoder_t *p_dec, block_t **pp_block)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    block_t *p_block = pp_block ? *pp_block : NULL;
+
+    if(p_block)
+    {
+        if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
         {
-            p_out_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
-            p_sys->b_discontuinity = false;
+            if(p_sys->i_type == TYPE_ADTS || p_sys->i_type == TYPE_LOAS)
+            {
+                /* First always drain complete blocks before discontinuity */
+                block_t *p_drain = PacketizeStreamBlock(p_dec, NULL);
+                if(p_drain)
+                    return p_drain;
+            }
+
+            Flush(p_dec);
+
+            if (p_block->i_flags & BLOCK_FLAG_CORRUPTED)
+            {
+                block_Release(p_block);
+                return NULL;
+            }
         }
 
-        return p_out_buffer;
+        if (!date_Get(&p_sys->end_date) && p_block->i_pts <= VLC_TS_INVALID)
+        {
+            /* We've just started the stream, wait for the first PTS. */
+            block_Release(p_block);
+            return NULL;
+        }
     }
 
-    return NULL;
+    if(p_block && p_sys->i_type == TYPE_UNKNOWN)
+    {
+        p_sys->i_type = TYPE_RAW;
+        if(p_block->i_buffer > 1)
+        {
+            if(p_block->p_buffer[0] == 0xff && (p_block->p_buffer[1] & 0xf6) == 0xf0)
+            {
+                p_sys->i_type = TYPE_ADTS;
+            }
+            else if(p_block->p_buffer[0] == 0x56 && (p_block->p_buffer[1] & 0xe0) == 0xe0)
+            {
+                p_sys->i_type = TYPE_LOAS;
+            }
+        }
+    }
+
+    if(p_sys->i_type == TYPE_RAW)
+        p_block = ForwardRawBlock(p_dec, pp_block);
+    else
+        p_block = PacketizeStreamBlock(p_dec, pp_block);
+
+    if(p_block && p_sys->b_discontuinity)
+    {
+        p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+        p_sys->b_discontuinity = false;
+    }
+
+    return p_block;
 }



More information about the vlc-commits mailing list