Reputation: 819
I've been trying to find out how to calculate width a height from SPS nal unit. I have H264 video which has these parameters
h264 (High), yuvj420p(pc), 1280x720 [SAR 1:1 DAR 16:9], 20 fps, 20 tbr, 1200k tbn, 40 tbc
I've been searching for a formula which would calculate width (1280) and height (720) but haven't found any which would help me. Right now I'm using this formula and it works for most H264 streams but in this case height and width is 80x48
if(frame_cropping_flag) {
width = ((pic_width_in_mbs_minus1 +1)*16) - frame_crop_left_offset*2 - frame_crop_right_offset*2;
height= ((2 - frame_mbs_only_flag)* (pic_height_in_map_units_minus1 +1) * 16) - (frame_crop_top_offset * 2) - (frame_crop_bottom_offset * 2);
}
else {
width = ((pic_width_in_mbs_minus1 +1)*16);
height= ((2 - frame_mbs_only_flag)* (pic_height_in_map_units_minus1 +1) * 16);
}
here is SPS as base64
Z2QAKa2EBUViuKxUdCAqKxXFYqOhAVFYrisVHQgKisVxWKjoQFRWK4rFR0ICorFcVio6ECSFITk8nyfk/k/J8nm5s00IEkKQnJ5Pk/J/J+T5PNzZprQCgC3YCqQAAAMB4AAASwGBAAH0AAADAjKAve+F4RCNQA==
here is SPS that I've parsed:
======= SPS =======
profile_idc : 100
constraint_set0_flag : 0
constraint_set1_flag : 0
constraint_set2_flag : 0
constraint_set3_flag : 0
constraint_set4_flag : 0
constraint_set5_flag : 0
reserved_zero_2bits : 0
level_idc : 41
seq_parameter_set_id : 0
chroma_format_idc : 1
separate_colour_plane_flag : 0
bit_depth_luma_minus8 : 0
bit_depth_chroma_minus8 : 0
qpprime_y_zero_transform_bypass_flag : 0
seq_scaling_matrix_present_flag : 1
log2_max_frame_num_minus4 : 41
pic_order_cnt_type : 4
log2_max_pic_order_cnt_lsb_minus4 : 0
delta_pic_order_always_zero_flag : 0
offset_for_non_ref_pic : 0
offset_for_top_to_bottom_field : 0
num_ref_frames_in_pic_order_cnt_cycle : 0
num_ref_frames : 2
gaps_in_frame_num_value_allowed_flag : 0
pic_width_in_mbs_minus1 : 4
pic_height_in_map_units_minus1 : 2
frame_mbs_only_flag : 1
mb_adaptive_frame_field_flag : 0
direct_8x8_inference_flag : 0
frame_cropping_flag : 0
frame_crop_left_offset : 0
frame_crop_right_offset : 0
frame_crop_top_offset : 0
frame_crop_bottom_offset : 0
vui_parameters_present_flag : 0
=== VUI ===
aspect_ratio_info_present_flag : 0
aspect_ratio_idc : 0
sar_width : 0
sar_height : 0
overscan_info_present_flag : 0
overscan_appropriate_flag : 0
video_signal_type_present_flag : 0
video_format : 0
video_full_range_flag : 0
colour_description_present_flag : 0
colour_primaries : 0
transfer_characteristics : 0
matrix_coefficients : 0
chroma_loc_info_present_flag : 0
chroma_sample_loc_type_top_field : 0
chroma_sample_loc_type_bottom_field : 0
timing_info_present_flag : 0
num_units_in_tick : 0
time_scale : 0
fixed_frame_rate_flag : 0
nal_hrd_parameters_present_flag : 0
vcl_hrd_parameters_present_flag : 0
low_delay_hrd_flag : 0
pic_struct_present_flag : 0
bitstream_restriction_flag : 0
motion_vectors_over_pic_boundaries_flag : 0
max_bytes_per_pic_denom : 0
max_bits_per_mb_denom : 0
log2_max_mv_length_horizontal : 0
log2_max_mv_length_vertical : 0
num_reorder_frames : 0
max_dec_frame_buffering : 0
=== HRD ===
cpb_cnt_minus1 : 0
bit_rate_scale : 0
cpb_size_scale : 0
bit_rate_value_minus1[0] : 0
cpb_size_value_minus1[0] : 0
cbr_flag[0] : 0
initial_cpb_removal_delay_length_minus1 : 0
cpb_removal_delay_length_minus1 : 0
dpb_output_delay_length_minus1 : 0
time_offset_length : 0
I guess it has something to do with luma and chroma macroblocks size I've been able to calculate SubWidthC\SubHeightC and MbWidthC\MbHeightC. But I'm still confused what to do next.
Upvotes: 7
Views: 6722
Reputation: 86
we now have an H.264 SPS parser in librem:
https://github.com/creytiv/rem/blob/master/include/rem_h264.h#L52
it can be used like this, to extract the resolution:
struct h264_sps sps;
struct vidsz vidsz;
h264_sps_decode(&sps, buf, len);
h264_sps_resolution(&sps, vidsz);
printf("resolution: %u x %u\n", vidsz.w, vidsz.h);
Upvotes: 1
Reputation: 369
Hello first of all you are parsing SPS incorrectly so you need to fix that. If you parse it correctly then you will have
pic_width_in_mbs_minus1 : 79
pic_height_in_map_units_minus1 : 44
frame_mbs_only_flag : 1
frame_cropping_flag : 0
If you calculate width and height using your formula then you will actualy have 1280x720
Anyway you should calculate height and width using SubWidth and SubHeight as follows:
int SubWidthC;
int SubHeightC;
if (sps->chroma_format_idc == 0 && sps->separate_colour_plane_flag == 0) { //monochrome
SubWidthC = SubHeightC = 0;
}
else if (sps->chroma_format_idc == 1 && sps->separate_colour_plane_flag == 0) { //4:2:0
SubWidthC = SubHeightC = 2;
}
else if (sps->chroma_format_idc == 2 && sps->separate_colour_plane_flag == 0) { //4:2:2
SubWidthC = 2;
SubHeightC = 1;
}
else if (sps->chroma_format_idc == 3) { //4:4:4
if (sps->separate_colour_plane_flag == 0) {
SubWidthC = SubHeightC = 1;
}
else if (sps->separate_colour_plane_flag == 1) {
SubWidthC = SubHeightC = 0;
}
}
int PicWidthInMbs = sps->pic_width_in_mbs_minus1 + 1;
int PicHeightInMapUnits = sps->pic_height_in_map_units_minus1 + 1;
int FrameHeightInMbs = (2 - sps->frame_mbs_only_flag) * PicHeightInMapUnits;
int crop_left = 0;
int crop_right = 0;
int crop_top = 0;
int crop_bottom = 0;
if (sps->frame_cropping_flag) {
crop_left = sps->frame_crop_left_offset;
crop_right = sps->frame_crop_right_offset;
crop_top = sps->frame_crop_top_offset;
crop_bottom = sps->frame_crop_bottom_offset;
}
int width = PicWidthInMbs * 16 - SubWidthC * (crop_left + crop_right);
int height = FrameHeightInMbs * 16 - SubHeightC * (2 - sps->frame_mbs_only_flag) * (crop_top + crop_bottom);
Upvotes: 11