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

Thomas Guillem thomas at gllm.fr
Mon Jul 13 16:01:36 CEST 2015


SPS and PPS NAL units always start with "00 00 00 01" but others NAL units may
starts with "00 00 01".
---
 modules/packetizer/h264_nal.c | 91 +++++++++++++++++++++++++++----------------
 1 file changed, 57 insertions(+), 34 deletions(-)

diff --git a/modules/packetizer/h264_nal.c b/modules/packetizer/h264_nal.c
index a35f861..a867dc9 100644
--- a/modules/packetizer/h264_nal.c
+++ b/modules/packetizer/h264_nal.c
@@ -20,9 +20,10 @@
 
 #include "h264_nal.h"
 
+#include <assert.h>
 #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,
@@ -140,6 +141,15 @@ void convert_h264_to_annexb( uint8_t *p_buf, uint32_t i_len,
     }
 }
 
+static size_t get_spspps_size( uint8_t *p_start, uint8_t *p_end )
+{
+    /* cf B.1.1: don't count trailing_zero_8bits */
+
+    while( *p_end == 0 && p_end > p_start )
+        p_end--;
+    return p_end - p_start + 1;
+}
+
 int h264_get_spspps( uint8_t *p_buf, size_t i_buf,
                      uint8_t **pp_sps, size_t *p_sps_size,
                      uint8_t **pp_pps, size_t *p_pps_size )
@@ -148,57 +158,70 @@ int h264_get_spspps( uint8_t *p_buf, size_t i_buf,
     size_t i_sps_size = 0, i_pps_size = 0;
     int i_nal_type = NAL_UNKNOWN;
 
-    if (unlikely(p_buf == NULL || i_buf == 0))
-        return -1;
+    assert( p_buf );
 
-    while( true )
+    while( i_buf > 0 )
     {
-        int i_inc = 0;
-
-        if( i_buf > 5 && memcmp( p_buf, annexb_startcode, 4 ) == 0 )
+        /* SPS and PPS NAL units always start with "00 00 00 01" but other NAL
+         * units may start with "00 00 01". */
+        if( i_buf > 5 && memcmp( p_buf + 1, annexb_startcode, 3 ) == 0 )
         {
             i_nal_type = p_buf[4] & 0x1F;
 
-            /* size of startcode + nal_type */
-            i_inc = 5;
+            /* The start prefix is always "00 00 00 01" for SPS and PPS */
+            if( ( i_nal_type == NAL_SPS || i_nal_type == NAL_PPS )
+             && p_buf[0] != 0 )
+                return -1;
 
             /* 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;
-        }
 
-        /* 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;
+            /* 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 )
-            i_sps_size = p_buf - p_sps;
-        if( !i_pps_size && p_pps && i_nal_type != NAL_PPS )
-            i_pps_size = p_buf - p_pps;
+            /* 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 )
+                i_sps_size = get_spspps_size( p_sps, p_buf );
+            if( !i_pps_size && p_pps && i_nal_type != NAL_PPS )
+                i_pps_size = get_spspps_size( p_pps, p_buf );
 
-        /* SPS/PPS are before the slices */
-        if (i_nal_type >= NAL_SLICE && i_nal_type <= NAL_SLICE_IDR )
-            break;
+            /* Found a SPS and a PPS */
+            if( i_sps_size && i_pps_size )
+                break;
 
-        i_buf -= i_inc;
-        p_buf += i_inc;
+            /* SPS/PPS are before the slices */
+            if ( i_nal_type >= NAL_SLICE && i_nal_type <= NAL_SLICE_IDR )
+                break;
 
-        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;
+            /* size of startcode + nal_type */
+            i_buf -= 5;
+            p_buf += 5;
+        } else {
+            /* cf B.1: Don't abort if there are leading_zero_8bits (only for
+             * the first NAL unit of the bytestream). */
+            if( i_nal_type == NAL_UNKNOWN && p_buf[0] != 0 )
+                return -1;
+
+            i_buf--;
+            p_buf++;
         }
     }
+
+    if( i_buf == 0 )
+    {
+        /* update SPS/PPS size if we reach the end of the bytestream */
+        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;
+    }
+
     if( ( !p_sps || !i_sps_size ) && ( !p_pps || !i_pps_size ) )
         return -1;
     *pp_sps = p_sps;
-- 
2.1.4




More information about the vlc-devel mailing list