当前位置:   article > 正文

H.264 序列参数集(SPS)_h264 sps

h264 sps

基本结构(SPS

H.264 中的 SPS(Sequence Parameter Set)是一种参数集,用于描述视频序列的特征和配置信息。SPS 是在 H.264 视频流中的一个元数据单元,它包含了视频编码器的设置和视频序列的特性。

SPS 包含了以下重要的信息:

  • Profile 和 Level:指定视频编码的配置和兼容性级别。
  • 图像尺寸和宽高比:描述视频图像的尺寸和宽高比。
  • 帧率和比特率:指定视频的帧率和比特率,影响视频的流畅度和压缩效率。
  • 帧间预测和帧内预测设置:描述视频编码中的预测模式和帧类型。
  • 量化参数:控制视频质量和压缩比例的参数。
  • 熵编码模式:指定熵编码的方式,影响编码的复杂度和压缩效率。
  • 参考帧设置:指定参考帧的配置和使用方式,用于帧间预测。

seq_parameter_set_rbsp()

封装结构

  1. // SPS
  2. typedef struct {
  3. uint32_t profile_idc; //!< 当前H.264的编码配置, baseline(66) | main(77) | extended(88)
  4. uint32_t constraint_set0_flag;
  5. uint32_t constraint_set1_flag;
  6. uint32_t constraint_set2_flag;
  7. uint32_t constraint_set3_flag;
  8. uint32_t constraint_set4_flag;
  9. uint32_t constraint_set5_flag;
  10. uint32_t reserved_zero_2bits;
  11. uint32_t level_idc; //!< 编码等级 0~51
  12. uint32_t seq_parameter_set_id;
  13. // if(profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144) {
  14. uint32_t chroma_format_idc;
  15. // if( chroma_format_idc = = 3 )
  16. uint32_t residual_colour_transform_flag;
  17. // }
  18. uint32_t bit_depth_luma_minus8;
  19. uint32_t bit_depth_chroma_minus8;
  20. uint32_t qpprime_y_zero_transform_bypass_flag;
  21. uint32_t seq_scaling_matrix_present_flag;
  22. // if (seq_scaling_matrix_present_flag)
  23. // for(i = 0; i < 8; i++) {
  24. uint32_t seq_scaling_list_present_flag[12];
  25. // }
  26. // }
  27. // }
  28. uint32_t log2_max_frame_num_minus4;
  29. uint32_t pic_order_cnt_type;
  30. // if(pic_order_cnt_type == 0) {
  31. uint32_t log2_max_pic_order_cnt_lsb_minus4;
  32. // }
  33. // else if(pic_order_cnt_type == 1) {
  34. uint32_t delta_pic_order_always_zero_flag;
  35. int offset_for_non_ref_pic;
  36. int offset_for_top_to_bottom_field;
  37. uint32_t num_ref_frames_in_pic_order_cnt_cycle;
  38. int offset_for_ref_frame[256];
  39. // }
  40. uint32_t max_num_ref_frames; //!< 参考帧的最大数目
  41. uint32_t gaps_in_frame_num_value_allowed_flag;
  42. uint32_t pic_width_in_mbs_minus1; //!< 用于计算图像的宽度,单位为宏块个数
  43. uint32_t pic_height_in_map_units_minus1; //!< 度量视频中一帧图像的高度
  44. uint32_t frame_mbs_only_flag;
  45. // if (!frame_mbs_only_flag) {
  46. uint32_t mb_adaptive_frame_field_flag;
  47. // }
  48. uint32_t direct_8x8_inference_flag;
  49. uint32_t frame_cropping_flag;
  50. // if (frame_cropping_flag) {
  51. uint32_t frame_crop_left_offset;
  52. uint32_t frame_crop_right_offset;
  53. uint32_t frame_crop_top_offset;
  54. uint32_t frame_crop_bottom_offset;
  55. // }
  56. uint32_t vui_parameters_present_flag;
  57. // if (vui_parameters_present_flag) {
  58. NaluSpsVuiParameters vui_parameters;
  59. // }
  60. } NaluSPS;

解析过程

  1. /// 解析SPS头信息
  2. bool parse_nalu_sps(uint8_t *sps_data, uint32_t sps_size, NaluSPS &sps) {
  3. if (sps_size < 4)
  4. return false;
  5. /// 找到 SPS NAL 单元的起始位置
  6. int start_code_length = 0;
  7. if (sps_data[0] == 0 && sps_data[1] == 0 && sps_data[2] == 1) { // TODO: 00 00 01
  8. start_code_length = 3;
  9. } else if (sps_data[0] == 0 && sps_data[1] == 0 && sps_data[2] == 0 && sps_data[3] == 1) { // TODO: 00 00 00 01
  10. start_code_length = 4;
  11. } else if ((sps_data[0] & 0x1f) == 7) { // TODO: 继StartCode后第一个字节以 0x67 开头
  12. start_code_length = 0;
  13. } else {
  14. return false;
  15. }
  16. sps_data += start_code_length;
  17. sps_size -= start_code_length;
  18. /// 标准文档里注明: SPS、PPS、SEI的解析,基于RBSP语法
  19. /// ITU-T Advanced Video Coding For Generic Audiovisual Services
  20. std::vector<uint8_t> rbsp = EBSP2RBSP(sps_data, (int)sps_size);
  21. bs_t *b = bs_new(rbsp.data(), rbsp.size());
  22. /// Nalu Header
  23. uint32_t forbidden_zero_bit = bs_read_u(b, 1);
  24. uint32_t nal_ref_idc = bs_read_u(b, 2);
  25. uint32_t nal_unit_type = bs_read_u(b, 5);
  26. NaluHeader nalu_header;
  27. nalu_header.nal_ref_idc = nal_ref_idc;
  28. nalu_header.nal_unit_type = nal_unit_type;
  29. /// 序列参数集(SPS)-RBSP语法
  30. if (H264_NAL_SPS == (NAL_TYPE)nal_unit_type) {
  31. memset(&sps, 0, sizeof(NaluSPS));
  32. sps.profile_idc = bs_read_u8(b); // TODO: 当前H.264的编码配置, baseline(66) | main(77) | extended(88)
  33. sps.constraint_set0_flag = bs_read_u(b, 1);
  34. sps.constraint_set1_flag = bs_read_u(b, 1);
  35. sps.constraint_set2_flag = bs_read_u(b, 1);
  36. sps.constraint_set3_flag = bs_read_u(b, 1);
  37. sps.constraint_set4_flag = bs_read_u(b, 1);
  38. sps.constraint_set5_flag = bs_read_u(b, 1);
  39. sps.reserved_zero_2bits = bs_read_u(b, 2);
  40. sps.level_idc = bs_read_u8(b);
  41. sps.seq_parameter_set_id = bs_read_ue(b);
  42. if (sps.profile_idc == 100 || sps.profile_idc == 110 || sps.profile_idc == 122 || sps.profile_idc == 244 || sps.profile_idc == 44 ||
  43. sps.profile_idc == 83 || sps.profile_idc == 86 || sps.profile_idc == 118 || sps.profile_idc == 128 || sps.profile_idc == 138) {
  44. sps.chroma_format_idc = bs_read_ue(b);
  45. if (sps.chroma_format_idc == 3) {
  46. sps.residual_colour_transform_flag = bs_read_u(b, 1);
  47. }
  48. sps.bit_depth_luma_minus8 = bs_read_ue(b);
  49. sps.bit_depth_chroma_minus8 = bs_read_ue(b);
  50. sps.qpprime_y_zero_transform_bypass_flag = bs_read_u(b, 1);
  51. sps.seq_scaling_matrix_present_flag = bs_read_u(b, 1);
  52. if (sps.seq_scaling_matrix_present_flag) {
  53. uint32_t *ScalingList4x4[12];
  54. uint32_t UseDefaultScalingMatrix4x4Flag[12];
  55. uint32_t *ScalingList8x8[12];
  56. uint32_t UseDefaultScalingMatrix8x8Flag[12];
  57. for (int i = 0; i < ((sps.chroma_format_idc != 3) ? 8 : 12); i++) {
  58. sps.seq_scaling_list_present_flag[i] = bs_read_u(b, 1);
  59. if (sps.seq_scaling_list_present_flag[i]) {
  60. if (i < 6) {
  61. scaling_list(b, ScalingList4x4[i], 16, UseDefaultScalingMatrix4x4Flag[i]);
  62. } else {
  63. scaling_list(b, ScalingList8x8[i - 6], 64, UseDefaultScalingMatrix8x8Flag[i - 6]);
  64. }
  65. }
  66. }
  67. }
  68. }
  69. sps.log2_max_frame_num_minus4 = bs_read_ue(b);
  70. sps.pic_order_cnt_type = bs_read_ue(b);
  71. if (sps.pic_order_cnt_type == 0) {
  72. sps.log2_max_pic_order_cnt_lsb_minus4 = bs_read_ue(b);
  73. } else if (sps.pic_order_cnt_type == 1) {
  74. sps.delta_pic_order_always_zero_flag = bs_read_u(b, 1);
  75. sps.offset_for_non_ref_pic = bs_read_se(b);
  76. sps.offset_for_top_to_bottom_field = bs_read_se(b);
  77. sps.num_ref_frames_in_pic_order_cnt_cycle = bs_read_ue(b);
  78. for (int i = 0; i < sps.num_ref_frames_in_pic_order_cnt_cycle; i++) {
  79. sps.offset_for_ref_frame[i] = bs_read_se(b);
  80. }
  81. }
  82. sps.max_num_ref_frames = bs_read_ue(b); // TODO: 参考帧的最大数目
  83. sps.gaps_in_frame_num_value_allowed_flag = bs_read_u(b, 1);
  84. sps.pic_width_in_mbs_minus1 = bs_read_ue(b); // TODO: 用于计算图像的宽度,单位为宏块个数
  85. sps.pic_height_in_map_units_minus1 = bs_read_ue(b); // TODO: 度量视频中一帧图像的高度
  86. uint32_t width = (sps.pic_width_in_mbs_minus1 + 1) * 16;
  87. uint32_t height = (sps.pic_height_in_map_units_minus1 + 1) * 16;
  88. sps.frame_mbs_only_flag = bs_read_u(b, 1); // TODO: 宏块的编码方式
  89. if (!sps.frame_mbs_only_flag) {
  90. sps.mb_adaptive_frame_field_flag = bs_read_u(b, 1);
  91. }
  92. sps.direct_8x8_inference_flag = bs_read_u(b, 1);
  93. sps.frame_cropping_flag = bs_read_u(b, 1);
  94. if (sps.frame_cropping_flag) {
  95. sps.frame_crop_left_offset = bs_read_ue(b);
  96. sps.frame_crop_right_offset = bs_read_ue(b);
  97. sps.frame_crop_top_offset = bs_read_ue(b);
  98. sps.frame_crop_bottom_offset = bs_read_ue(b);
  99. }
  100. sps.vui_parameters_present_flag = bs_read_u(b, 1); // TODO: SPS中是否存在VUI信息?
  101. if (sps.vui_parameters_present_flag) {
  102. vui_parameters(b, sps);
  103. }
  104. rbsp_trailing_bits(b);
  105. }
  106. bs_free(b);
  107. return true;
  108. }

视频使用者信息(VUI)

vui_parameters 是视频编码中的一种参数,用于描述视频序列的附加信息,即视频使用者信息 (Video Usability Information)。vui_parameters 包含了与视频序列的使用和显示相关的配置信息,以提供更好的用户体验和兼容性。

vui_parameters 主要包括以下信息:

  • 宽高比 (aspect_ratio_info):视频的显示宽高比,用于正确显示视频的宽高比例。
  • 颜色参数 (color_primaries、transfer_characteristics、matrix_coefficients):视频的颜色空间信息,用于正确解释和显示视频的颜色。
  • 时间相关信息 (timing_info):视频的时间参数,包括帧率和时间码等,用于正确解码和播放视频。
  • 视频信号范围 (video_signal_type_present_flag):视频信号的范围,例如全范围或标准范围,用于正确显示视频的亮度和对比度。
  • 音频同步信息 (nal_hrd_parameters、vcl_hrd_parameters):视频和音频之间的同步信息,确保音视频同步播放。

vui_parameters()

封装结构

  1. // Vui Parameters
  2. typedef struct {
  3. uint32_t aspect_ratio_info_present_flag;
  4. // if(aspect_ratio_info_present_flag) {
  5. uint32_t aspect_ratio_idc;
  6. // if (aspect_ratio_idc == Extended_SAR) {
  7. uint32_t sar_width;
  8. uint32_t sar_height;
  9. // }
  10. // }
  11. uint32_t overscan_info_present_flag;
  12. // if (overscan_info_present_flag) {
  13. uint32_t overscan_appropriate_flag;
  14. // }
  15. uint32_t video_signal_type_present_flag;
  16. // if (video_signal_type_present_flag) {
  17. uint32_t video_format;
  18. uint32_t video_full_range_flag;
  19. uint32_t colour_description_present_flag;
  20. // if (colour_description_present_flag) {
  21. uint32_t colour_primaries;
  22. uint32_t transfer_characteristics;
  23. uint32_t matrix_coefficients;
  24. // }
  25. // }
  26. uint32_t chroma_loc_info_present_flag;
  27. // if (chroma_loc_info_present_flag) {
  28. uint32_t chroma_sample_loc_type_top_field;
  29. uint32_t chroma_sample_loc_type_bottom_field;
  30. // }
  31. uint32_t timing_info_present_flag;
  32. // if (timing_info_present_flag) {
  33. uint32_t num_units_in_tick;
  34. uint32_t time_scale;
  35. uint32_t fixed_frame_rate_flag;
  36. // }
  37. uint32_t nal_hrd_parameters_present_flag;
  38. // if (nal_hrd_parameters_present_flag) {
  39. NaluSpsHrdParameters nal_hrd_parameters_present;
  40. // }
  41. uint32_t vcl_hrd_parameters_present_flag;
  42. // if (vcl_hrd_parameters_present_flag) {
  43. NaluSpsHrdParameters vcl_hrd_parameters_present;
  44. // }
  45. // if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
  46. uint32_t low_delay_hrd_flag;
  47. // }
  48. uint32_t pic_struct_present_flag;
  49. uint32_t bitstream_restriction_flag;
  50. // if (bitstream_restriction_flag) {
  51. uint32_t motion_vectors_over_pic_boundaries_flag;
  52. uint32_t max_bytes_per_pic_denom;
  53. uint32_t max_bits_per_mb_denom;
  54. uint32_t log2_max_mv_length_horizontal;
  55. uint32_t log2_max_mv_length_vertical;
  56. uint32_t num_reorder_frames;
  57. uint32_t max_dec_frame_buffering;
  58. // }
  59. } NaluSpsVuiParameters;

解析过程

  1. void vui_parameters(bs_t *b, NaluSPS &sps) {
  2. NaluSpsVuiParameters vui;
  3. memset(&vui, 0, sizeof(NaluSpsVuiParameters));
  4. vui.aspect_ratio_info_present_flag = bs_read_u1(b);
  5. if (vui.aspect_ratio_info_present_flag) {
  6. vui.aspect_ratio_idc = bs_read_u8(b);
  7. if (vui.aspect_ratio_idc == 255) {
  8. vui.sar_width = bs_read_u(b, 16);
  9. vui.sar_height = bs_read_u(b, 16);
  10. }
  11. }
  12. vui.overscan_info_present_flag = bs_read_u1(b);
  13. if (vui.overscan_info_present_flag) {
  14. vui.overscan_appropriate_flag = bs_read_u1(b);
  15. }
  16. vui.video_signal_type_present_flag = bs_read_u1(b);
  17. if (vui.video_signal_type_present_flag) {
  18. vui.video_format = bs_read_u(b, 3);
  19. vui.video_full_range_flag = bs_read_u1(b);
  20. vui.colour_description_present_flag = bs_read_u1(b);
  21. if (vui.colour_description_present_flag) {
  22. vui.colour_primaries = bs_read_u8(b);
  23. vui.transfer_characteristics = bs_read_u8(b);
  24. vui.matrix_coefficients = bs_read_u8(b);
  25. }
  26. }
  27. vui.chroma_loc_info_present_flag = bs_read_u1(b);
  28. if (vui.chroma_loc_info_present_flag) {
  29. vui.chroma_sample_loc_type_top_field = bs_read_ue(b);
  30. vui.chroma_sample_loc_type_bottom_field = bs_read_ue(b);
  31. }
  32. vui.timing_info_present_flag = bs_read_u1(b);
  33. if (vui.timing_info_present_flag) {
  34. vui.num_units_in_tick = bs_read_u(b, 32);
  35. vui.time_scale = bs_read_u(b, 32);
  36. vui.fixed_frame_rate_flag = bs_read_u1(b);
  37. }
  38. vui.nal_hrd_parameters_present_flag = bs_read_u1(b);
  39. if (vui.nal_hrd_parameters_present_flag) {
  40. hrd_parameters(b);
  41. }
  42. vui.vcl_hrd_parameters_present_flag = bs_read_u1(b);
  43. if (vui.vcl_hrd_parameters_present_flag) {
  44. hrd_parameters(b);
  45. }
  46. if (vui.nal_hrd_parameters_present_flag || vui.vcl_hrd_parameters_present_flag) {
  47. vui.low_delay_hrd_flag = bs_read_u1(b);
  48. }
  49. vui.pic_struct_present_flag = bs_read_u1(b);
  50. vui.bitstream_restriction_flag = bs_read_u1(b);
  51. if (vui.bitstream_restriction_flag) {
  52. vui.motion_vectors_over_pic_boundaries_flag = bs_read_u1(b);
  53. vui.max_bytes_per_pic_denom = bs_read_ue(b);
  54. vui.max_bits_per_mb_denom = bs_read_ue(b);
  55. vui.log2_max_mv_length_horizontal = bs_read_ue(b);
  56. vui.log2_max_mv_length_vertical = bs_read_ue(b);
  57. vui.num_reorder_frames = bs_read_ue(b);
  58. vui.max_dec_frame_buffering = bs_read_ue(b);
  59. }
  60. sps.vui_parameters = vui;
  61. }

假定参考解码器(HRD)

hrd_parameters 是视频编码中的一种参数,用于描述视频编码的恢复点检测相关的信息。HRD 是 Hypothetical Reference Decoder(假设参考解码器)的缩写,它定义了视频编码的比特率、缓冲区大小和相关的时间参数。

hrd_parameters 包含了视频编码过程中的控制和管理参数,用于确保编码后的视频流在解码时能够正确恢复,并保持一定的稳定性和适应性。

hrd_parameters 主要包括以下信息:

  • 比特率 (bit_rate):视频编码的平均比特率。
  • 缓冲区大小 (cpb_size):解码器的缓冲区大小,用于存储已解码和待解码的视频数据。
  • 初始缓冲区满度 (initial_cpb_fullness):初始时解码器缓冲区的填充级别,通常以百分比表示。
  • 约束参数 (cpb_cnt_minus1、bit_rate_scale、cpb_size_scale):用于计算实际的缓冲区大小和填充级别。

hrd_parameters()

封装结构

  1. typedef struct {
  2. uint32_t cpb_cnt_minus1;
  3. uint32_t bit_rate_scale;
  4. uint32_t cpb_size_scale;
  5. // for( SchedSelIdx = 0; SchedSelIdx <= cpb_cnt_minus1; SchedSelIdx++ ) {
  6. uint32_t bit_rate_value_minus1[5];
  7. uint32_t cpb_size_value_minus1[5];
  8. uint32_t cbr_flag[5];
  9. // }
  10. uint32_t initial_cpb_removal_delay_length_minus1;
  11. uint32_t cpb_removal_delay_length_minus1;
  12. uint32_t dpb_output_delay_length_minus1;
  13. uint32_t time_offset_length;
  14. } NaluSpsHrdParameters;

解析过程

  1. void hrd_parameters(bs_t *b, NaluSpsHrdParameters &out_hrd) {
  2. NaluSpsHrdParameters hrd;
  3. memset(&hrd, 0, sizeof(NaluSpsHrdParameters));
  4. hrd.cpb_cnt_minus1 = bs_read_ue(b);
  5. hrd.bit_rate_scale = bs_read_u(b, 4);
  6. hrd.cpb_size_scale = bs_read_u(b, 4);
  7. for (int SchedSelIdx = 0; SchedSelIdx <= hrd.cpb_cnt_minus1; SchedSelIdx++) {
  8. hrd.bit_rate_value_minus1[SchedSelIdx] = bs_read_ue(b);
  9. hrd.cpb_size_value_minus1[SchedSelIdx] = bs_read_ue(b);
  10. hrd.cbr_flag[SchedSelIdx] = bs_read_u1(b);
  11. }
  12. hrd.initial_cpb_removal_delay_length_minus1 = bs_read_u(b, 5);
  13. hrd.cpb_removal_delay_length_minus1 = bs_read_u(b, 5);
  14. hrd.dpb_output_delay_length_minus1 = bs_read_u(b, 5);
  15. hrd.time_offset_length = bs_read_u(b, 5);
  16. }

其他附录

scaling_list()

  1. /// 缩放比例列表
  2. void scaling_list(bs_t *b, uint32_t *scalingList, int sizeOfScalingList, uint32_t useDefaultScalingMatrixFlag) {
  3. int lastScale = 8;
  4. int nextScale = 8;
  5. for (int j = 0; j < sizeOfScalingList; j++) {
  6. if (nextScale != 0) {
  7. //!< delta_scale
  8. int32_t delta_scale = bs_read_se(b);
  9. nextScale = (lastScale + delta_scale + 256) % 256;
  10. useDefaultScalingMatrixFlag = (j == 0 && nextScale == 0);
  11. }
  12. scalingList[j] = (nextScale == 0) ? lastScale : nextScale;
  13. lastScale = (int)scalingList[j];
  14. }
  15. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/722328
推荐阅读
相关标签
  

闽ICP备14008679号