[vlc-devel] [RFC PATCH 4/7] packetizer h264: refactor and expose sps/pps parsing

Thomas Guillem thomas at gllm.fr
Thu Apr 23 19:30:52 CEST 2015


The goal is to expose h264_parse_sps and h264_parse_pps functions that can be
used from decoders.
---
 modules/packetizer/h264.c     | 306 +++++-------------------------------------
 modules/packetizer/h264_nal.c | 275 +++++++++++++++++++++++++++++++++++++
 modules/packetizer/h264_nal.h |  58 ++++++++
 3 files changed, 369 insertions(+), 270 deletions(-)

diff --git a/modules/packetizer/h264.c b/modules/packetizer/h264.c
index 778b439..f82168c 100644
--- a/modules/packetizer/h264.c
+++ b/modules/packetizer/h264.c
@@ -84,8 +84,6 @@ typedef struct
     int i_delta_pic_order_cnt1;
 } slice_t;
 
-#define SPS_MAX (32)
-#define PPS_MAX (256)
 struct decoder_sys_t
 {
     /* */
@@ -558,17 +556,6 @@ static block_t *CreateAnnexbNAL( decoder_t *p_dec, const uint8_t *p, int i_size
     return p_nal;
 }
 
-static void CreateDecodedNAL( uint8_t **pp_ret, int *pi_ret,
-                              const uint8_t *src, int i_src )
-{
-    uint8_t *dst = malloc( i_src );
-
-    *pp_ret = dst;
-
-    if( dst )
-        *pi_ret = nal_decode(src, dst, i_src);
-}
-
 /*****************************************************************************
  * ParseNALBlock: parses annexB type NALs
  * All p_frag blocks are required to start with 0 0 0 1 4-byte startcode
@@ -828,295 +815,74 @@ static block_t *OutputPicture( decoder_t *p_dec )
 static void PutSPS( decoder_t *p_dec, block_t *p_frag )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
+    struct nal_sps sps;
 
-    uint8_t *pb_dec = NULL;
-    int     i_dec = 0;
-    bs_t s;
-    int i_tmp;
-    int i_sps_id;
-
-    CreateDecodedNAL( &pb_dec, &i_dec, &p_frag->p_buffer[5],
-                     p_frag->i_buffer - 5 );
-
-    bs_init( &s, pb_dec, i_dec );
-    int i_profile_idc = bs_read( &s, 8 );
-    p_dec->fmt_out.i_profile = i_profile_idc;
-    /* Skip constraint_set0123, reserved(4) */
-    bs_skip( &s, 1+1+1+1 + 4 );
-    p_dec->fmt_out.i_level = bs_read( &s, 8 );
-    /* sps id */
-    i_sps_id = bs_read_ue( &s );
-    if( i_sps_id >= SPS_MAX || i_sps_id < 0 )
+    if( h264_parse_sps( p_frag->p_buffer, p_frag->i_buffer, &sps ) != 0 )
     {
-        msg_Warn( p_dec, "invalid SPS (sps_id=%d)", i_sps_id );
-        free( pb_dec );
+        msg_Warn( p_dec, "invalid SPS (sps_id=%d)", sps.i_id );
         block_Release( p_frag );
         return;
     }
 
-    if( i_profile_idc == PROFILE_H264_HIGH || i_profile_idc == PROFILE_H264_HIGH_10 ||
-        i_profile_idc == PROFILE_H264_HIGH_422 || i_profile_idc == PROFILE_H264_HIGH_444_PREDICTIVE ||
-        i_profile_idc ==  PROFILE_H264_CAVLC_INTRA || i_profile_idc ==  PROFILE_H264_SVC_BASELINE ||
-        i_profile_idc ==  PROFILE_H264_SVC_HIGH )
+    p_dec->fmt_out.i_profile = sps.i_profile;
+    p_dec->fmt_out.i_level = sps.i_level;
+    p_dec->fmt_out.video.i_width  = sps.i_width;
+    p_dec->fmt_out.video.i_height = sps.i_height;
+    if( sps.vui.i_sar_num != 0 && sps.vui.i_sar_den != 0 )
     {
-        /* chroma_format_idc */
-        const int i_chroma_format_idc = bs_read_ue( &s );
-        if( i_chroma_format_idc == 3 )
-            bs_skip( &s, 1 ); /* separate_colour_plane_flag */
-        /* bit_depth_luma_minus8 */
-        bs_read_ue( &s );
-        /* bit_depth_chroma_minus8 */
-        bs_read_ue( &s );
-        /* qpprime_y_zero_transform_bypass_flag */
-        bs_skip( &s, 1 );
-        /* seq_scaling_matrix_present_flag */
-        i_tmp = bs_read( &s, 1 );
-        if( i_tmp )
-        {
-            for( int i = 0; i < ((3 != i_chroma_format_idc) ? 8 : 12); i++ )
-            {
-                /* seq_scaling_list_present_flag[i] */
-                i_tmp = bs_read( &s, 1 );
-                if( !i_tmp )
-                    continue;
-                const int i_size_of_scaling_list = (i < 6 ) ? 16 : 64;
-                /* scaling_list (...) */
-                int i_lastscale = 8;
-                int i_nextscale = 8;
-                for( int j = 0; j < i_size_of_scaling_list; j++ )
-                {
-                    if( i_nextscale != 0 )
-                    {
-                        /* delta_scale */
-                        i_tmp = bs_read_se( &s );
-                        i_nextscale = ( i_lastscale + i_tmp + 256 ) % 256;
-                        /* useDefaultScalingMatrixFlag = ... */
-                    }
-                    /* scalinglist[j] */
-                    i_lastscale = ( i_nextscale == 0 ) ? i_lastscale : i_nextscale;
-                }
-            }
-        }
+        p_dec->fmt_out.video.i_sar_num = sps.vui.i_sar_num;
+        p_dec->fmt_out.video.i_sar_den = sps.vui.i_sar_den;
     }
 
-    /* Skip i_log2_max_frame_num */
-    p_sys->i_log2_max_frame_num = bs_read_ue( &s );
-    if( p_sys->i_log2_max_frame_num > 12)
-        p_sys->i_log2_max_frame_num = 12;
-    /* Read poc_type */
-    p_sys->i_pic_order_cnt_type = bs_read_ue( &s );
-    if( p_sys->i_pic_order_cnt_type == 0 )
-    {
-        /* skip i_log2_max_poc_lsb */
-        p_sys->i_log2_max_pic_order_cnt_lsb = bs_read_ue( &s );
-        if( p_sys->i_log2_max_pic_order_cnt_lsb > 12 )
-            p_sys->i_log2_max_pic_order_cnt_lsb = 12;
-    }
-    else if( p_sys->i_pic_order_cnt_type == 1 )
-    {
-        int i_cycle;
-        /* skip b_delta_pic_order_always_zero */
-        p_sys->i_delta_pic_order_always_zero_flag = bs_read( &s, 1 );
-        /* skip i_offset_for_non_ref_pic */
-        bs_read_se( &s );
-        /* skip i_offset_for_top_to_bottom_field */
-        bs_read_se( &s );
-        /* read i_num_ref_frames_in_poc_cycle */
-        i_cycle = bs_read_ue( &s );
-        if( i_cycle > 256 ) i_cycle = 256;
-        while( i_cycle > 0 )
-        {
-            /* skip i_offset_for_ref_frame */
-            bs_read_se(&s );
-            i_cycle--;
-        }
-    }
-    /* i_num_ref_frames */
-    bs_read_ue( &s );
-    /* b_gaps_in_frame_num_value_allowed */
-    bs_skip( &s, 1 );
-
-    /* Read size */
-    p_dec->fmt_out.video.i_width  = 16 * ( bs_read_ue( &s ) + 1 );
-    p_dec->fmt_out.video.i_height = 16 * ( bs_read_ue( &s ) + 1 );
-
-    /* b_frame_mbs_only */
-    p_sys->b_frame_mbs_only = bs_read( &s, 1 );
-    p_dec->fmt_out.video.i_height *=  ( 2 - p_sys->b_frame_mbs_only );
-    if( p_sys->b_frame_mbs_only == 0 )
-    {
-        bs_skip( &s, 1 );
-    }
-    /* b_direct8x8_inference */
-    bs_skip( &s, 1 );
+    p_sys->i_log2_max_frame_num = sps.i_log2_max_frame_num;
+    p_sys->b_frame_mbs_only = sps.b_frame_mbs_only;
+    p_sys->i_pic_order_cnt_type = sps.i_pic_order_cnt_type;
+    p_sys->i_delta_pic_order_always_zero_flag = sps.i_delta_pic_order_always_zero_flag;
+    p_sys->i_log2_max_pic_order_cnt_lsb = sps.i_log2_max_pic_order_cnt_lsb;
 
-    /* crop */
-    i_tmp = bs_read( &s, 1 );
-    if( i_tmp )
+    if( sps.vui.b_valid )
     {
-        /* left */
-        bs_read_ue( &s );
-        /* right */
-        bs_read_ue( &s );
-        /* top */
-        bs_read_ue( &s );
-        /* bottom */
-        bs_read_ue( &s );
+        p_sys->b_timing_info_present_flag = sps.vui.b_timing_info_present_flag;
+        p_sys->i_num_units_in_tick =  sps.vui.i_num_units_in_tick;
+        p_sys->i_time_scale = sps.vui.i_time_scale;
+        p_sys->b_fixed_frame_rate = sps.vui.b_fixed_frame_rate;
+        p_sys->b_pic_struct_present_flag = sps.vui.b_pic_struct_present_flag;
+        p_sys->b_cpb_dpb_delays_present_flag = sps.vui.b_cpb_dpb_delays_present_flag;
+        p_sys->i_cpb_removal_delay_length_minus1 = sps.vui.i_cpb_removal_delay_length_minus1;
+        p_sys->i_dpb_output_delay_length_minus1 = sps.vui.i_dpb_output_delay_length_minus1;
     }
 
-    /* vui */
-    i_tmp = bs_read( &s, 1 );
-    if( i_tmp )
-    {
-        /* read the aspect ratio part if any */
-        i_tmp = bs_read( &s, 1 );
-        if( i_tmp )
-        {
-            static const struct { int w, h; } sar[17] =
-            {
-                { 0,   0 }, { 1,   1 }, { 12, 11 }, { 10, 11 },
-                { 16, 11 }, { 40, 33 }, { 24, 11 }, { 20, 11 },
-                { 32, 11 }, { 80, 33 }, { 18, 11 }, { 15, 11 },
-                { 64, 33 }, { 160,99 }, {  4,  3 }, {  3,  2 },
-                {  2,  1 },
-            };
-            int i_sar = bs_read( &s, 8 );
-            int w, h;
-
-            if( i_sar < 17 )
-            {
-                w = sar[i_sar].w;
-                h = sar[i_sar].h;
-            }
-            else if( i_sar == 255 )
-            {
-                w = bs_read( &s, 16 );
-                h = bs_read( &s, 16 );
-            }
-            else
-            {
-                w = 0;
-                h = 0;
-            }
-
-            if( w != 0 && h != 0 )
-            {
-                p_dec->fmt_out.video.i_sar_num = w;
-                p_dec->fmt_out.video.i_sar_den = h;
-            }
-            else
-            {
-                p_dec->fmt_out.video.i_sar_num = 1;
-                p_dec->fmt_out.video.i_sar_den = 1;
-            }
-        }
-
-        /* overscan */
-        i_tmp = bs_read( &s, 1 );
-        if ( i_tmp )
-            bs_read( &s, 1 );
-
-        /* video signal type */
-        i_tmp = bs_read( &s, 1 );
-        if( i_tmp )
-        {
-            bs_read( &s, 4 );
-            /* colour desc */
-            bs_read( &s, 1 );
-            if ( i_tmp )
-                bs_read( &s, 24 );
-        }
-
-        /* chroma loc info */
-        i_tmp = bs_read( &s, 1 );
-        if( i_tmp )
-        {
-            bs_read_ue( &s );
-            bs_read_ue( &s );
-        }
-
-        /* timing info */
-        p_sys->b_timing_info_present_flag = bs_read( &s, 1 );
-        if( p_sys->b_timing_info_present_flag )
-        {
-            p_sys->i_num_units_in_tick = bs_read( &s, 32 );
-            p_sys->i_time_scale = bs_read( &s, 32 );
-            p_sys->b_fixed_frame_rate = bs_read( &s, 1 );
-        }
-
-        /* Nal hrd & VC1 hrd parameters */
-        p_sys->b_cpb_dpb_delays_present_flag = false;
-        for ( int i=0; i<2; i++ )
-        {
-            i_tmp = bs_read( &s, 1 );
-            if( i_tmp )
-            {
-                p_sys->b_cpb_dpb_delays_present_flag = true;
-                uint32_t count = bs_read_ue( &s ) + 1;
-                bs_read( &s, 4 );
-                bs_read( &s, 4 );
-                for( uint32_t i=0; i<count; i++ )
-                {
-                    bs_read_ue( &s );
-                    bs_read_ue( &s );
-                    bs_read( &s, 1 );
-                }
-                bs_read( &s, 5 );
-                p_sys->i_cpb_removal_delay_length_minus1 = bs_read( &s, 5 );
-                p_sys->i_dpb_output_delay_length_minus1 = bs_read( &s, 5 );
-                bs_read( &s, 5 );
-            }
-        }
-
-        if( p_sys->b_cpb_dpb_delays_present_flag )
-            bs_read( &s, 1 );
-
-        /* pic struct info */
-        p_sys->b_pic_struct_present_flag = bs_read( &s, 1 );
-
-        /* + unparsed remains */
-    }
-
-    free( pb_dec );
-
     /* We have a new SPS */
     if( !p_sys->b_sps )
-        msg_Dbg( p_dec, "found NAL_SPS (sps_id=%d)", i_sps_id );
+        msg_Dbg( p_dec, "found NAL_SPS (sps_id=%d)", sps.i_id );
     p_sys->b_sps = true;
 
-    if( p_sys->pp_sps[i_sps_id] )
-        block_Release( p_sys->pp_sps[i_sps_id] );
-    p_sys->pp_sps[i_sps_id] = p_frag;
+    if( p_sys->pp_sps[sps.i_id] )
+        block_Release( p_sys->pp_sps[sps.i_id] );
+    p_sys->pp_sps[sps.i_id] = p_frag;
 }
 
 static void PutPPS( decoder_t *p_dec, block_t *p_frag )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    bs_t s;
-    int i_pps_id;
-    int i_sps_id;
+    struct nal_pps pps;
 
-    bs_init( &s, &p_frag->p_buffer[5], p_frag->i_buffer - 5 );
-    i_pps_id = bs_read_ue( &s ); // pps id
-    i_sps_id = bs_read_ue( &s ); // sps id
-    if( i_pps_id >= PPS_MAX || i_sps_id >= SPS_MAX )
+    if( h264_parse_pps( p_frag->p_buffer, p_frag->i_buffer, &pps ) != 0 )
     {
-        msg_Warn( p_dec, "invalid PPS (pps_id=%d sps_id=%d)", i_pps_id, i_sps_id );
+        msg_Warn( p_dec, "invalid PPS (pps_id=%d sps_id=%d)", pps.i_id, pps.i_sps_id );
         block_Release( p_frag );
         return;
     }
-    bs_skip( &s, 1 ); // entropy coding mode flag
-    p_sys->i_pic_order_present_flag = bs_read( &s, 1 );
-    /* TODO */
+    p_sys->i_pic_order_present_flag = pps.i_pic_order_present_flag;
 
     /* We have a new PPS */
     if( !p_sys->b_pps )
-        msg_Dbg( p_dec, "found NAL_PPS (pps_id=%d sps_id=%d)", i_pps_id, i_sps_id );
+        msg_Dbg( p_dec, "found NAL_PPS (pps_id=%d sps_id=%d)", pps.i_id, pps.i_sps_id );
     p_sys->b_pps = true;
 
-    if( p_sys->pp_pps[i_pps_id] )
-        block_Release( p_sys->pp_pps[i_pps_id] );
-    p_sys->pp_pps[i_pps_id] = p_frag;
+    if( p_sys->pp_pps[pps.i_id] )
+        block_Release( p_sys->pp_pps[pps.i_id] );
+    p_sys->pp_pps[pps.i_id] = p_frag;
 }
 
 static void ParseSlice( decoder_t *p_dec, bool *pb_new_picture, slice_t *p_slice,
diff --git a/modules/packetizer/h264_nal.c b/modules/packetizer/h264_nal.c
index de3ce6f..9a0f6c0 100644
--- a/modules/packetizer/h264_nal.c
+++ b/modules/packetizer/h264_nal.c
@@ -212,6 +212,281 @@ int h264_get_spspps( uint8_t *p_buf, size_t i_buf,
     return -1;
 }
 
+int h264_parse_sps( const uint8_t *p_sps_buf, int i_sps_size,
+                    struct nal_sps *p_sps )
+{
+    uint8_t *pb_dec = NULL;
+    int     i_dec = 0;
+    bs_t s;
+    int i_tmp;
+
+    memset( p_sps, 0, sizeof(struct nal_sps) );
+    CreateDecodedNAL( &pb_dec, &i_dec, &p_sps_buf[5],
+                      i_sps_size - 5 );
+
+    bs_init( &s, pb_dec, i_dec );
+    int i_profile_idc = bs_read( &s, 8 );
+    p_sps->i_profile = i_profile_idc;
+    /* Skip constraint_set0123, reserved(4) */
+    bs_skip( &s, 1+1+1+1 + 4 );
+    p_sps->i_level = bs_read( &s, 8 );
+    /* sps id */
+    p_sps->i_id = bs_read_ue( &s );
+    if( p_sps->i_id >= SPS_MAX || p_sps->i_id < 0 )
+    {
+        free( pb_dec );
+        return -1;
+    }
+
+    if( i_profile_idc == PROFILE_H264_HIGH || i_profile_idc == PROFILE_H264_HIGH_10 ||
+        i_profile_idc == PROFILE_H264_HIGH_422 || i_profile_idc == PROFILE_H264_HIGH_444_PREDICTIVE ||
+        i_profile_idc ==  PROFILE_H264_CAVLC_INTRA || i_profile_idc ==  PROFILE_H264_SVC_BASELINE ||
+        i_profile_idc ==  PROFILE_H264_SVC_HIGH )
+    {
+        /* chroma_format_idc */
+        const int i_chroma_format_idc = bs_read_ue( &s );
+        if( i_chroma_format_idc == 3 )
+            bs_skip( &s, 1 ); /* separate_colour_plane_flag */
+        /* bit_depth_luma_minus8 */
+        bs_read_ue( &s );
+        /* bit_depth_chroma_minus8 */
+        bs_read_ue( &s );
+        /* qpprime_y_zero_transform_bypass_flag */
+        bs_skip( &s, 1 );
+        /* seq_scaling_matrix_present_flag */
+        i_tmp = bs_read( &s, 1 );
+        if( i_tmp )
+        {
+            for( int i = 0; i < ((3 != i_chroma_format_idc) ? 8 : 12); i++ )
+            {
+                /* seq_scaling_list_present_flag[i] */
+                i_tmp = bs_read( &s, 1 );
+                if( !i_tmp )
+                    continue;
+                const int i_size_of_scaling_list = (i < 6 ) ? 16 : 64;
+                /* scaling_list (...) */
+                int i_lastscale = 8;
+                int i_nextscale = 8;
+                for( int j = 0; j < i_size_of_scaling_list; j++ )
+                {
+                    if( i_nextscale != 0 )
+                    {
+                        /* delta_scale */
+                        i_tmp = bs_read_se( &s );
+                        i_nextscale = ( i_lastscale + i_tmp + 256 ) % 256;
+                        /* useDefaultScalingMatrixFlag = ... */
+                    }
+                    /* scalinglist[j] */
+                    i_lastscale = ( i_nextscale == 0 ) ? i_lastscale : i_nextscale;
+                }
+            }
+        }
+    }
+
+    /* Skip i_log2_max_frame_num */
+    p_sps->i_log2_max_frame_num = bs_read_ue( &s );
+    if( p_sps->i_log2_max_frame_num > 12)
+        p_sps->i_log2_max_frame_num = 12;
+    /* Read poc_type */
+    p_sps->i_pic_order_cnt_type = bs_read_ue( &s );
+    if( p_sps->i_pic_order_cnt_type == 0 )
+    {
+        /* skip i_log2_max_poc_lsb */
+        p_sps->i_log2_max_pic_order_cnt_lsb = bs_read_ue( &s );
+        if( p_sps->i_log2_max_pic_order_cnt_lsb > 12 )
+            p_sps->i_log2_max_pic_order_cnt_lsb = 12;
+    }
+    else if( p_sps->i_pic_order_cnt_type == 1 )
+    {
+        int i_cycle;
+        /* skip b_delta_pic_order_always_zero */
+        p_sps->i_delta_pic_order_always_zero_flag = bs_read( &s, 1 );
+        /* skip i_offset_for_non_ref_pic */
+        bs_read_se( &s );
+        /* skip i_offset_for_top_to_bottom_field */
+        bs_read_se( &s );
+        /* read i_num_ref_frames_in_poc_cycle */
+        i_cycle = bs_read_ue( &s );
+        if( i_cycle > 256 ) i_cycle = 256;
+        while( i_cycle > 0 )
+        {
+            /* skip i_offset_for_ref_frame */
+            bs_read_se(&s );
+            i_cycle--;
+        }
+    }
+    /* i_num_ref_frames */
+    bs_read_ue( &s );
+    /* b_gaps_in_frame_num_value_allowed */
+    bs_skip( &s, 1 );
+
+    /* Read size */
+    p_sps->i_width  = 16 * ( bs_read_ue( &s ) + 1 );
+    p_sps->i_height = 16 * ( bs_read_ue( &s ) + 1 );
+
+    /* b_frame_mbs_only */
+    p_sps->b_frame_mbs_only = bs_read( &s, 1 );
+    p_sps->i_height *=  ( 2 - p_sps->b_frame_mbs_only );
+    if( p_sps->b_frame_mbs_only == 0 )
+    {
+        bs_skip( &s, 1 );
+    }
+    /* b_direct8x8_inference */
+    bs_skip( &s, 1 );
+
+    /* crop */
+    i_tmp = bs_read( &s, 1 );
+    if( i_tmp )
+    {
+        /* left */
+        bs_read_ue( &s );
+        /* right */
+        bs_read_ue( &s );
+        /* top */
+        bs_read_ue( &s );
+        /* bottom */
+        bs_read_ue( &s );
+    }
+
+    /* vui */
+    i_tmp = bs_read( &s, 1 );
+    if( i_tmp )
+    {
+        p_sps->vui.b_valid = true;
+        /* read the aspect ratio part if any */
+        i_tmp = bs_read( &s, 1 );
+        if( i_tmp )
+        {
+            static const struct { int w, h; } sar[17] =
+            {
+                { 0,   0 }, { 1,   1 }, { 12, 11 }, { 10, 11 },
+                { 16, 11 }, { 40, 33 }, { 24, 11 }, { 20, 11 },
+                { 32, 11 }, { 80, 33 }, { 18, 11 }, { 15, 11 },
+                { 64, 33 }, { 160,99 }, {  4,  3 }, {  3,  2 },
+                {  2,  1 },
+            };
+            int i_sar = bs_read( &s, 8 );
+            int w, h;
+
+            if( i_sar < 17 )
+            {
+                w = sar[i_sar].w;
+                h = sar[i_sar].h;
+            }
+            else if( i_sar == 255 )
+            {
+                w = bs_read( &s, 16 );
+                h = bs_read( &s, 16 );
+            }
+            else
+            {
+                w = 0;
+                h = 0;
+            }
+
+            if( w != 0 && h != 0 )
+            {
+                p_sps->vui.i_sar_num = w;
+                p_sps->vui.i_sar_den = h;
+            }
+            else
+            {
+                p_sps->vui.i_sar_num = 1;
+                p_sps->vui.i_sar_den = 1;
+            }
+        }
+
+        /* overscan */
+        i_tmp = bs_read( &s, 1 );
+        if ( i_tmp )
+            bs_read( &s, 1 );
+
+        /* video signal type */
+        i_tmp = bs_read( &s, 1 );
+        if( i_tmp )
+        {
+            bs_read( &s, 4 );
+            /* colour desc */
+            bs_read( &s, 1 );
+            if ( i_tmp )
+                bs_read( &s, 24 );
+        }
+
+        /* chroma loc info */
+        i_tmp = bs_read( &s, 1 );
+        if( i_tmp )
+        {
+            bs_read_ue( &s );
+            bs_read_ue( &s );
+        }
+
+        /* timing info */
+        p_sps->vui.b_timing_info_present_flag = bs_read( &s, 1 );
+        if( p_sps->vui.b_timing_info_present_flag )
+        {
+            p_sps->vui.i_num_units_in_tick = bs_read( &s, 32 );
+            p_sps->vui.i_time_scale = bs_read( &s, 32 );
+            p_sps->vui.b_fixed_frame_rate = bs_read( &s, 1 );
+        }
+
+        /* Nal hrd & VC1 hrd parameters */
+        p_sps->vui.b_cpb_dpb_delays_present_flag = false;
+        for ( int i=0; i<2; i++ )
+        {
+            i_tmp = bs_read( &s, 1 );
+            if( i_tmp )
+            {
+                p_sps->vui.b_cpb_dpb_delays_present_flag = true;
+                uint32_t count = bs_read_ue( &s ) + 1;
+                bs_read( &s, 4 );
+                bs_read( &s, 4 );
+                for( uint32_t i=0; i<count; i++ )
+                {
+                    bs_read_ue( &s );
+                    bs_read_ue( &s );
+                    bs_read( &s, 1 );
+                }
+                bs_read( &s, 5 );
+                p_sps->vui.i_cpb_removal_delay_length_minus1 = bs_read( &s, 5 );
+                p_sps->vui.i_dpb_output_delay_length_minus1 = bs_read( &s, 5 );
+                bs_read( &s, 5 );
+            }
+        }
+
+        if( p_sps->vui.b_cpb_dpb_delays_present_flag )
+            bs_read( &s, 1 );
+
+        /* pic struct info */
+        p_sps->vui.b_pic_struct_present_flag = bs_read( &s, 1 );
+
+        /* + unparsed remains */
+    }
+
+    free( pb_dec );
+
+    return 0;
+}
+
+int h264_parse_pps( const uint8_t *p_pps_buf, int i_pps_size,
+                    struct nal_pps *p_pps )
+{
+    bs_t s;
+
+    memset( p_pps, 0, sizeof(struct nal_pps) );
+    bs_init( &s, &p_pps_buf[5], i_pps_size - 5 );
+    p_pps->i_id = bs_read_ue( &s ); // pps id
+    p_pps->i_sps_id = bs_read_ue( &s ); // sps id
+    if( p_pps->i_id >= PPS_MAX || p_pps->i_sps_id >= SPS_MAX )
+    {
+        return -1;
+    }
+    bs_skip( &s, 1 ); // entropy coding mode flag
+    p_pps->i_pic_order_present_flag = bs_read( &s, 1 );
+    /* TODO */
+
+    return 0;
+}
+
 bool h264_get_profile_level(const es_format_t *p_fmt, size_t *p_profile,
                             size_t *p_level, size_t *p_nal_size)
 {
diff --git a/modules/packetizer/h264_nal.h b/modules/packetizer/h264_nal.h
index c991ddc..f307b64 100644
--- a/modules/packetizer/h264_nal.h
+++ b/modules/packetizer/h264_nal.h
@@ -28,6 +28,8 @@
 # include <vlc_common.h>
 # include <vlc_codec.h>
 
+# include "../demux/mpeg/mpeg_parser_helpers.h"
+
 #define PROFILE_H264_BASELINE             66
 #define PROFILE_H264_MAIN                 77
 #define PROFILE_H264_EXTENDED             88
@@ -43,6 +45,9 @@
 #define PROFILE_H264_MVC_STEREO_HIGH      128
 #define PROFILE_H264_MVC_MULTIVIEW_HIGH   118
 
+#define SPS_MAX (32)
+#define PPS_MAX (256)
+
 enum nal_unit_type_e
 {
     NAL_UNKNOWN = 0,
@@ -66,6 +71,49 @@ enum sei_type_e
     SEI_RECOVERY_POINT = 6
 };
 
+struct nal_sps
+{
+    int i_id;
+    int i_profile, i_level;
+    int i_width, i_height;
+    int i_log2_max_frame_num;
+    int b_frame_mbs_only;
+    int i_pic_order_cnt_type;
+    int i_delta_pic_order_always_zero_flag;
+    int i_log2_max_pic_order_cnt_lsb;
+
+    struct {
+        bool b_valid;
+        int i_sar_num, i_sar_den;
+        bool b_timing_info_present_flag;
+        uint32_t i_num_units_in_tick;
+        uint32_t i_time_scale;
+        bool b_fixed_frame_rate;
+        bool b_pic_struct_present_flag;
+        bool b_cpb_dpb_delays_present_flag;
+        uint8_t i_cpb_removal_delay_length_minus1;
+        uint8_t i_dpb_output_delay_length_minus1;
+    } vui;
+};
+
+struct nal_pps
+{
+    int i_id;
+    int i_sps_id;
+    int i_pic_order_present_flag;
+};
+
+static inline void CreateDecodedNAL( uint8_t **pp_ret, int *pi_ret,
+                                     const uint8_t *src, int i_src )
+{
+    uint8_t *dst = malloc( i_src );
+
+    *pp_ret = dst;
+
+    if( dst )
+        *pi_ret = nal_decode(src, dst, i_src);
+}
+
 /* Parse the SPS/PPS Metadata and convert it to annex b format */
 int convert_sps_pps( decoder_t *p_dec, const uint8_t *p_buf,
                      uint32_t i_buf_size, uint8_t *p_out_buf,
@@ -88,6 +136,16 @@ 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 );
 
+/* Parse a SPS into the struct nal_sps
+ * Returns 0 in case of success */
+int h264_parse_sps( const uint8_t *p_sps_buf, int i_sps_size,
+                    struct nal_sps *p_sps );
+
+/* Parse a PPS into the struct nal_pps
+ * Returns 0 in case of success */
+int h264_parse_pps( const uint8_t *p_pps_buf, int i_pps_size,
+                    struct nal_pps *p_pps );
+
 /* Get level and Profile */
 bool h264_get_profile_level(const es_format_t *p_fmt, size_t *p_profile,
                             size_t *p_level, size_t *p_nal_size);
-- 
2.1.3




More information about the vlc-devel mailing list