diff --git a/src/parser/avc_parser.cpp b/src/parser/avc_parser.cpp index fd7213fdbf..a9bb26cd3b 100644 --- a/src/parser/avc_parser.cpp +++ b/src/parser/avc_parser.cpp @@ -33,6 +33,7 @@ AvcVideoParser::AvcVideoParser() { curr_has_mmco_5_ = 0; prev_ref_pic_bottom_field_ = 0; curr_ref_pic_bottom_field_ = 0; + max_long_term_frame_idx_ = 0; slice_info_list_.assign(INIT_SLICE_LIST_NUM, {0}); slice_param_list_.assign(INIT_SLICE_LIST_NUM, {0}); @@ -197,16 +198,21 @@ ParserResult AvcVideoParser::ParsePictureData(const uint8_t *p_stream, uint32_t curr_pic_.pic_output_flag = 1; // Annex C. OutputFlag is set to 1 for Annex A streams } + ParserResult ret2; // Reference picture lists construction (8.2.4) if (p_slice_header->slice_type != kAvcSliceTypeI && p_slice_header->slice_type != kAvcSliceTypeSI && p_slice_header->slice_type != kAvcSliceTypeI_7 && p_slice_header->slice_type != kAvcSliceTypeSI_9) { - SetupReflist(&slice_info_list_[num_slices_]); + if ((ret2 = SetupReflist(&slice_info_list_[num_slices_])) != PARSER_OK) { + return ret2; + } } if (num_slices_ == 0) { // Find a free buffer in DPB for the current picture. Due to the current 1-1 mapping of DPB and // decoded buffer pool at VAAP level, we need to get a surface from DPB for the current picture to be // decoded into. - FindFreeBufInDpb(); + if ((ret2 = FindFreeBufInDpb()) != PARSER_OK) { + return ret2; + } } num_slices_++; break; @@ -1712,11 +1718,12 @@ static inline int CompareLongTermPicNumAsc(const void *p_pic_info_1, const void } // 8.2.4 Decoding process for reference picture lists construction -void AvcVideoParser::SetupReflist(AvcSliceInfo *p_slice_info) { +ParserResult AvcVideoParser::SetupReflist(AvcSliceInfo *p_slice_info) { AvcSeqParameterSet *p_sps = &sps_list_[active_sps_id_]; - int max_frame_num = 1 << (p_sps->log2_max_frame_num_minus4 + 4); - int i; + int max_frame_num = 1 << (p_sps->log2_max_frame_num_minus4 + 4); // MaxFrameNum AvcSliceHeader *p_slice_header = &p_slice_info->slice_header; + int max_pic_num = p_slice_header->field_pic_flag ? 2 * max_frame_num : max_frame_num; + int i; memset(p_slice_info->ref_list_0_, 0, sizeof(p_slice_info->ref_list_0_)); memset(p_slice_info->ref_list_1_, 0, sizeof(p_slice_info->ref_list_1_)); @@ -1783,7 +1790,8 @@ void AvcVideoParser::SetupReflist(AvcSliceInfo *p_slice_info) { qsort((void*)&p_slice_info->ref_list_0_[dpb_buffer_.num_short_term], dpb_buffer_.num_long_term, sizeof(AvcPicture), CompareLongTermPicNumAsc); } } else { // 8.2.4.2.2 - std::cout << "Error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Todo: Add P ref field list init." << std::endl; + ERR("P ref field list init not supported yet."); + return PARSER_NOT_IMPLEMENTED; } } else { if (curr_pic_.pic_structure == kFrame) { // 8.2.4.2.3 @@ -1882,20 +1890,133 @@ void AvcVideoParser::SetupReflist(AvcSliceInfo *p_slice_info) { qsort((void*)&p_slice_info->ref_list_1_[num_short_term_smaller + num_short_term_greater], num_long_term, sizeof(AvcPicture), CompareLongTermPicNumAsc); } } else { // 8.2.4.2.4 - std::cout << "Error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Todo: Add B ref field list init." << std::endl; + ERR("B ref field list init not supported yet."); + return PARSER_NOT_IMPLEMENTED; } } // 8.2.4.3 Modification process for reference picture lists if (p_slice_header->ref_pic_list.ref_pic_list_modification_flag_l0 == 1) { - std::cout << "Error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Todo: Added ref list 0 modification support." << std::endl; + AvcPicture *ref_pic_list_x = p_slice_info->ref_list_0_; // RefPicListX + AvcListMod *p_list_mod = p_slice_header->ref_pic_list.modification_l0; + int num_ref_idx_lx_active = p_slice_header->num_ref_idx_l0_active_minus1 + 1; + if (num_ref_idx_lx_active >= AVC_MAX_REF_FRAME_NUM) { + ERR("Can not shift the remaining ref pictures.\n"); + return PARSER_OUT_OF_RANGE; + } + if (ModifiyRefList(ref_pic_list_x, p_list_mod, num_ref_idx_lx_active, p_slice_header) != PARSER_OK) { + return PARSER_FAIL; + } } if (p_slice_header->slice_type == kAvcSliceTypeB || p_slice_header->slice_type == kAvcSliceTypeB_6) { if (p_slice_header->ref_pic_list.ref_pic_list_modification_flag_l1 == 1) { - std::cout << "Error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Todo: Added ref list 1 modification support." << std::endl; + AvcPicture *ref_pic_list_x = p_slice_info->ref_list_1_; // RefPicListX + AvcListMod *p_list_mod = p_slice_header->ref_pic_list.modification_l1; + int num_ref_idx_lx_active = p_slice_header->num_ref_idx_l1_active_minus1 + 1; + if (num_ref_idx_lx_active >= AVC_MAX_REF_FRAME_NUM) { + ERR("Can not shift the remaining ref pictures.\n"); + return PARSER_OUT_OF_RANGE; + } + if (ModifiyRefList(ref_pic_list_x, p_list_mod, num_ref_idx_lx_active, p_slice_header) != PARSER_OK) { + return PARSER_FAIL; + } } } + return PARSER_OK; +} + +ParserResult AvcVideoParser::ModifiyRefList(AvcPicture *ref_pic_list_x, AvcListMod *p_list_mod, int num_ref_idx_lx_active, AvcSliceHeader *p_slice_header) { + AvcSeqParameterSet *p_sps = &sps_list_[active_sps_id_]; + int ref_idx_lx = 0; // refIdxLX + int curr_pic_num = p_slice_header->field_pic_flag ? 2 * p_slice_header->frame_num + 1 : p_slice_header->frame_num; // CurrPicNum + int pic_num_lx_pred = curr_pic_num; // picNumLXPred + int max_frame_num = 1 << (p_sps->log2_max_frame_num_minus4 + 4); // MaxFrameNum + int max_pic_num = p_slice_header->field_pic_flag ? 2 * max_frame_num : max_frame_num; + int i; + + while (p_list_mod->modification_of_pic_nums_idc != 3) { + if (p_list_mod->modification_of_pic_nums_idc < 2) { + // 8.2.4.3.1 Modification process of reference picture lists for short-term reference pictures + int pic_num_lx_no_wrap; // picNumLXNoWrap + if (p_list_mod->modification_of_pic_nums_idc == 0) { + // (8-34) + if (pic_num_lx_pred < (p_list_mod->abs_diff_pic_num_minus1 + 1)) { + pic_num_lx_no_wrap = pic_num_lx_pred - (p_list_mod->abs_diff_pic_num_minus1 + 1) + max_pic_num; + } else { + pic_num_lx_no_wrap = pic_num_lx_pred - (p_list_mod->abs_diff_pic_num_minus1 + 1); + } + } else { + // (8-35) + if ((pic_num_lx_pred + (p_list_mod->abs_diff_pic_num_minus1 + 1)) >= max_pic_num) { + pic_num_lx_no_wrap = pic_num_lx_pred + (p_list_mod->abs_diff_pic_num_minus1 + 1) - max_pic_num; + } else { + pic_num_lx_no_wrap = pic_num_lx_pred + (p_list_mod->abs_diff_pic_num_minus1 + 1); + } + } + // (8-36) + pic_num_lx_pred = pic_num_lx_no_wrap; + int pic_num_lx; // picNumLX + if (pic_num_lx_no_wrap > curr_pic_num) { + pic_num_lx = pic_num_lx_no_wrap - max_pic_num; + } else { + pic_num_lx = pic_num_lx_no_wrap; + } + // (8-37) + // Shift further + for (int c_idx = num_ref_idx_lx_active; c_idx > ref_idx_lx; c_idx--) { + ref_pic_list_x[c_idx] = ref_pic_list_x[c_idx - 1]; + } + // Find short-term reference picture with PicNum equal to pic_num_lx + for (i = 0; i <= num_ref_idx_lx_active; i++) { + if (ref_pic_list_x[i].is_reference == kUsedForShortTerm && ref_pic_list_x[i].pic_num == pic_num_lx) { + break; + } + } + if (i > num_ref_idx_lx_active) { + ERR("Could not find a short-term reference with the modified pic num."); + return PARSER_OUT_OF_RANGE; + } + ref_pic_list_x[ref_idx_lx] = ref_pic_list_x[i]; + ref_idx_lx++; + int n_idx = ref_idx_lx; + for (int c_idx = ref_idx_lx; c_idx <= num_ref_idx_lx_active; c_idx++) { + int pic_num_f = ref_pic_list_x[c_idx].is_reference == kUsedForShortTerm ? ref_pic_list_x[c_idx].pic_num : max_pic_num; + if ( pic_num_f != pic_num_lx) { + ref_pic_list_x[n_idx++] = ref_pic_list_x[c_idx]; + } + } + } else if (p_list_mod->modification_of_pic_nums_idc == 2) { + // 8.2.4.3.2 Modification process of reference picture lists for long-term reference pictures + // (8-38) + // Shift further + for (int c_idx = num_ref_idx_lx_active; c_idx > ref_idx_lx; c_idx--) { + ref_pic_list_x[c_idx] = ref_pic_list_x[c_idx - 1]; + } + // Find long-term reference picture with LongTermPicNum equal to long_term_pic_num + for (i = 0; i <= num_ref_idx_lx_active; i++) { + if (ref_pic_list_x[i].is_reference == kUsedForLongTerm && ref_pic_list_x[i].long_term_pic_num == p_list_mod->long_term_pic_num) { + break; + } + } + if (i > num_ref_idx_lx_active) { + ERR("Could not find long-term reference with the modified long term pic num."); + return PARSER_OUT_OF_RANGE; + } + ref_pic_list_x[ref_idx_lx] = ref_pic_list_x[i]; + ref_idx_lx++; + int n_idx = ref_idx_lx; + for (int c_idx = ref_idx_lx; c_idx <= num_ref_idx_lx_active; c_idx++) { + int long_term_pic_num_f = ref_pic_list_x[c_idx].is_reference == kUsedForLongTerm ? ref_pic_list_x[c_idx].long_term_pic_num : 2 * (max_long_term_frame_idx_ + 1); + if ( long_term_pic_num_f != p_list_mod->long_term_pic_num) { + ref_pic_list_x[n_idx++] = ref_pic_list_x[c_idx]; + } + } + } + p_list_mod = &p_slice_header->ref_pic_list.modification_l0[ref_idx_lx]; + } + + return PARSER_OK; } ParserResult AvcVideoParser::CheckDpbAndOutput() { @@ -1968,6 +2089,7 @@ ParserResult AvcVideoParser::MarkDecodedRefPics() { curr_pic_.is_reference = kUsedForLongTerm; curr_pic_.long_term_frame_idx = 0; dpb_buffer_.num_long_term = 0; + max_long_term_frame_idx_ = 0; } else { curr_pic_.is_reference = kUsedForShortTerm; dpb_buffer_.num_short_term = 0; @@ -1975,7 +2097,8 @@ ParserResult AvcVideoParser::MarkDecodedRefPics() { } else { if (p_slice_header->dec_ref_pic_marking.adaptive_ref_pic_marking_mode_flag == 1) { // 8.2.5.4 Adaptive memory control decoded reference picture marking process - std::cout << "Error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Todo: 8.2.5.4 ............" << std::endl; + ERR("8.2.5.4 Adaptive memory control decoded reference picture marking process not supported yet."); + return PARSER_NOT_IMPLEMENTED; } else { // 8.2.5.3 Sliding window decoded reference picture marking process curr_pic_.is_reference = kUsedForShortTerm; // 8.2.5.1: 3. diff --git a/src/parser/avc_parser.h b/src/parser/avc_parser.h index 45ae8208b1..b35e714e20 100644 --- a/src/parser/avc_parser.h +++ b/src/parser/avc_parser.h @@ -123,6 +123,7 @@ protected: int curr_has_mmco_5_; int prev_ref_pic_bottom_field_; int curr_ref_pic_bottom_field_; + int max_long_term_frame_idx_; // MaxLongTermFrameIdx // DPB AvcPicture curr_pic_; @@ -218,8 +219,18 @@ protected: /*! \brief Function to set up the reference picutre lists for each slice. 8.2.4. * \param [in] p_slice_info Poiner to slice info struct + * \return ParserResult */ - void SetupReflist(AvcSliceInfo *p_slice_info); + ParserResult SetupReflist(AvcSliceInfo *p_slice_info); + + /*! \brief Function to modify a reference picture list. + * \param [in/out] ref_pic_list_x The reference picture list to be modified + * \param [in] p_list_mod Modification instructions + * \param [in] num_ref_idx_lx_active Reference list size + * \param [in] p_slice_header Pointer to slice header struct + * \return ParserResult + */ + ParserResult ModifiyRefList(AvcPicture *ref_pic_list_x, AvcListMod *p_list_mod, int num_ref_idx_lx_active, AvcSliceHeader *p_slice_header); /*! \brief Function to check the fullness of DPB and output picture if needed. * \return ParserResult