butil::Status AVCDecoderConfigurationRecord::ParseSPS()

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();
}