From 031c28105cccd4bae622f65be6286318b8acd7ee Mon Sep 17 00:00:00 2001 From: jeffqjiangNew <142832361+jeffqjiangNew@users.noreply.github.com> Date: Wed, 31 Jan 2024 09:10:41 -0500 Subject: [PATCH] * rocDecode/AVC: Fixed a few issues with P frame. (#212) - Moved decoded reference picture marking after decode picture submission, according to the spec. - Fixed several errors in the decoding process. - Added two debug functions to log out DPB content and VAAPI buffer info. - P frames look good now. [ROCm/rocdecode commit: 90cddfe655bbc1fd5b4f499b52c3c54d71f3e2a3] --- projects/rocdecode/src/parser/avc_parser.cpp | 114 ++++++++++++++++--- projects/rocdecode/src/parser/avc_parser.h | 25 +++- 2 files changed, 118 insertions(+), 21 deletions(-) diff --git a/projects/rocdecode/src/parser/avc_parser.cpp b/projects/rocdecode/src/parser/avc_parser.cpp index 8be07654a0..0bd3294edd 100644 --- a/projects/rocdecode/src/parser/avc_parser.cpp +++ b/projects/rocdecode/src/parser/avc_parser.cpp @@ -33,6 +33,9 @@ AvcVideoParser::AvcVideoParser() { curr_has_mmco_5_ = 0; prev_ref_pic_bottom_field_ = 0; curr_ref_pic_bottom_field_ = 0; + + memset(&curr_pic_, 0, sizeof(AvcPicture)); + InitDpb(); } AvcVideoParser::~AvcVideoParser() { @@ -67,6 +70,9 @@ rocDecStatus AvcVideoParser::ParseVideoData(RocdecSourceDataPacket *p_data) { return ROCDEC_RUNTIME_ERROR; } + // Decoded reference picture marking + MarkDecodedRefPics(); + pic_count_++; } else if (!(p_data->flags & ROCDEC_PKT_ENDOFSTREAM)) { // If no payload and EOS is not set, treated as invalid. @@ -159,8 +165,8 @@ ParserResult AvcVideoParser::ParsePictureData(const uint8_t *p_stream, uint32_t SetupReflist(); } - // Decoded reference picture marking - MarkDecodedRefPic(); + // Find a free buffer in DPB for the current picture + FindFreeBufInDpb(); } slice_num_++; break; @@ -370,6 +376,8 @@ ParserResult AvcVideoParser::SendPicForDecode() { p_pic_param->ref_frames[buf_index].flags |= p_ref_pic->pic_structure == kBottomField ? RocdecAvcPicture_FLAGS_BOTTOM_FIELD : RocdecAvcPicture_FLAGS_TOP_FIELD; } p_pic_param->ref_frames[buf_index].flags |= p_ref_pic->is_reference == kUsedForShortTerm ? RocdecAvcPicture_FLAGS_SHORT_TERM_REFERENCE : RocdecAvcPicture_FLAGS_LONG_TERM_REFERENCE; + p_pic_param->ref_frames[buf_index].top_field_order_cnt = p_ref_pic->top_field_order_cnt; + p_pic_param->ref_frames[buf_index].bottom_field_order_cnt = p_ref_pic->bottom_field_order_cnt; buf_index++; } } @@ -515,6 +523,10 @@ ParserResult AvcVideoParser::SendPicForDecode() { } } +#if DBGINFO + PrintVappiBufInfo(); +#endif // DBGINFO + if (pfn_decode_picture_cb_(parser_params_.user_data, &dec_pic_params_) == 0) { ERR("Decode error occurred."); return PARSER_FAIL; @@ -1399,6 +1411,18 @@ bool AvcVideoParser::MoreRbspData(uint8_t *p_stream, size_t stream_size_in_byte, return more_rbsp_bits; } +void AvcVideoParser::InitDpb() { + memset(&dpb_buffer_, 0, sizeof(DecodedPictureBuffer)); + for (int i = 0; i < AVC_MAX_DPB_FRAMES; i++) { + dpb_buffer_.frame_buffer_list[i].pic_idx = i; + dpb_buffer_.frame_buffer_list[i].is_reference = kUnusedForReference; + dpb_buffer_.frame_buffer_list[i].use_status = 0; + } + dpb_buffer_.dpb_size = 0; + dpb_buffer_.num_short_term = 0; + dpb_buffer_.num_long_term = 0; +} + // 8.2.1 void AvcVideoParser::CalculateCurrPoc() { AvcSeqParameterSet *p_sps = &sps_list_[active_sps_id_]; @@ -1589,7 +1613,6 @@ void AvcVideoParser::SetupReflist() { AvcPicture *p_ref_pic = &dpb_buffer_.frame_buffer_list[i]; if (p_ref_pic->is_reference == kUsedForShortTerm) { - p_ref_pic->frame_num = p_ref_pic->frame_num; // Eq. 8-27 if (p_ref_pic->frame_num > curr_pic_.frame_num) { p_ref_pic->frame_num_wrap = p_ref_pic->frame_num - max_frame_num; @@ -1605,7 +1628,7 @@ void AvcVideoParser::SetupReflist() { p_ref_pic->pic_num = 2 * p_ref_pic->frame_num_wrap; // Eq. 8-31 } } else if (p_ref_pic->is_reference == kUsedForLongTerm) { - // Note: Todo: assign long_term_frame_idx in MarkDecodedRefPic() + // Note: Todo: assign long_term_frame_idx in MarkDecodedRefPics() if (curr_pic_.pic_structure == kFrame) { p_ref_pic->long_term_pic_num = p_ref_pic->long_term_frame_idx; // Eq. 8-29 } else if (((curr_pic_.pic_structure == kTopField) && (p_ref_pic->pic_structure == kTopField)) || ((curr_pic_.pic_structure == kBottomField) && (p_ref_pic->pic_structure == kBottomField))) { @@ -1663,7 +1686,30 @@ void AvcVideoParser::SetupReflist() { } } -ParserResult AvcVideoParser::MarkDecodedRefPic() { +ParserResult AvcVideoParser::FindFreeBufInDpb() { + int i; + for (i = 0; i < AVC_MAX_DPB_FRAMES; i++) { + if (dpb_buffer_.frame_buffer_list[i].use_status == 0) { + break; + } + } + if (i < AVC_MAX_DPB_FRAMES) { + curr_pic_.pic_idx = dpb_buffer_.frame_buffer_list[i].pic_idx; + if (curr_pic_.pic_structure == kFrame) { + curr_pic_.use_status = 3; + } else if (curr_pic_.pic_structure == kTopField) { + curr_pic_.use_status = 1; + } else { + curr_pic_.use_status = 2; + } + } else { + ERR("Could not find any free frame buffer in DPB."); + return PARSER_FAIL; + } + return PARSER_OK; +} + +ParserResult AvcVideoParser::MarkDecodedRefPics() { AvcSeqParameterSet *p_sps = &sps_list_[active_sps_id_]; AvcSliceHeader *p_slice_header = &slice_header_0_; int i; @@ -1676,6 +1722,7 @@ ParserResult AvcVideoParser::MarkDecodedRefPic() { // Mark all reference pictures as "unused for reference for (i = 0; i < AVC_MAX_DPB_FRAMES; i++) { dpb_buffer_.frame_buffer_list[i].is_reference = kUnusedForReference; + dpb_buffer_.frame_buffer_list[i].use_status = 0; } if (p_slice_header->dec_ref_pic_marking.long_term_reference_flag) { curr_pic_.is_reference = kUsedForLongTerm; @@ -1715,22 +1762,15 @@ ParserResult AvcVideoParser::MarkDecodedRefPic() { } } - // Look for an empty frame buffer in DPB and add the current ref picture to DPB + // Add the current ref picture to DPB. + // We have reserved a spot in DPB already. for (i = 0; i < AVC_MAX_DPB_FRAMES; i++) { - if (dpb_buffer_.frame_buffer_list[i].use_status == 0) { + if (dpb_buffer_.frame_buffer_list[i].pic_idx == curr_pic_.pic_idx) { break; } } if (i < AVC_MAX_DPB_FRAMES) { - AvcPicture *frame_buf = &dpb_buffer_.frame_buffer_list[i]; - *frame_buf = curr_pic_; - if (curr_pic_.pic_structure == kFrame) { - frame_buf->use_status = 3; - } else if (curr_pic_.pic_structure == kTopField) { - frame_buf->use_status = 1; - } else { - frame_buf->use_status = 2; - } + dpb_buffer_.frame_buffer_list[i] = curr_pic_; if (curr_pic_.is_reference == kUsedForShortTerm) { dpb_buffer_.num_short_term++; } else if (curr_pic_.is_reference == kUsedForLongTerm) { @@ -1740,10 +1780,13 @@ ParserResult AvcVideoParser::MarkDecodedRefPic() { return PARSER_FAIL; } } else { - ERR("Could not find any free frame buffer in DPB."); + ERR("Could not find the reserved frame buffer for the current picture in DPB."); return PARSER_FAIL; } +#if DBGINFO + PrintDpb(); +#endif // DBGINFO return PARSER_OK; } @@ -1958,4 +2001,41 @@ void AvcVideoParser::PrintSliceHeader(AvcSliceHeader *p_slice_header) { MSG("slice_beta_offset_div2 = " << p_slice_header->slice_beta_offset_div2); MSG("slice_group_change_cycle = " << p_slice_header->slice_group_change_cycle); } + +void AvcVideoParser::PrintDpb() { + uint32_t i; + + MSG("======================="); + MSG("DPB buffer content: "); + MSG("======================="); + MSG("dpb_size = " << dpb_buffer_.dpb_size); + MSG("num_short_term = " << dpb_buffer_.num_short_term); + MSG("num_long_term = " << dpb_buffer_.num_long_term); + MSG("Frame buffer store:"); + for (i = 0; i < AVC_MAX_DPB_FRAMES; i++) { + AvcPicture *p_buf = &dpb_buffer_.frame_buffer_list[i]; + MSG("Frame buffer " << i << ": pic_idx = " << p_buf->pic_idx << ", pic_structure = " << p_buf->pic_structure << ", pic_order_cnt = " << p_buf->pic_order_cnt << ", top_field_order_cnt = " << p_buf->top_field_order_cnt << ", bottom_field_order_cnt = " << p_buf->bottom_field_order_cnt << ", frame_num = " << p_buf->frame_num << ", frame_num_wrap = " << p_buf->frame_num_wrap << ", pic_num = " << p_buf->pic_num << ", long_term_pic_num = " << p_buf->long_term_pic_num << ", long_term_frame_idx = " << p_buf->long_term_frame_idx << ", is_reference = " << p_buf->is_reference << ", use_status = " << p_buf->use_status); + } + MSG(""); +} + +void AvcVideoParser::PrintVappiBufInfo() { + RocdecAvcPicParams *p_pic_param = &dec_pic_params_.pic_params.avc; + MSG("======================="); + MSG("VAAPI Buffer Info: "); + MSG("======================="); + MSG("Current buffer:"); + //MSG("pic_idx = " << p_pic_param->curr_pic.pic_idx << ", frame_idx = " << p_pic_param->curr_pic.frame_idx << ", top_field_order_cnt = " << p_pic_param->curr_pic.top_field_order_cnt << ", bottom_field_order_cnt = " << std::dec << p_pic_param->curr_pic.bottom_field_order_cnt << ", flags = 0x" << std::hex << p_pic_param->curr_pic.flags); + MSG_NO_NEWLINE("pic_idx = " << p_pic_param->curr_pic.pic_idx << ", frame_idx = " << p_pic_param->curr_pic.frame_idx << ", top_field_order_cnt = " << p_pic_param->curr_pic.top_field_order_cnt << ", bottom_field_order_cnt = " << std::dec << p_pic_param->curr_pic.bottom_field_order_cnt); + MSG(", flags = 0x" << std::hex << p_pic_param->curr_pic.flags); + + MSG("Reference pictures:"); + for (int i = 0; i < AVC_MAX_DPB_FRAMES; i++) { + RocdecAvcPicture *p_ref_pic = &p_pic_param->ref_frames[i]; + //MSG("Ref pic " << i << ": " << "pic_idx = " << p_ref_pic->pic_idx << ", frame_idx = " << p_ref_pic->frame_idx << ", top_field_order_cnt = " << p_ref_pic->top_field_order_cnt << ", bottom_field_order_cnt = " << p_ref_pic->bottom_field_order_cnt << ", flags = 0x" << std::hex << p_ref_pic->flags); + MSG_NO_NEWLINE("Ref pic " << i << ": " << "pic_idx = " << p_ref_pic->pic_idx << ", frame_idx = " << p_ref_pic->frame_idx << ", top_field_order_cnt = " << p_ref_pic->top_field_order_cnt << ", bottom_field_order_cnt = " << p_ref_pic->bottom_field_order_cnt); + MSG(", flags = 0x" << std::hex << p_ref_pic->flags); + } + MSG(std::dec); +} #endif // DBGINFO \ No newline at end of file diff --git a/projects/rocdecode/src/parser/avc_parser.h b/projects/rocdecode/src/parser/avc_parser.h index efdb4fcaa9..dc55ef792b 100644 --- a/projects/rocdecode/src/parser/avc_parser.h +++ b/projects/rocdecode/src/parser/avc_parser.h @@ -185,17 +185,26 @@ protected: */ bool MoreRbspData(uint8_t *p_stream, size_t stream_size_in_byte, size_t bit_offset); - /*! \brief Function to calculate picture order count of the current slice + /*! \brief Function to initialize DPB buffer. + */ + void InitDpb(); + + /*! \brief Function to calculate picture order count of the current slice. 8.2.1. */ void CalculateCurrPoc(); - /*! \brief Function to set up the reference picutre lists. + /*! \brief Function to set up the reference picutre lists. 8.2.4. */ void SetupReflist(); - /*! \brief Function to mark decoded reference picture in DPB + /*! \brief Function to find a free buffer in DPB for the current picture */ - ParserResult MarkDecodedRefPic(); + ParserResult FindFreeBufInDpb(); + + /*! \brief Function to mark decoded reference picture in DPB. 8.2.5. This step is + * performed after the current picture is decoded. + */ + ParserResult MarkDecodedRefPics(); #if DBGINFO /*! \brief Function to log out parsed SPS content for debug. @@ -209,5 +218,13 @@ protected: /*! \brief Function to log out parsed slice header content for debug. */ void PrintSliceHeader(AvcSliceHeader *p_slice_header); + + /*! \brief Function to log out decoded picture buffer content + */ + void PrintDpb(); + + /*! \brief Function to log out buffer info in VAAPI decode params + */ + void PrintVappiBufInfo(); #endif // DBGINFO }; \ No newline at end of file