in src/brpc/rtmp.cpp [646:814]
butil::Status AVCDecoderConfigurationRecord::ParseSPS(
const butil::StringPiece& buf, size_t sps_length) {
// for NALU, 7.3.1 NAL unit syntax
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 61.
if (buf.empty()) {
return butil::Status(EINVAL, "SPS is empty");
}
const int8_t nutv = buf[0];
const int8_t forbidden_zero_bit = (nutv >> 7) & 0x01;
if (forbidden_zero_bit) {
return butil::Status(EINVAL, "forbidden_zero_bit shall equal 0");
}
// nal_ref_idc not equal to 0 specifies that the content of the NAL unit
// contains:
// a sequence parameter set
// or a picture parameter set
// or a slice of a reference picture
// or a slice data partition of a reference picture.
int8_t nal_ref_idc = (nutv >> 5) & 0x03;
if (!nal_ref_idc) {
return butil::Status(EINVAL, "nal_ref_idc is 0");
}
// 7.4.1 NAL unit semantics
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 61.
// nal_unit_type specifies the type of RBSP data structure contained in
// the NAL unit as specified in Table 7-1.
const AVCNaluType nal_unit_type = (AVCNaluType)(nutv & 0x1f);
if (nal_unit_type != AVC_NALU_SPS) {
return butil::Status(EINVAL, "nal_unit_type is not %d", (int)AVC_NALU_SPS);
}
// Extract the rbsp from sps.
DEFINE_SMALL_ARRAY(char, rbsp, sps_length - 1, 64);
buf.copy(rbsp, sps_length - 1, 1);
size_t rbsp_len = 0;
for (size_t i = 1; i < sps_length; ++i) {
// XX 00 00 03 XX, the 03 byte should be dropped.
if (!(i >= 3 && buf[i - 2] == 0 && buf[i - 1] == 0 && buf[i] == 3)) {
rbsp[rbsp_len++] = buf[i];
}
}
// for SPS, 7.3.2.1.1 Sequence parameter set data syntax
// H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62.
if (rbsp_len < 3) {
return butil::Status(EINVAL, "rbsp must be at least 3 bytes");
}
// Decode rbsp.
const char* p = rbsp;
uint8_t profile_idc = *p++;
if (!profile_idc) {
return butil::Status(EINVAL, "profile_idc is 0");
}
int8_t flags = *p++;
if (flags & 0x03) {
return butil::Status(EINVAL, "Invalid flags=%d", (int)flags);
}
uint8_t level_idc = *p++;
if (!level_idc) {
return butil::Status(EINVAL, "level_idc is 0");
}
BitStream bs(p, rbsp + rbsp_len - p);
int32_t seq_parameter_set_id = -1;
if (avc_nalu_read_uev(&bs, &seq_parameter_set_id) != 0) {
return butil::Status(EINVAL, "Fail to read seq_parameter_set_id");
}
if (seq_parameter_set_id < 0) {
return butil::Status(EINVAL, "Invalid seq_parameter_set_id=%d",
(int)seq_parameter_set_id);
}
int32_t chroma_format_idc = -1;
if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 ||
profile_idc == 244 || profile_idc == 44 || profile_idc == 83 ||
profile_idc == 86 || profile_idc == 118 || profile_idc == 128) {
if (avc_nalu_read_uev(&bs, &chroma_format_idc) != 0) {
return butil::Status(EINVAL, "Fail to read chroma_format_idc");
}
if (chroma_format_idc == 3) {
int8_t separate_colour_plane_flag = -1;
if (avc_nalu_read_bit(&bs, &separate_colour_plane_flag) != 0) {
return butil::Status(EINVAL, "Fail to read separate_colour_plane_flag");
}
}
int32_t bit_depth_luma_minus8 = -1;
if (avc_nalu_read_uev(&bs, &bit_depth_luma_minus8) != 0) {
return butil::Status(EINVAL, "Fail to read bit_depth_luma_minus8");
}
int32_t bit_depth_chroma_minus8 = -1;
if (avc_nalu_read_uev(&bs, &bit_depth_chroma_minus8) != 0) {
return butil::Status(EINVAL, "Fail to read bit_depth_chroma_minus8");
}
int8_t qpprime_y_zero_transform_bypass_flag = -1;
if (avc_nalu_read_bit(&bs, &qpprime_y_zero_transform_bypass_flag) != 0) {
return butil::Status(EINVAL, "Fail to read qpprime_y_zero_transform_bypass_flag");
}
int8_t seq_scaling_matrix_present_flag = -1;
if (avc_nalu_read_bit(&bs, &seq_scaling_matrix_present_flag) != 0) {
return butil::Status(EINVAL, "Fail to read seq_scaling_matrix_present_flag");
}
if (seq_scaling_matrix_present_flag) {
int nb_scmpfs = (chroma_format_idc != 3 ? 8 : 12);
for (int i = 0; i < nb_scmpfs; i++) {
int8_t seq_scaling_matrix_present_flag_i = -1;
if (avc_nalu_read_bit(&bs, &seq_scaling_matrix_present_flag_i)) {
return butil::Status(EINVAL, "Fail to read seq_scaling_"
"matrix_present_flag[%d]", i);
}
if (seq_scaling_matrix_present_flag_i) {
return butil::Status(EINVAL, "Invalid seq_scaling_matrix_"
"present_flag[%d]=%d nb_scmpfs=%d",
i, (int)seq_scaling_matrix_present_flag_i,
nb_scmpfs);
}
}
}
}
int32_t log2_max_frame_num_minus4 = -1;
if (avc_nalu_read_uev(&bs, &log2_max_frame_num_minus4) != 0) {
return butil::Status(EINVAL, "Fail to read log2_max_frame_num_minus4");
}
int32_t pic_order_cnt_type = -1;
if (avc_nalu_read_uev(&bs, &pic_order_cnt_type) != 0) {
return butil::Status(EINVAL, "Fail to read pic_order_cnt_type");
}
if (pic_order_cnt_type == 0) {
int32_t log2_max_pic_order_cnt_lsb_minus4 = -1;
if (avc_nalu_read_uev(&bs, &log2_max_pic_order_cnt_lsb_minus4) != 0) {
return butil::Status(EINVAL, "Fail to read log2_max_pic_order_cnt_lsb_minus4");
}
} else if (pic_order_cnt_type == 1) {
int8_t delta_pic_order_always_zero_flag = -1;
if (avc_nalu_read_bit(&bs, &delta_pic_order_always_zero_flag) != 0) {
return butil::Status(EINVAL, "Fail to read delta_pic_order_always_zero_flag");
}
int32_t offset_for_non_ref_pic = -1;
if (avc_nalu_read_uev(&bs, &offset_for_non_ref_pic) != 0) {
return butil::Status(EINVAL, "Fail to read offset_for_non_ref_pic");
}
int32_t offset_for_top_to_bottom_field = -1;
if (avc_nalu_read_uev(&bs, &offset_for_top_to_bottom_field) != 0) {
return butil::Status(EINVAL, "Fail to read offset_for_top_to_bottom_field");
}
int32_t num_ref_frames_in_pic_order_cnt_cycle = -1;
if (avc_nalu_read_uev(&bs, &num_ref_frames_in_pic_order_cnt_cycle) != 0) {
return butil::Status(EINVAL, "Fail to read num_ref_frames_in_pic_order_cnt_cycle");
}
if (num_ref_frames_in_pic_order_cnt_cycle) {
return butil::Status(EINVAL, "Invalid num_ref_frames_in_pic_order_cnt_cycle=%d",
num_ref_frames_in_pic_order_cnt_cycle);
}
}
int32_t max_num_ref_frames = -1;
if (avc_nalu_read_uev(&bs, &max_num_ref_frames) != 0) {
return butil::Status(EINVAL, "Fail to read max_num_ref_frames");
}
int8_t gaps_in_frame_num_value_allowed_flag = -1;
if (avc_nalu_read_bit(&bs, &gaps_in_frame_num_value_allowed_flag) != 0) {
return butil::Status(EINVAL, "Fail to read gaps_in_frame_num_value_allowed_flag");
}
int32_t pic_width_in_mbs_minus1 = -1;
if (avc_nalu_read_uev(&bs, &pic_width_in_mbs_minus1) != 0) {
return butil::Status(EINVAL, "Fail to read pic_width_in_mbs_minus1");
}
int32_t pic_height_in_map_units_minus1 = -1;
if (avc_nalu_read_uev(&bs, &pic_height_in_map_units_minus1) != 0) {
return butil::Status(EINVAL, "Fail to read pic_height_in_map_units_minus1");
}
width = (int)(pic_width_in_mbs_minus1 + 1) * 16;
height = (int)(pic_height_in_map_units_minus1 + 1) * 16;
return butil::Status::OK();
}