diff --git a/src/parser/avc_parser.cpp b/src/parser/avc_parser.cpp
index 11c1d5b07b..502f5d1b98 100644
--- a/src/parser/avc_parser.cpp
+++ b/src/parser/avc_parser.cpp
@@ -53,6 +53,9 @@ rocDecStatus AvcVideoParser::UnInitialize() {
rocDecStatus AvcVideoParser::ParseVideoData(RocdecSourceDataPacket *p_data) {
if (p_data->payload && p_data->payload_size) {
+ // Clear DPB output/display buffer number
+ dpb_buffer_.num_output_pics = 0;
+
if (ParsePictureData(p_data->payload, p_data->payload_size) != PARSER_OK) {
ERR(STR("Parser failed!"));
return ROCDEC_RUNTIME_ERROR;
@@ -72,8 +75,17 @@ rocDecStatus AvcVideoParser::ParseVideoData(RocdecSourceDataPacket *p_data) {
return ROCDEC_RUNTIME_ERROR;
}
- // Decoded reference picture marking
- MarkDecodedRefPics();
+ // Decoded reference picture marking (8.2.5) for later pictures
+ if (MarkDecodedRefPics() != PARSER_OK) {
+ return ROCDEC_RUNTIME_ERROR;
+ }
+
+ if (InsertCurrPicIntoDpb() != PARSER_OK) {
+ return ROCDEC_RUNTIME_ERROR;
+ }
+ if (CheckDpbAndOutput() != PARSER_OK) {
+ return ROCDEC_RUNTIME_ERROR;
+ }
pic_count_++;
} else if (!(p_data->flags & ROCDEC_PKT_ENDOFSTREAM)) {
@@ -81,6 +93,12 @@ rocDecStatus AvcVideoParser::ParseVideoData(RocdecSourceDataPacket *p_data) {
return ROCDEC_INVALID_PARAMETER;
}
+ if (p_data->flags & ROCDEC_PKT_ENDOFSTREAM) {
+ if (FlushDpb() != PARSER_OK) {
+ return ROCDEC_RUNTIME_ERROR;
+ }
+ }
+
return ROCDEC_SUCCESS;
}
@@ -97,6 +115,7 @@ ParserResult AvcVideoParser::ParsePictureData(const uint8_t *p_stream, uint32_t
num_slices_ = 0;
sei_message_count_ = 0;
sei_payload_size_ = 0;
+ curr_pic_ = {0};
do {
ret = GetNalUnit();
@@ -170,9 +189,10 @@ ParserResult AvcVideoParser::ParsePictureData(const uint8_t *p_stream, uint32_t
curr_pic_.pic_structure = kFrame;
}
curr_pic_.frame_num = p_slice_header->frame_num;
+ curr_pic_.pic_output_flag = 1; // Annex C. OutputFlag is set to 1 for Annex A streams
}
- // Set up reference picture list
+ // 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_]);
}
@@ -558,6 +578,20 @@ ParserResult AvcVideoParser::SendPicForDecode() {
}
}
+ParserResult AvcVideoParser::OutputDecodedPictures() {
+ RocdecParserDispInfo disp_info = {0};
+ disp_info.progressive_frame = sps_list_[active_sps_id_].frame_mbs_only_flag;
+ disp_info.top_field_first = slice_info_list_[0].slice_header.bottom_field_flag && (pic_count_ & 1);
+
+ for (int i = 0; i < dpb_buffer_.num_output_pics; i++) {
+ disp_info.picture_index = dpb_buffer_.frame_buffer_list[dpb_buffer_.output_pic_list[i]].pic_idx;
+ pfn_display_picture_cb_(parser_params_.user_data, &disp_info);
+ }
+
+ dpb_buffer_.num_output_pics = 0;
+ return PARSER_OK;
+}
+
AvcNalUnitHeader AvcVideoParser::ParseNalUnitHeader(uint8_t header_byte) {
size_t bit_offset = 0;
AvcNalUnitHeader nal_header;
@@ -1015,7 +1049,7 @@ ParserResult AvcVideoParser::ParseSliceHeader(uint8_t *p_stream, size_t stream_s
active_sps_id_ = p_pps->seq_parameter_set_id;
p_sps = &sps_list_[active_sps_id_];
// Re-set DPB size.
- dpb_buffer_.dpb_size = p_sps->max_num_ref_frames + 1;
+ dpb_buffer_.dpb_size = p_sps->max_num_ref_frames + 2;
dpb_buffer_.dpb_size = dpb_buffer_.dpb_size > AVC_MAX_DPB_FRAMES ? AVC_MAX_DPB_FRAMES : dpb_buffer_.dpb_size;
new_sps_activated_ = true; // Note: clear this flag after the actions are taken.
}
@@ -1029,7 +1063,7 @@ ParserResult AvcVideoParser::ParseSliceHeader(uint8_t *p_stream, size_t stream_s
pic_height_ = curr_pic_height;
// Take care of the case where a new SPS replaces the old SPS with the same id but with different dimensions
// Re-set DPB size.
- dpb_buffer_.dpb_size = p_sps->max_num_ref_frames + 1;
+ dpb_buffer_.dpb_size = p_sps->max_num_ref_frames + 2;
dpb_buffer_.dpb_size = dpb_buffer_.dpb_size > AVC_MAX_DPB_FRAMES ? AVC_MAX_DPB_FRAMES : dpb_buffer_.dpb_size;
new_sps_activated_ = true; // Note: clear this flag after the actions are taken.
}
@@ -1267,10 +1301,6 @@ ParserResult AvcVideoParser::ParseSliceHeader(uint8_t *p_stream, size_t stream_s
p_slice_header->slice_group_change_cycle = Parser::ReadBits(p_stream, offset, size);
}
-#if DBGINFO
- PrintSliceHeader(p_slice_header);
-#endif // DBGINFO
-
return PARSER_OK;
}
@@ -1440,13 +1470,17 @@ void AvcVideoParser::InitDpb() {
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_.frame_buffer_list[i].pic_output_flag = 0;
}
dpb_buffer_.dpb_size = 0;
+ dpb_buffer_.dpb_fullness = 0;
dpb_buffer_.num_short_term = 0;
dpb_buffer_.num_long_term = 0;
+ dpb_buffer_.num_pics_needed_for_output = 0;
+ dpb_buffer_.num_output_pics = 0;
}
-// 8.2.1
+// 8.2.1 Decoding process for picture order count
void AvcVideoParser::CalculateCurrPoc() {
AvcSeqParameterSet *p_sps = &sps_list_[active_sps_id_];
AvcSliceHeader *p_slice_header = &slice_info_list_[0].slice_header;
@@ -1649,6 +1683,7 @@ 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) {
AvcSeqParameterSet *p_sps = &sps_list_[active_sps_id_];
int max_frame_num = 1 << (p_sps->log2_max_frame_num_minus4 + 4);
@@ -1835,14 +1870,36 @@ void AvcVideoParser::SetupReflist(AvcSliceInfo *p_slice_info) {
}
}
+ParserResult AvcVideoParser::CheckDpbAndOutput() {
+ // If DPB is full, bump one picture out
+ if (dpb_buffer_.dpb_fullness == dpb_buffer_.dpb_size) {
+ if (BumpPicFromDpb() != PARSER_OK) {
+ return PARSER_FAIL;
+ }
+ }
+ // Output decoded pictures from DPB if any are ready
+ if (pfn_display_picture_cb_ && dpb_buffer_.num_output_pics > 0) {
+ if (OutputDecodedPictures() != PARSER_OK) {
+ return PARSER_FAIL;
+ }
+ }
+ return PARSER_OK;
+}
+
ParserResult AvcVideoParser::FindFreeBufInDpb() {
int i;
- for (i = 0; i < AVC_MAX_DPB_FRAMES; i++) {
+ if (dpb_buffer_.dpb_fullness == dpb_buffer_.dpb_size) {
+ if (BumpPicFromDpb() != PARSER_OK) {
+ return PARSER_FAIL;
+ }
+ }
+
+ for (i = 0; i < dpb_buffer_.dpb_size; i++) {
if (dpb_buffer_.frame_buffer_list[i].use_status == 0) {
break;
}
}
- if (i < AVC_MAX_DPB_FRAMES) {
+ if (i < dpb_buffer_.dpb_size) {
curr_pic_.pic_idx = dpb_buffer_.frame_buffer_list[i].pic_idx;
if (curr_pic_.pic_structure == kFrame) {
curr_pic_.use_status = 3;
@@ -1858,6 +1915,7 @@ ParserResult AvcVideoParser::FindFreeBufInDpb() {
return PARSER_OK;
}
+// 8.2.5 Decoded reference picture marking process
ParserResult AvcVideoParser::MarkDecodedRefPics() {
AvcSeqParameterSet *p_sps = &sps_list_[active_sps_id_];
AvcSliceHeader *p_slice_header = &slice_info_list_[0].slice_header;
@@ -1871,8 +1929,13 @@ ParserResult AvcVideoParser::MarkDecodedRefPics() {
// 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;
}
+ // Output the remaining picutres in DPB
+ if (FlushDpb() != PARSER_OK) {
+ return PARSER_FAIL;
+ }
+
+ dpb_buffer_.dpb_fullness = 0;
if (p_slice_header->dec_ref_pic_marking.long_term_reference_flag) {
curr_pic_.is_reference = kUsedForLongTerm;
curr_pic_.long_term_frame_idx = 0;
@@ -1883,14 +1946,16 @@ 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;
- } else { // 8.2.5.3
+ } else {
+ // 8.2.5.3 Sliding window decoded reference picture marking process
curr_pic_.is_reference = kUsedForShortTerm; // 8.2.5.1: 3.
if (dpb_buffer_.num_short_term + dpb_buffer_.num_long_term == p_sps->max_num_ref_frames) {
int32_t min_frame_num_wrap = 0xFFFFFF; // more than the largest possible value of FrameNumWrap (2 ^ 16)
int min_index = AVC_MAX_DPB_FRAMES;
- for (i = 0; i < AVC_MAX_DPB_FRAMES; i++) {
+ for (i = 0; i < dpb_buffer_.dpb_size; i++) {
if (dpb_buffer_.frame_buffer_list[i].is_reference == kUsedForShortTerm) {
if (dpb_buffer_.frame_buffer_list[i].frame_num_wrap < min_frame_num_wrap) {
min_frame_num_wrap = dpb_buffer_.frame_buffer_list[i].frame_num_wrap;
@@ -1898,10 +1963,8 @@ ParserResult AvcVideoParser::MarkDecodedRefPics() {
}
}
}
- if (min_index < AVC_MAX_DPB_FRAMES) {
+ if (min_index < dpb_buffer_.dpb_size) {
dpb_buffer_.frame_buffer_list[min_index].is_reference = kUnusedForReference;
- // Todo: implement output policy
- dpb_buffer_.frame_buffer_list[min_index].use_status = 0;
} else {
ERR("Could not find any short term ref picture.");
return PARSER_FAIL;
@@ -1911,22 +1974,104 @@ ParserResult AvcVideoParser::MarkDecodedRefPics() {
}
}
- // Add the current ref picture to DPB.
+ return PARSER_OK;
+}
+
+ParserResult AvcVideoParser::BumpPicFromDpb() {
+ int32_t min_poc_no_ref = 0x7FFFFFFF; // largest possible POC value 2^31 - 1
+ int32_t min_poc_ref = 0x7FFFFFFF; // largest possible POC value 2^31 - 1
+ int min_poc_pic_idx_no_ref = AVC_MAX_DPB_FRAMES;
+ int min_poc_pic_idx_ref = AVC_MAX_DPB_FRAMES;
+ int i;
+
+ for (i = 0; i < dpb_buffer_.dpb_size; i++) {
+ if (dpb_buffer_.frame_buffer_list[i].use_status) {
+ if (dpb_buffer_.frame_buffer_list[i].is_reference) {
+ if (dpb_buffer_.frame_buffer_list[i].pic_order_cnt < min_poc_ref && dpb_buffer_.frame_buffer_list[i].pic_output_flag) {
+ // Find the min-poc ref pic that has not been output yet.
+ min_poc_ref = dpb_buffer_.frame_buffer_list[i].pic_order_cnt;
+ min_poc_pic_idx_ref = i;
+ }
+ } else {
+ if (dpb_buffer_.frame_buffer_list[i].pic_order_cnt < min_poc_no_ref) {
+ min_poc_no_ref = dpb_buffer_.frame_buffer_list[i].pic_order_cnt;
+ min_poc_pic_idx_no_ref = i;
+ }
+ }
+ }
+ }
+ if (min_poc_pic_idx_no_ref >= dpb_buffer_.dpb_size) {
+ ERR("Error! Could not find a non-reference buffer to bump.");
+ return PARSER_OUT_OF_RANGE;
+ }
+
+ // Output any ref pics before (lower POC) the non-ref pic to be bumped out.
+ while (min_poc_ref < min_poc_no_ref) {
+ dpb_buffer_.frame_buffer_list[min_poc_pic_idx_ref].pic_output_flag = 0;
+ if (dpb_buffer_.num_pics_needed_for_output > 0) {
+ dpb_buffer_.num_pics_needed_for_output--;
+ // Insert into output/display picture list
+ if (dpb_buffer_.num_output_pics >= AVC_MAX_DPB_FRAMES) {
+ ERR("Error! DPB output buffer list overflow!");
+ return PARSER_OUT_OF_RANGE;
+ } else {
+ dpb_buffer_.output_pic_list[dpb_buffer_.num_output_pics] = min_poc_pic_idx_ref;
+ dpb_buffer_.num_output_pics++;
+ }
+ }
+ min_poc_ref = 0x7FFFFFFF;
+ min_poc_pic_idx_ref = AVC_MAX_DPB_FRAMES;
+ for (i = 0; i < dpb_buffer_.dpb_size; i++) {
+ if (dpb_buffer_.frame_buffer_list[i].pic_output_flag && dpb_buffer_.frame_buffer_list[i].use_status && dpb_buffer_.frame_buffer_list[i].is_reference && dpb_buffer_.frame_buffer_list[i].pic_order_cnt < min_poc_ref) {
+ min_poc_ref = dpb_buffer_.frame_buffer_list[i].pic_order_cnt;
+ min_poc_pic_idx_ref = i;
+ }
+ }
+ }
+
+ // Mark as "not needed for output"
+ if (dpb_buffer_.frame_buffer_list[min_poc_pic_idx_no_ref].pic_output_flag) {
+ dpb_buffer_.frame_buffer_list[min_poc_pic_idx_no_ref].pic_output_flag = 0;
+ if (dpb_buffer_.num_pics_needed_for_output > 0) {
+ dpb_buffer_.num_pics_needed_for_output--;
+ }
+
+ // Insert into output/display picture list
+ if (dpb_buffer_.num_output_pics >= AVC_MAX_DPB_FRAMES) {
+ ERR("Error! DPB output buffer list overflow!");
+ return PARSER_OUT_OF_RANGE;
+ } else {
+ dpb_buffer_.output_pic_list[dpb_buffer_.num_output_pics] = min_poc_pic_idx_no_ref;
+ dpb_buffer_.num_output_pics++;
+ }
+ }
+ // Remove it from DPB.
+ dpb_buffer_.frame_buffer_list[min_poc_pic_idx_no_ref].use_status = 0;
+ if (dpb_buffer_.dpb_fullness > 0 ) {
+ dpb_buffer_.dpb_fullness--;
+ }
+
+ return PARSER_OK;
+}
+
+ParserResult AvcVideoParser::InsertCurrPicIntoDpb() {
+ int i;
// We have reserved a spot in DPB already.
- for (i = 0; i < AVC_MAX_DPB_FRAMES; i++) {
+ for (i = 0; i < dpb_buffer_.dpb_size; i++) {
if (dpb_buffer_.frame_buffer_list[i].pic_idx == curr_pic_.pic_idx) {
break;
}
}
- if (i < AVC_MAX_DPB_FRAMES) {
+ if (i < dpb_buffer_.dpb_size) {
dpb_buffer_.frame_buffer_list[i] = curr_pic_;
+ if (dpb_buffer_.frame_buffer_list[i].pic_output_flag) {
+ dpb_buffer_.num_pics_needed_for_output++;
+ }
+ dpb_buffer_.dpb_fullness++;
if (curr_pic_.is_reference == kUsedForShortTerm) {
dpb_buffer_.num_short_term++;
} else if (curr_pic_.is_reference == kUsedForLongTerm) {
dpb_buffer_.num_long_term++;
- } else {
- ERR("Incorrect ref type.");
- return PARSER_FAIL;
}
} else {
ERR("Could not find the reserved frame buffer for the current picture in DPB.");
@@ -1939,6 +2084,27 @@ ParserResult AvcVideoParser::MarkDecodedRefPics() {
return PARSER_OK;
}
+ParserResult AvcVideoParser::FlushDpb() {
+ if (dpb_buffer_.num_pics_needed_for_output) {
+ // Mark all reference pictures as "unused for reference
+ for (int i = 0; i < AVC_MAX_DPB_FRAMES; i++) {
+ dpb_buffer_.frame_buffer_list[i].is_reference = kUnusedForReference;
+ }
+ // Bump the remaining pictures
+ while (dpb_buffer_.num_pics_needed_for_output) {
+ if (BumpPicFromDpb() != PARSER_OK) {
+ return PARSER_FAIL;
+ }
+ }
+ if (pfn_display_picture_cb_ && dpb_buffer_.num_output_pics > 0) {
+ if (OutputDecodedPictures() != PARSER_OK) {
+ return PARSER_FAIL;
+ }
+ }
+ }
+ return PARSER_OK;
+}
+
#if DBGINFO
void AvcVideoParser::PrintSps(AvcSeqParameterSet *p_sps) {
uint32_t i, j;
@@ -2160,10 +2326,18 @@ void AvcVideoParser::PrintDpb() {
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("num_pics_needed_for_output = " << dpb_buffer_.num_pics_needed_for_output);
+ MSG("dpb_fullness = " << dpb_buffer_.dpb_fullness);
+ MSG("num_output_pics = " << dpb_buffer_.num_output_pics);
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("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 << ", pic_output_flag = " << p_buf->pic_output_flag);
+ }
+ MSG("");
+ MSG("output_pic_list:");
+ for (i = 0; i < dpb_buffer_.num_output_pics; i++) {
+ MSG_NO_NEWLINE(dpb_buffer_.output_pic_list[i] << ", ");
}
MSG("");
}
@@ -2174,17 +2348,16 @@ void AvcVideoParser::PrintVappiBufInfo() {
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(std::dec);
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_NO_NEWLINE(std::dec);
}
- MSG(std::dec);
}
#endif // DBGINFO
\ No newline at end of file
diff --git a/src/parser/avc_parser.h b/src/parser/avc_parser.h
index 1a07408249..a0b82ad225 100644
--- a/src/parser/avc_parser.h
+++ b/src/parser/avc_parser.h
@@ -71,6 +71,7 @@ public:
uint32_t long_term_frame_idx; // LongTermFrameIdx: long term reference frame/field identifier
uint32_t is_reference;
uint32_t use_status; // 0 = empty; 1 = top used; 2 = bottom used; 3 = both fields or frame used
+ uint32_t pic_output_flag; // OutputFlag
} AvcPicture;
protected:
@@ -97,6 +98,10 @@ protected:
uint32_t num_short_term; // numShortTerm;
uint32_t num_long_term; // numLongTerm;
AvcPicture frame_buffer_list[AVC_MAX_DPB_FRAMES];
+ uint32_t num_pics_needed_for_output; // number of pictures in DPB that need to be output
+ uint32_t dpb_fullness; // number of pictures in DPB
+ uint32_t num_output_pics; // number of pictures that are output after the decode call
+ uint32_t output_pic_list[AVC_MAX_DPB_FRAMES]; // sorted output picuture index to frame_buffer_list[]
} DecodedPictureBuffer;
AvcNalUnitHeader nal_unit_header_;
@@ -134,6 +139,11 @@ protected:
*/
ParserResult SendPicForDecode();
+ /*! \brief Function to output decoded pictures from DPB for post-processing.
+ * \return Return code in ParserResult form
+ */
+ ParserResult OutputDecodedPictures();
+
/*! \brief Function to parse one picture bit stream received from the demuxer.
* \param [in] p_stream A pointer of uint8_t for the input stream to be parsed
* \param [in] pic_data_size Size of the input stream
@@ -207,15 +217,37 @@ protected:
*/
void SetupReflist(AvcSliceInfo *p_slice_info);
+ /*! \brief Function to check the fullness of DPB and output picture if needed.
+ * \return ParserResult
+ */
+ ParserResult CheckDpbAndOutput();
+
/*! \brief Function to find a free buffer in DPB for the current picture
+ * \return ParserResult
*/
ParserResult FindFreeBufInDpb();
/*! \brief Function to mark decoded reference picture in DPB. 8.2.5. This step is
- * performed after the current picture is decoded.
+ * performed after the current picture is decoded, for future pictures.
+ * \return ParserResult
*/
ParserResult MarkDecodedRefPics();
+ /*! \brief Function to bump one picture out of DPB. C.4.5.3.
+ * \return ParserResult
+ */
+ ParserResult BumpPicFromDpb();
+
+ /*! \brief Function to insert the current picture into DPB.
+ * \return ParserResult
+ */
+ ParserResult InsertCurrPicIntoDpb();
+
+ /*! \brief Function to send out the remaining pictures that need for output in DPB buffer.
+ * \return ParserResult
+ */
+ ParserResult FlushDpb();
+
#if DBGINFO
/*! \brief Function to log out parsed SPS content for debug.
*/
diff --git a/src/parser/hevc_parser.cpp b/src/parser/hevc_parser.cpp
index 7658814fa8..2cebc5d61a 100644
--- a/src/parser/hevc_parser.cpp
+++ b/src/parser/hevc_parser.cpp
@@ -2181,7 +2181,7 @@ void HevcVideoParser::InitDpb() {
}
dpb_buffer_.dpb_size = 0;
dpb_buffer_.dpb_fullness = 0;
- dpb_buffer_.num_needed_for_output = 0;
+ dpb_buffer_.num_pics_needed_for_output = 0;
dpb_buffer_.num_output_pics = 0;
}
@@ -2193,14 +2193,14 @@ void HevcVideoParser::EmptyDpb() {
dpb_buffer_.output_pic_list[i] = 0xFF;
}
dpb_buffer_.dpb_fullness = 0;
- dpb_buffer_.num_needed_for_output = 0;
+ dpb_buffer_.num_pics_needed_for_output = 0;
dpb_buffer_.num_output_pics = 0;
}
int HevcVideoParser::FlushDpb() {
- if (dpb_buffer_.num_needed_for_output) {
+ if (dpb_buffer_.num_pics_needed_for_output) {
// Bump the remaining pictures
- while (dpb_buffer_.num_needed_for_output) {
+ while (dpb_buffer_.num_pics_needed_for_output) {
if (BumpPicFromDpb() != PARSER_OK) {
return PARSER_FAIL;
}
@@ -2256,7 +2256,7 @@ int HevcVideoParser::MarkOutputPictures() {
}
}
- while (dpb_buffer_.num_needed_for_output > max_num_reorder_pics) {
+ while (dpb_buffer_.num_pics_needed_for_output > max_num_reorder_pics) {
if (BumpPicFromDpb() != PARSER_OK) {
return PARSER_FAIL;
}
@@ -2310,7 +2310,7 @@ int HevcVideoParser::FindFreeBufAndMark() {
dpb_buffer_.frame_buffer_list[index].use_status = 3;
if (dpb_buffer_.frame_buffer_list[index].pic_output_flag) {
- dpb_buffer_.num_needed_for_output++;
+ dpb_buffer_.num_pics_needed_for_output++;
}
dpb_buffer_.dpb_fullness++;
@@ -2319,7 +2319,7 @@ int HevcVideoParser::FindFreeBufAndMark() {
uint32_t max_num_reorder_pics = sps_ptr->sps_max_num_reorder_pics[highest_tid];
// Conditional bumping (when max_num_reorder_pics > 0) to avoid synchronous job submission while keeping in conformance with the spec.
- while (max_num_reorder_pics > 0 && dpb_buffer_.num_needed_for_output > max_num_reorder_pics) {
+ while (max_num_reorder_pics > 0 && dpb_buffer_.num_pics_needed_for_output > max_num_reorder_pics) {
if (BumpPicFromDpb() != PARSER_OK) {
return PARSER_FAIL;
}
@@ -2350,8 +2350,8 @@ int HevcVideoParser::BumpPicFromDpb() {
// Mark as "not needed for output"
dpb_buffer_.frame_buffer_list[min_poc_pic_idx].pic_output_flag = 0;
- if (dpb_buffer_.num_needed_for_output > 0) {
- dpb_buffer_.num_needed_for_output--;
+ if (dpb_buffer_.num_pics_needed_for_output > 0) {
+ dpb_buffer_.num_pics_needed_for_output--;
}
// If it is not used for reference, empty it.
diff --git a/src/parser/hevc_parser.h b/src/parser/hevc_parser.h
index 362c3c7880..51162f6757 100644
--- a/src/parser/hevc_parser.h
+++ b/src/parser/hevc_parser.h
@@ -115,7 +115,7 @@ protected:
typedef struct
{
uint32_t dpb_size; // DPB buffer size in number of frames
- uint32_t num_needed_for_output; // number of pictures in DPB that need to be output
+ uint32_t num_pics_needed_for_output; // number of pictures in DPB that need to be output
uint32_t dpb_fullness; // number of pictures in DPB
HevcPicInfo frame_buffer_list[HEVC_MAX_DPB_FRAMES];