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