Commit a56ed71a authored by Thomas Guillem's avatar Thomas Guillem

packetizer h264: refactor and expose SPS/PPS parsing

The goal is to expose h264_parse_sps and h264_parse_pps functions that can be
used from decoders.
parent f815b9e5
This diff is collapsed.
......@@ -206,6 +206,287 @@ int h264_get_spspps( uint8_t *p_buf, size_t i_buf,
return 0;
}
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;
if (i_sps_size < 5 || (p_sps_buf[4] & 0x1f) != NAL_SPS)
return -1;
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;
if (i_pps_size < 5 || (p_pps_buf[4] & 0x1f) != NAL_PPS)
return -1;
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)
{
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment