* 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: 90cddfe655]
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
};
|
||||
Reference in New Issue
Block a user