diff --git a/CHANGELOG.md b/CHANGELOG.md index 7482a9a98f..a6d995fb4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Full documentation for rocDecode is available at [https://rocm.docs.amd.com/proj * VP9 IVF container file parsing support in bitstream reader. * CTest for VP9 decode on bitstream reader. +* HEVC stream syntax error handling. ### Changed diff --git a/src/parser/hevc_parser.cpp b/src/parser/hevc_parser.cpp index 24e805eabd..eaae1408ee 100644 --- a/src/parser/hevc_parser.cpp +++ b/src/parser/hevc_parser.cpp @@ -775,7 +775,7 @@ void HevcVideoParser::ParseSubLayerHrdParameters(HevcSubLayerHrdParameters *sub_ } } -void HevcVideoParser::ParseHrdParameters(HevcHrdParameters *hrd, bool common_inf_present_flag, uint32_t max_num_sub_layers_minus1, uint8_t *nalu, size_t size,size_t &offset) { +ParserResult HevcVideoParser::ParseHrdParameters(HevcHrdParameters *hrd, bool common_inf_present_flag, uint32_t max_num_sub_layers_minus1, uint8_t *nalu, size_t size,size_t &offset) { if (common_inf_present_flag) { hrd->nal_hrd_parameters_present_flag = Parser::GetBit(nalu, offset); hrd->vcl_hrd_parameters_present_flag = Parser::GetBit(nalu, offset); @@ -807,11 +807,13 @@ void HevcVideoParser::ParseHrdParameters(HevcHrdParameters *hrd, bool common_inf if (hrd->fixed_pic_rate_within_cvs_flag[i]) { hrd->elemental_duration_in_tc_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + CHECK_ALLOWED_RANGE("elemental_duration_in_tc_minus1", hrd->elemental_duration_in_tc_minus1[i], 0, 2047); } else { hrd->low_delay_hrd_flag[i] = Parser::GetBit(nalu, offset); } if (!hrd->low_delay_hrd_flag[i]) { hrd->cpb_cnt_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + CHECK_ALLOWED_RANGE("cpb_cnt_minus1", hrd->cpb_cnt_minus1[i], 0, 31); } if (hrd->nal_hrd_parameters_present_flag) { //sub_layer_hrd_parameters( i ) @@ -822,6 +824,7 @@ void HevcVideoParser::ParseHrdParameters(HevcHrdParameters *hrd, bool common_inf ParseSubLayerHrdParameters(&hrd->sub_layer_hrd_parameters_1[i], hrd->cpb_cnt_minus1[i], hrd->sub_pic_hrd_params_present_flag, nalu, size, offset); } } + return PARSER_OK; } // Table 7-5. Default values of ScalingList[ 0 ][ matrixId ][ i ] with i = 0..15. @@ -1041,7 +1044,7 @@ ParserResult HevcVideoParser::ParseShortTermRefPicSet(HevcSeqParamSet *sps_ptr, rps->num_negative_pics = Parser::ExpGolomb::ReadUe(nalu, offset); rps->num_positive_pics = Parser::ExpGolomb::ReadUe(nalu, offset); rps->num_of_delta_pocs = rps->num_negative_pics + rps->num_positive_pics; - CHECK_ALLOWED_RANGE(rps->num_of_delta_pocs, 0, sps_ptr->sps_max_dec_pic_buffering_minus1[sps_ptr->sps_max_sub_layers_minus1]); + CHECK_ALLOWED_RANGE("num_of_delta_pocs", rps->num_of_delta_pocs, 0, sps_ptr->sps_max_dec_pic_buffering_minus1[sps_ptr->sps_max_sub_layers_minus1]); for (i = 0; i < rps->num_negative_pics; i++) { rps->delta_poc_s0_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); @@ -1201,7 +1204,7 @@ void HevcVideoParser::ParseVui(HevcVuiParameters *vui, uint32_t max_num_sub_laye } } -void HevcVideoParser::ParseVps(uint8_t *nalu, size_t size) { +ParserResult HevcVideoParser::ParseVps(uint8_t *nalu, size_t size) { size_t offset = 0; // current bit offset uint32_t vps_id = Parser::ReadBits(nalu, offset, 4); HevcVideoParamSet *p_vps = &vps_list_[vps_id]; @@ -1214,13 +1217,18 @@ void HevcVideoParser::ParseVps(uint8_t *nalu, size_t size) { p_vps->vps_max_sub_layers_minus1 = Parser::ReadBits(nalu, offset, 3); p_vps->vps_temporal_id_nesting_flag = Parser::GetBit(nalu, offset); p_vps->vps_reserved_0xffff_16bits = Parser::ReadBits(nalu, offset, 16); + if (p_vps->vps_reserved_0xffff_16bits != 0xFFFF) { + ERR("vps_reserved_0xffff_16bits is not equal to 0xFFFF."); + return PARSER_INVALID_ARG; + } ParsePtl(&p_vps->profile_tier_level, true, p_vps->vps_max_sub_layers_minus1, nalu, size, offset); p_vps->vps_sub_layer_ordering_info_present_flag = Parser::GetBit(nalu, offset); - for (int i = 0; i <= p_vps->vps_max_sub_layers_minus1; i++) { if (p_vps->vps_sub_layer_ordering_info_present_flag || (i == 0)) { p_vps->vps_max_dec_pic_buffering_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + CHECK_ALLOWED_RANGE("vps_max_dec_pic_buffering_minus1", p_vps->vps_max_dec_pic_buffering_minus1[i], 0, HEVC_MAX_DPB_FRAMES - 1); p_vps->vps_max_num_reorder_pics[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + CHECK_ALLOWED_RANGE("vps_max_num_reorder_pics", p_vps->vps_max_num_reorder_pics[i], 0, p_vps->vps_max_dec_pic_buffering_minus1[i]); p_vps->vps_max_latency_increase_plus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); } else { p_vps->vps_max_dec_pic_buffering_minus1[i] = p_vps->vps_max_dec_pic_buffering_minus1[0]; @@ -1230,6 +1238,7 @@ void HevcVideoParser::ParseVps(uint8_t *nalu, size_t size) { } p_vps->vps_max_layer_id = Parser::ReadBits(nalu, offset, 6); p_vps->vps_num_layer_sets_minus1 = Parser::ExpGolomb::ReadUe(nalu, offset); + CHECK_ALLOWED_RANGE("vps_num_layer_sets_minus1", p_vps->vps_num_layer_sets_minus1, 0, 1023); for (int i = 1; i <= p_vps->vps_num_layer_sets_minus1; i++) { for (int j = 0; j <= p_vps->vps_max_layer_id; j++) { p_vps->layer_id_included_flag[i][j] = Parser::GetBit(nalu, offset); @@ -1244,13 +1253,18 @@ void HevcVideoParser::ParseVps(uint8_t *nalu, size_t size) { p_vps->vps_num_ticks_poc_diff_one_minus1 = Parser::ExpGolomb::ReadUe(nalu, offset); } p_vps->vps_num_hrd_parameters = Parser::ExpGolomb::ReadUe(nalu, offset); + CHECK_ALLOWED_RANGE("vps_num_hrd_parameters", p_vps->vps_num_hrd_parameters, 0, p_vps->vps_num_layer_sets_minus1 + 1); for (int i = 0; ivps_num_hrd_parameters; i++) { p_vps->hrd_layer_set_idx[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + CHECK_ALLOWED_RANGE("hrd_layer_set_idx", p_vps->hrd_layer_set_idx[i], (p_vps->vps_base_layer_internal_flag ? 0 : 1), p_vps->vps_num_layer_sets_minus1); if (i > 0) { p_vps->cprms_present_flag[i] = Parser::GetBit(nalu, offset); } //parse HRD parameters - ParseHrdParameters(&p_vps->hrd_parameters[i], p_vps->cprms_present_flag[i], p_vps->vps_max_sub_layers_minus1, nalu, size, offset); + ParserResult ret; + if ((ret = ParseHrdParameters(&p_vps->hrd_parameters[i], p_vps->cprms_present_flag[i], p_vps->vps_max_sub_layers_minus1, nalu, size, offset)) != PARSER_OK) { + return ret; + } } } p_vps->vps_extension_flag = Parser::GetBit(nalu, offset); @@ -1259,6 +1273,7 @@ void HevcVideoParser::ParseVps(uint8_t *nalu, size_t size) { #if DBGINFO PrintVps(p_vps); #endif // DBGINFO + return PARSER_OK; } void HevcVideoParser::ParseSps(uint8_t *nalu, size_t size) { @@ -1525,7 +1540,7 @@ ParserResult HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcS // Set active VPS, SPS and PPS for the current slice m_active_pps_id_ = Parser::ExpGolomb::ReadUe(nalu, offset); - CHECK_ALLOWED_MAX(m_active_pps_id_, (MAX_PPS_COUNT - 1)); + CHECK_ALLOWED_MAX("active_pps_id", m_active_pps_id_, (MAX_PPS_COUNT - 1)); temp_sh.slice_pic_parameter_set_id = p_slice_header->slice_pic_parameter_set_id = m_active_pps_id_; pps_ptr = &pps_list_[m_active_pps_id_]; if ( pps_ptr->is_received == 0) { @@ -1592,7 +1607,7 @@ ParserResult HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcS p_slice_header->slice_reserved_flag[i] = Parser::GetBit(nalu, offset); } p_slice_header->slice_type = Parser::ExpGolomb::ReadUe(nalu, offset); - CHECK_ALLOWED_MAX(p_slice_header->slice_type, 2); + CHECK_ALLOWED_MAX("slice_type", p_slice_header->slice_type, 2); if (pps_ptr->output_flag_present_flag) { p_slice_header->pic_output_flag = Parser::GetBit(nalu, offset); @@ -1675,7 +1690,7 @@ ParserResult HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcS } } if (p_slice_header->slice_type != HEVC_SLICE_TYPE_I) { - CHECK_ALLOWED_RANGE(p_slice_header->st_rps.num_of_delta_pocs + p_slice_header->num_long_term_pics, 1, dpb_buffer_.dpb_size); + CHECK_ALLOWED_RANGE("num_of_delta_pocs + num_long_term_pics", p_slice_header->st_rps.num_of_delta_pocs + p_slice_header->num_long_term_pics, 1, dpb_buffer_.dpb_size); } if (sps_ptr->sps_temporal_mvp_enabled_flag) { p_slice_header->slice_temporal_mvp_enabled_flag = Parser::GetBit(nalu, offset); @@ -1695,10 +1710,10 @@ ParserResult HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcS p_slice_header->num_ref_idx_active_override_flag = Parser::GetBit(nalu, offset); if (p_slice_header->num_ref_idx_active_override_flag) { p_slice_header->num_ref_idx_l0_active_minus1 = Parser::ExpGolomb::ReadUe(nalu, offset); - CHECK_ALLOWED_MAX(p_slice_header->num_ref_idx_l0_active_minus1, std::min(14, static_cast(dpb_buffer_.dpb_size - 1))); + CHECK_ALLOWED_MAX("num_ref_idx_l0_active_minus1", p_slice_header->num_ref_idx_l0_active_minus1, std::min(14, static_cast(dpb_buffer_.dpb_size - 1))); if (p_slice_header->slice_type == HEVC_SLICE_TYPE_B) { p_slice_header->num_ref_idx_l1_active_minus1 = Parser::ExpGolomb::ReadUe(nalu, offset); - CHECK_ALLOWED_MAX(p_slice_header->num_ref_idx_l1_active_minus1, std::min(14, static_cast(dpb_buffer_.dpb_size - 1))); + CHECK_ALLOWED_MAX("num_ref_idx_l1_active_minus1", p_slice_header->num_ref_idx_l1_active_minus1, std::min(14, static_cast(dpb_buffer_.dpb_size - 1))); } } else { p_slice_header->num_ref_idx_l0_active_minus1 = pps_ptr->num_ref_idx_l0_default_active_minus1; @@ -1770,9 +1785,9 @@ ParserResult HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcS if ((p_slice_header->collocated_from_l0_flag && p_slice_header->num_ref_idx_l0_active_minus1 > 0) || (!p_slice_header->collocated_from_l0_flag && p_slice_header->num_ref_idx_l1_active_minus1 > 0)) { p_slice_header->collocated_ref_idx = Parser::ExpGolomb::ReadUe(nalu, offset); if (p_slice_header->slice_type == HEVC_SLICE_TYPE_P || (p_slice_header->slice_type == HEVC_SLICE_TYPE_B && p_slice_header->collocated_from_l0_flag == 1)) { - CHECK_ALLOWED_MAX(p_slice_header->collocated_ref_idx, p_slice_header->num_ref_idx_l0_active_minus1); + CHECK_ALLOWED_MAX("collocated_ref_idx", p_slice_header->collocated_ref_idx, p_slice_header->num_ref_idx_l0_active_minus1); } else { - CHECK_ALLOWED_MAX(p_slice_header->collocated_ref_idx, p_slice_header->num_ref_idx_l1_active_minus1); + CHECK_ALLOWED_MAX("collocated_ref_idx", p_slice_header->collocated_ref_idx, p_slice_header->num_ref_idx_l1_active_minus1); } } } @@ -1781,15 +1796,15 @@ ParserResult HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcS ParsePredWeightTable(p_slice_header, chroma_array_type, nalu, offset); } p_slice_header->five_minus_max_num_merge_cand = Parser::ExpGolomb::ReadUe(nalu, offset); - //CHECK_ALLOWED_MAX(p_slice_header->five_minus_max_num_merge_cand, 4); + //CHECK_ALLOWED_MAX("five_minus_max_num_merge_cand", p_slice_header->five_minus_max_num_merge_cand, 4); } p_slice_header->slice_qp_delta = Parser::ExpGolomb::ReadSe(nalu, offset); if (pps_ptr->pps_slice_chroma_qp_offsets_present_flag) { p_slice_header->slice_cb_qp_offset = Parser::ExpGolomb::ReadSe(nalu, offset); - CHECK_ALLOWED_RANGE(p_slice_header->slice_cb_qp_offset, -12, 12); + CHECK_ALLOWED_RANGE("slice_cb_qp_offset", p_slice_header->slice_cb_qp_offset, -12, 12); p_slice_header->slice_cr_qp_offset = Parser::ExpGolomb::ReadSe(nalu, offset); - CHECK_ALLOWED_RANGE(p_slice_header->slice_cr_qp_offset, -12, 12); + CHECK_ALLOWED_RANGE("slice_cr_qp_offset", p_slice_header->slice_cr_qp_offset, -12, 12); } if (pps_ptr->chroma_qp_offset_list_enabled_flag) { p_slice_header->cu_chroma_qp_offset_enabled_flag = Parser::GetBit(nalu, offset); @@ -1801,9 +1816,9 @@ ParserResult HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcS p_slice_header->slice_deblocking_filter_disabled_flag = Parser::GetBit(nalu, offset); if ( !p_slice_header->slice_deblocking_filter_disabled_flag ) { p_slice_header->slice_beta_offset_div2 = Parser::ExpGolomb::ReadSe(nalu, offset); - CHECK_ALLOWED_RANGE(p_slice_header->slice_beta_offset_div2, -6, 6); + CHECK_ALLOWED_RANGE("slice_beta_offset_div2", p_slice_header->slice_beta_offset_div2, -6, 6); p_slice_header->slice_tc_offset_div2 = Parser::ExpGolomb::ReadSe(nalu, offset); - CHECK_ALLOWED_RANGE(p_slice_header->slice_tc_offset_div2, -6, 6); + CHECK_ALLOWED_RANGE("slice_tc_offset_div2", p_slice_header->slice_tc_offset_div2, -6, 6); } } diff --git a/src/parser/hevc_parser.h b/src/parser/hevc_parser.h index 678965a365..9f0ff27364 100644 --- a/src/parser/hevc_parser.h +++ b/src/parser/hevc_parser.h @@ -163,9 +163,9 @@ protected: /*! \brief Function to parse Video Parameter Set * \param [in] nalu A pointer of uint8_t for the input stream to be parsed * \param [in] size Size of the input stream - * \return No return value + * \return ParserResult */ - void ParseVps(uint8_t *nalu, size_t size); + ParserResult ParseVps(uint8_t *nalu, size_t size); /*! \brief Function to parse Sequence Parameter Set * \param [in] nalu A pointer of uint8_t for the input stream to be parsed @@ -210,9 +210,9 @@ protected: * \param [in] nalu A pointer of uint8_t for the input stream to be parsed * \param [in] size Size of the input stream * \param [in] offset Reference to the offset in the input buffer - * \return No return value + * \return ParserResult */ - void ParseHrdParameters(HevcHrdParameters *hrd, bool common_inf_present_flag, uint32_t max_num_sub_layers_minus1, uint8_t *nalu, size_t size, size_t &offset); + ParserResult ParseHrdParameters(HevcHrdParameters *hrd, bool common_inf_present_flag, uint32_t max_num_sub_layers_minus1, uint8_t *nalu, size_t size, size_t &offset); /*! \brief Function to set the default values to the scaling list * \param [out] sl_ptr A pointer to the scaling list HevcScalingListData diff --git a/src/parser/roc_video_parser.h b/src/parser/roc_video_parser.h index 555af13d7e..0af339a3fd 100644 --- a/src/parser/roc_video_parser.h +++ b/src/parser/roc_video_parser.h @@ -80,21 +80,20 @@ typedef struct { #define INIT_SEI_PAYLOAD_BUF_SIZE 1024 * 1024 // initial SEI payload buffer size, 1 MB #define DECODE_BUF_POOL_EXTENSION 2 -#define CHECK_ALLOWED_RANGE(val, min, max) { \ +#define CHECK_ALLOWED_RANGE(str, val, min, max) { \ if (val < min || val > max) { \ - ERR ("value not in range: " + TOSTR(val) + " allowed (min,max): " + TOSTR(min) + " " + TOSTR(max));\ + ERR (STR(str) + " value not in valid range: " + TOSTR(val) + ", allowed (min,max): " + TOSTR(min) + "," + TOSTR(max));\ return PARSER_OUT_OF_RANGE; \ } \ } -#define CHECK_ALLOWED_MAX(val, max) { \ +#define CHECK_ALLOWED_MAX(str, val, max) { \ if (val > max) { \ - ERR ("value greater than maximum allowed value: " + TOSTR(val) + " max: " + TOSTR(max));\ + ERR (STR(str) + " value greater than maximum allowed value: " + TOSTR(val) + ", max: " + TOSTR(max));\ return PARSER_OUT_OF_RANGE; \ } \ } - enum { kNotUsed = 0, kTopFieldUsedForDecode = 1,