[vlc-devel] [PATCH] h264_nal: fix parsing of the end of SPS and PPS NAL units

Thomas Guillem thomas at gllm.fr
Thu Jul 23 19:15:03 CEST 2015


SPS and PPS NAL units always start with 0x00000001 and finish with 0x000000,
0x000001 or the end of the bytestream.
---
 modules/packetizer/h264_nal.c | 110 +++++++++++++++++++++++++-----------------
 1 file changed, 66 insertions(+), 44 deletions(-)

diff --git a/modules/packetizer/h264_nal.c b/modules/packetizer/h264_nal.c
index a35f861..a894763 100644
--- a/modules/packetizer/h264_nal.c
+++ b/modules/packetizer/h264_nal.c
@@ -22,7 +22,7 @@
 
 #include <limits.h>
 
-static const uint8_t annexb_startcode[] = { 0x00, 0x00, 0x00, 0x01 };
+static const uint8_t annexb_startcode[] = { 0x00, 0x00, 0x01 };
 
 int convert_sps_pps( decoder_t *p_dec, const uint8_t *p_buf,
                      uint32_t i_buf_size, uint8_t *p_out_buf,
@@ -147,57 +147,79 @@ int h264_get_spspps( uint8_t *p_buf, size_t i_buf,
     uint8_t *p_sps = NULL, *p_pps = NULL;
     size_t i_sps_size = 0, i_pps_size = 0;
     int i_nal_type = NAL_UNKNOWN;
+    bool b_first_nal = true;
+    bool b_has_zero_byte = false;
 
-    if (unlikely(p_buf == NULL || i_buf == 0))
-        return -1;
-
-    while( true )
+    while( i_buf > 0 )
     {
-        int i_inc = 0;
+        unsigned int i_move = 1;
 
-        if( i_buf > 5 && memcmp( p_buf, annexb_startcode, 4 ) == 0 )
+        if( i_nal_type == NAL_UNKNOWN )
         {
-            i_nal_type = p_buf[4] & 0x1F;
-
-            /* size of startcode + nal_type */
-            i_inc = 5;
-
-            /* pointer to the beginning of the sps/pps  */
-            if( i_nal_type == NAL_SPS && !p_sps )
-                p_sps = p_buf;
-            if( i_nal_type == NAL_PPS && !p_pps )
-                p_pps = p_buf;
-        } else {
-            i_inc = 1;
+            if( i_buf > 4 && !memcmp( p_buf, annexb_startcode, 3 ) )
+            {
+                i_nal_type = p_buf[3] & 0x1F;
+                i_move = 4;
+
+                /* The start prefix is always 0x00000001 (annexb_startcode + a
+                 * leading zero byte) for SPS, PPS or the first NAL */
+                if( !b_has_zero_byte && ( b_first_nal || i_nal_type == NAL_SPS
+                 || i_nal_type == NAL_PPS ) )
+                    return -1;
+                b_first_nal = false;
+
+                /* Pointer to the beginning of the SPS/PPS starting with the
+                 * leading zero byte */
+                if( i_nal_type == NAL_SPS && !p_sps )
+                    p_sps = p_buf - 1;
+                if( i_nal_type == NAL_PPS && !p_pps )
+                    p_pps = p_buf - 1;
+
+                /* cf. 7.4.1.2.3 */
+                if( i_nal_type > 18 || ( i_nal_type >= 10 && i_nal_type <= 12 ) )
+                    return -1;
+
+                /* SPS/PPS are before the slices */
+                if ( i_nal_type >= NAL_SLICE && i_nal_type <= NAL_SLICE_IDR )
+                    break;
+
+            } else if( b_first_nal && p_buf[0] != 0 )
+            {
+                /* leading_zero_8bits only before the first NAL */
+                return -1;
+            }
         }
+        else
+        {
+            /* cf B.3-3: a NAL unit ends with 0x000000, 0x000001 or with the
+             * end of the bytestream */
+            if( i_buf > 3 && p_buf[0] == 0 && p_buf[1] == 0
+             && ( p_buf[2] == 0 || p_buf[2] == 1 ) )
+            {
+                /* update SPS/PPS size */
+                if( i_nal_type == NAL_SPS )
+                    i_sps_size = p_buf - p_sps;
+                if( i_nal_type == NAL_PPS )
+                    i_pps_size = p_buf - p_pps;
+
+                if( i_sps_size && i_pps_size )
+                    break;
+                i_nal_type = NAL_UNKNOWN;
+                i_move = 0;
+            }
+        }
+        b_has_zero_byte = *p_buf == 0;
+        i_buf -= i_move;
+        p_buf += i_move;
+    }
 
-        /* cf. 7.4.1.2.3 */
-        if( i_nal_type == NAL_UNKNOWN || i_nal_type > 18
-         || (i_nal_type >= 10 && i_nal_type <= 12))
-            return -1;
-
-        /* update SPS/PPS size if the new NAL is different than the last one */
-        if( !i_sps_size && p_sps && i_nal_type != NAL_SPS )
+    if( i_buf == 0 )
+    {
+        /* update SPS/PPS size if we reach the end of the bytestream */
+        if( !i_sps_size && i_nal_type == NAL_SPS )
             i_sps_size = p_buf - p_sps;
-        if( !i_pps_size && p_pps && i_nal_type != NAL_PPS )
+        if( !i_pps_size && i_nal_type == NAL_PPS )
             i_pps_size = p_buf - p_pps;
-
-        /* SPS/PPS are before the slices */
-        if (i_nal_type >= NAL_SLICE && i_nal_type <= NAL_SLICE_IDR )
-            break;
-
-        i_buf -= i_inc;
-        p_buf += i_inc;
-
-        if( i_buf == 0 )
-        {
-            /* update SPS/PPS size if we reach the end of the buffer */
-            if( !i_sps_size && p_sps )
-                i_sps_size = p_buf - p_sps;
-            if( !i_pps_size && p_pps )
-                i_pps_size = p_buf - p_pps;
-            break;
-        }
     }
     if( ( !p_sps || !i_sps_size ) && ( !p_pps || !i_pps_size ) )
         return -1;
-- 
2.1.4




More information about the vlc-devel mailing list