rocDecode: Added decode buffer pool implementation for AVC and HEVC. (#355)
* * rocDecode: Initial check in for decode buffer pool.
* * rocDecode: All 135 streams pass.
* * rocDecode: Fixed a build error in debug mode.
* * rocDecode/HEVC: Removed two workaround in HEVC DPB management, after decode buffer pool implementa
tion.
- WR 1: Conditional bumping (when max_num_reorder_pics > 0) to avoid synchronous job submission in
C.5.2.3.
- WR 2: Add two more buffers in DPB to avoid buffer over-writing.
* * rocDecode/HEVC: Added display delay feature.
* * rocDecode/HEVC: Fixed the -z option issue within the context of the new decode buffer pool implementation.
* * rocDecode/HEVC: Removed redundent code.
* * rocDecode/AVC: Added decode buffer pool implementation for AVC.
* * rocDecode: Added a few changes.
- Added display delay feature to AVC.
- Removed a workaround for AVC: AVC_MAX_DPB_FRAMES was increased to 18. Now it is back to 16.
- Removed a workaround for AVC: increased DPB buffer size by 2. Now it is back to normal.
- Code format changes for HEVC.
* * rocDecode/AVC: Fixed the -z option issue within the context of the new decode buffer pool implementation.
* * rocDecode: Merged OutputDecodedPictures() method to upper class RocVideoParser.
* * rocDecode: Code cleanup. No functional changes.
* * rocDecode: Made decode buffer pool size adaptive.
- Removed the hard coded decode buffer pool size set in the decoder.
- Exposed the display delay parameter from RocVideoDecoder class to the user.
- Now the decoder buffer pool size is determined from the DPB buffer size and display delay parameter.
* * rocDecode: Several changes based on code review.
- Merged decode and display use status into one parameter.
- Removed the surface index from DecodeFrameBuffer, which is now implicitly referred by the array index.
- Changed a function name for better clarity.
* * rocDecode: Added a comment.
[ROCm/rocdecode commit: 61c8661b9c]
This commit is contained in:
@@ -32,6 +32,7 @@ make -j
|
||||
-d <GPU device ID - 0:device 0 / 1:device 1/ ... [optional - default:0]>
|
||||
-f <Number of decoded frames - specify the number of pictures to be decoded [optional]>
|
||||
-z <force_zero_latency - Decoded frames will be flushed out for display immediately [optional]>
|
||||
-disp_delay <display delay - specify the number of frames to be delayed for display [optional]>
|
||||
-sei <extract SEI messages [optional]>
|
||||
-md5 <generate MD5 message digest on the decoded YUV image sequence [optional]>
|
||||
-md5_check MD5_File_Path <generate MD5 message digest on the decoded YUV image sequence and compare to the reference MD5 string in a file [optional]>
|
||||
|
||||
@@ -47,6 +47,7 @@ void ShowHelpAndExit(const char *option = NULL) {
|
||||
<< "-d GPU device ID (0 for the first device, 1 for the second, etc.); optional; default: 0" << std::endl
|
||||
<< "-f Number of decoded frames - specify the number of pictures to be decoded; optional" << std::endl
|
||||
<< "-z force_zero_latency (force_zero_latency, Decoded frames will be flushed out for display immediately); optional;" << std::endl
|
||||
<< "-disp_delay -specify the number of frames to be delayed for display; optional;" << std::endl
|
||||
<< "-sei extract SEI messages; optional;" << std::endl
|
||||
<< "-md5 generate MD5 message digest on the decoded YUV image sequence; optional;" << std::endl
|
||||
<< "-md5_check MD5 File Path - generate MD5 message digest on the decoded YUV image sequence and compare to the reference MD5 string in a file; optional;" << std::endl
|
||||
@@ -66,6 +67,7 @@ int main(int argc, char **argv) {
|
||||
std::fstream ref_md5_file;
|
||||
int dump_output_frames = 0;
|
||||
int device_id = 0;
|
||||
int disp_delay = 0;
|
||||
bool b_force_zero_latency = false; // false by default: enabling this option might affect decoding performance
|
||||
bool b_extract_sei_messages = false;
|
||||
bool b_generate_md5 = false;
|
||||
@@ -111,6 +113,13 @@ int main(int argc, char **argv) {
|
||||
device_id = atoi(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-disp_delay")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-disp_delay");
|
||||
}
|
||||
disp_delay = atoi(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-f")) {
|
||||
if (++i == argc) {
|
||||
ShowHelpAndExit("-d");
|
||||
@@ -197,7 +206,7 @@ int main(int argc, char **argv) {
|
||||
VideoDemuxer demuxer(input_file_path.c_str());
|
||||
VideoSeekContext video_seek_ctx;
|
||||
rocDecVideoCodec rocdec_codec_id = AVCodec2RocDecVideoCodec(demuxer.GetCodecID());
|
||||
RocVideoDecoder viddec(device_id, mem_type, rocdec_codec_id, b_force_zero_latency, p_crop_rect, b_extract_sei_messages);
|
||||
RocVideoDecoder viddec(device_id, mem_type, rocdec_codec_id, b_force_zero_latency, p_crop_rect, b_extract_sei_messages, disp_delay);
|
||||
|
||||
std::string device_name, gcn_arch_name;
|
||||
int pci_bus_id, pci_domain_id, pci_device_id;
|
||||
|
||||
@@ -33,7 +33,7 @@ THE SOFTWARE.
|
||||
|
||||
#define AVC_MAX_REF_FRAME_NUM 16
|
||||
#define AVC_MAX_REF_PICTURE_NUM 32
|
||||
#define AVC_MAX_DPB_FRAMES 18
|
||||
#define AVC_MAX_DPB_FRAMES 16
|
||||
#define AVC_MAX_DPB_FIELDS AVC_MAX_DPB_FRAMES * 2
|
||||
|
||||
#define AVC_MACRO_BLOCK_SIZE 16
|
||||
|
||||
@@ -24,6 +24,9 @@ THE SOFTWARE.
|
||||
#include "avc_parser.h"
|
||||
|
||||
AvcVideoParser::AvcVideoParser() {
|
||||
active_sps_id_ = -1;
|
||||
active_pps_id_ = -1;
|
||||
|
||||
prev_pic_order_cnt_msb_ = 0;
|
||||
prev_pic_order_cnt_lsb_ = 0;
|
||||
prev_top_field_order_cnt_ = 0;
|
||||
@@ -42,6 +45,7 @@ AvcVideoParser::AvcVideoParser() {
|
||||
field_pic_count_ = 0;
|
||||
second_field_ = 0;
|
||||
first_field_pic_idx_ = 0;
|
||||
first_field_dec_buf_idx_ = 0;
|
||||
|
||||
InitDpb();
|
||||
}
|
||||
@@ -59,9 +63,6 @@ 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;
|
||||
@@ -86,8 +87,8 @@ rocDecStatus AvcVideoParser::ParseVideoData(RocdecSourceDataPacket *p_data) {
|
||||
}
|
||||
|
||||
// Output decoded pictures from DPB if any are ready in case of frame_num gaps.
|
||||
if (pfn_display_picture_cb_ && dpb_buffer_.num_output_pics > 0) {
|
||||
if (OutputDecodedPictures() != PARSER_OK) {
|
||||
if (pfn_display_picture_cb_ && num_output_pics_ > 0) {
|
||||
if (OutputDecodedPictures(false) != PARSER_OK) {
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -237,9 +238,9 @@ ParserResult AvcVideoParser::ParsePictureData(const uint8_t *p_stream, uint32_t
|
||||
}
|
||||
|
||||
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.
|
||||
if ((ret2 = FindFreeInDecBufPool()) != PARSER_OK) {
|
||||
return ret2;
|
||||
}
|
||||
if ((ret2 = FindFreeBufInDpb()) != PARSER_OK) {
|
||||
return ret2;
|
||||
}
|
||||
@@ -299,7 +300,7 @@ ParserResult AvcVideoParser::NotifyNewSps(AvcSeqParameterSet *p_sps) {
|
||||
video_format_params_.bit_depth_luma_minus8 = p_sps->bit_depth_luma_minus8;
|
||||
video_format_params_.bit_depth_chroma_minus8 = p_sps->bit_depth_chroma_minus8;
|
||||
video_format_params_.progressive_sequence = p_sps->frame_mbs_only_flag ? 1 : 0;
|
||||
video_format_params_.min_num_decode_surfaces = dpb_buffer_.dpb_size;
|
||||
video_format_params_.min_num_decode_surfaces = dec_buf_pool_size_;
|
||||
video_format_params_.coded_width = pic_width_;
|
||||
video_format_params_.coded_height = pic_height_;
|
||||
video_format_params_.chroma_format = static_cast<rocDecVideoChromaFormat>(p_sps->chroma_format_idc);
|
||||
@@ -408,7 +409,7 @@ void AvcVideoParser::SendSeiMsgPayload() {
|
||||
sei_message_info_params_.sei_message_count = sei_message_count_;
|
||||
sei_message_info_params_.sei_message = sei_message_list_.data();
|
||||
sei_message_info_params_.sei_data = (void*)sei_payload_buf_;
|
||||
sei_message_info_params_.picIdx = curr_pic_.pic_idx;
|
||||
sei_message_info_params_.picIdx = curr_pic_.dec_buf_idx;
|
||||
|
||||
// callback function with RocdecSeiMessageInfo params filled out
|
||||
if (pfn_get_sei_message_cb_) pfn_get_sei_message_cb_(parser_params_.user_data, &sei_message_info_params_);
|
||||
@@ -441,7 +442,7 @@ ParserResult AvcVideoParser::SendPicForDecode() {
|
||||
|
||||
dec_pic_params_.pic_width = pic_width_;
|
||||
dec_pic_params_.pic_height = pic_height_;
|
||||
dec_pic_params_.curr_pic_idx = curr_pic_.pic_idx;
|
||||
dec_pic_params_.curr_pic_idx = curr_pic_.dec_buf_idx;
|
||||
dec_pic_params_.field_pic_flag = p_slice_header->field_pic_flag;
|
||||
dec_pic_params_.bottom_field_flag = p_slice_header->bottom_field_flag;
|
||||
dec_pic_params_.second_field = second_field_;
|
||||
@@ -457,7 +458,7 @@ ParserResult AvcVideoParser::SendPicForDecode() {
|
||||
RocdecAvcPicParams *p_pic_param = &dec_pic_params_.pic_params.avc;
|
||||
|
||||
// Current picture
|
||||
p_pic_param->curr_pic.pic_idx = curr_pic_.pic_idx;
|
||||
p_pic_param->curr_pic.pic_idx = curr_pic_.dec_buf_idx;
|
||||
if (curr_pic_.is_reference == kUsedForLongTerm) {
|
||||
p_pic_param->curr_pic.frame_idx = curr_pic_.long_term_pic_num;
|
||||
} else {
|
||||
@@ -479,7 +480,7 @@ ParserResult AvcVideoParser::SendPicForDecode() {
|
||||
if (p_slice_header->field_pic_flag == 0) { // frame picture
|
||||
AvcPicture *p_ref_pic = &dpb_buffer_.frame_buffer_list[i];
|
||||
if (p_ref_pic->is_reference != kUnusedForReference) {
|
||||
p_pic_param->ref_frames[buf_index].pic_idx = p_ref_pic->pic_idx;
|
||||
p_pic_param->ref_frames[buf_index].pic_idx = p_ref_pic->dec_buf_idx;
|
||||
if ( p_ref_pic->is_reference == kUsedForLongTerm) {
|
||||
p_pic_param->ref_frames[buf_index].frame_idx = p_ref_pic->long_term_pic_num;
|
||||
} else {
|
||||
@@ -500,7 +501,7 @@ ParserResult AvcVideoParser::SendPicForDecode() {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
AvcPicture *p_field_pic = &dpb_buffer_.field_pic_list[i * 2 + j];
|
||||
if (p_field_pic->is_reference != kUnusedForReference) {
|
||||
p_ref_frame->pic_idx = p_field_pic->pic_idx;
|
||||
p_ref_frame->pic_idx = p_field_pic->dec_buf_idx;
|
||||
if (p_field_pic->is_reference == kUsedForLongTerm) {
|
||||
p_ref_frame->frame_idx = p_field_pic->long_term_frame_idx;
|
||||
} else {
|
||||
@@ -611,7 +612,7 @@ ParserResult AvcVideoParser::SendPicForDecode() {
|
||||
for (i = 0; i <= p_slice_info->slice_header.num_ref_idx_l0_active_minus1; i++) {
|
||||
AvcPicture *p_ref_pic = &p_slice_info->ref_list_0_[i];
|
||||
if (p_ref_pic->is_reference != kUnusedForReference) {
|
||||
p_slice_param->ref_pic_list_0[i].pic_idx = p_ref_pic->pic_idx;
|
||||
p_slice_param->ref_pic_list_0[i].pic_idx = p_ref_pic->dec_buf_idx;
|
||||
if ( p_ref_pic->is_reference == kUsedForLongTerm) {
|
||||
p_slice_param->ref_pic_list_0[i].frame_idx = p_ref_pic->long_term_pic_num;
|
||||
} else {
|
||||
@@ -632,7 +633,7 @@ ParserResult AvcVideoParser::SendPicForDecode() {
|
||||
for (i = 0; i <= p_slice_info->slice_header.num_ref_idx_l1_active_minus1; i++) {
|
||||
AvcPicture *p_ref_pic = &p_slice_info->ref_list_1_[i];
|
||||
if (p_ref_pic->is_reference != kUnusedForReference) {
|
||||
p_slice_param->ref_pic_list_1[i].pic_idx = p_ref_pic->pic_idx;
|
||||
p_slice_param->ref_pic_list_1[i].pic_idx = p_ref_pic->dec_buf_idx;
|
||||
if ( p_ref_pic->is_reference == kUsedForLongTerm) {
|
||||
p_slice_param->ref_pic_list_1[i].frame_idx = p_ref_pic->long_term_pic_num;
|
||||
} else {
|
||||
@@ -709,20 +710,6 @@ 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;
|
||||
@@ -1192,7 +1179,7 @@ ParserResult AvcVideoParser::ParseSliceHeader(uint8_t *p_stream, size_t stream_s
|
||||
return PARSER_WRONG_STATE;
|
||||
}
|
||||
// Re-set DPB size.
|
||||
dpb_buffer_.dpb_size = p_sps->max_num_ref_frames + 3;
|
||||
dpb_buffer_.dpb_size = p_sps->max_num_ref_frames + 1;
|
||||
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.
|
||||
}
|
||||
@@ -1206,11 +1193,16 @@ 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 + 3;
|
||||
dpb_buffer_.dpb_size = p_sps->max_num_ref_frames + 1;
|
||||
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.
|
||||
}
|
||||
|
||||
// Check and adjust decode buffer pool size if needed
|
||||
if (new_sps_activated_) {
|
||||
CheckAndAdjustDecBufPoolSize(dpb_buffer_.dpb_size);
|
||||
}
|
||||
|
||||
// Set frame rate if available
|
||||
if (new_sps_activated_) {
|
||||
if (p_sps->vui_seq_parameters.timing_info_present_flag) {
|
||||
@@ -1626,14 +1618,14 @@ void AvcVideoParser::InitDpb() {
|
||||
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_.frame_buffer_list[i].use_status = kNotUsed;
|
||||
dpb_buffer_.frame_buffer_list[i].pic_output_flag = 0;
|
||||
dpb_buffer_.field_pic_list[i * 2].pic_idx = i;
|
||||
dpb_buffer_.field_pic_list[i * 2 + 1].pic_idx = i;
|
||||
dpb_buffer_.field_pic_list[i * 2].is_reference = kUnusedForReference;
|
||||
dpb_buffer_.field_pic_list[i * 2 + 1].is_reference = kUnusedForReference;
|
||||
dpb_buffer_.field_pic_list[i * 2].use_status = 0;
|
||||
dpb_buffer_.field_pic_list[i * 2 + 1].use_status = 0;
|
||||
dpb_buffer_.field_pic_list[i * 2].use_status = kNotUsed;
|
||||
dpb_buffer_.field_pic_list[i * 2 + 1].use_status = kNotUsed;
|
||||
dpb_buffer_.field_pic_list[i * 2].pic_output_flag = 0;
|
||||
dpb_buffer_.field_pic_list[i * 2 + 1].pic_output_flag = 0;
|
||||
}
|
||||
@@ -1644,7 +1636,6 @@ void AvcVideoParser::InitDpb() {
|
||||
dpb_buffer_.num_short_term_ref_fields = 0;
|
||||
dpb_buffer_.num_long_term_ref_fields = 0;
|
||||
dpb_buffer_.num_pics_needed_for_output = 0;
|
||||
dpb_buffer_.num_output_pics = 0;
|
||||
}
|
||||
|
||||
// 8.2.1 Decoding process for picture order count
|
||||
@@ -1962,13 +1953,13 @@ ParserResult AvcVideoParser::DecodeFrameNumGaps() {
|
||||
}
|
||||
|
||||
for (i = 0; i < dpb_buffer_.dpb_size; i++) {
|
||||
if (dpb_buffer_.frame_buffer_list[i].use_status == 0) {
|
||||
if (dpb_buffer_.frame_buffer_list[i].use_status == kNotUsed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < dpb_buffer_.dpb_size) {
|
||||
non_existing_pic.pic_idx = dpb_buffer_.frame_buffer_list[i].pic_idx;
|
||||
non_existing_pic.use_status = 3;
|
||||
non_existing_pic.use_status = kFrameUsedForDecode;
|
||||
dpb_buffer_.frame_buffer_list[i] = non_existing_pic;
|
||||
dpb_buffer_.dpb_fullness++;
|
||||
dpb_buffer_.num_short_term++;
|
||||
@@ -2566,14 +2557,40 @@ ParserResult AvcVideoParser::CheckDpbAndOutput() {
|
||||
}
|
||||
}
|
||||
// Output decoded pictures from DPB if any are ready
|
||||
if (pfn_display_picture_cb_ && dpb_buffer_.num_output_pics > 0) {
|
||||
if (OutputDecodedPictures() != PARSER_OK) {
|
||||
if (pfn_display_picture_cb_ && num_output_pics_ > 0) {
|
||||
if (OutputDecodedPictures(false) != PARSER_OK) {
|
||||
return PARSER_FAIL;
|
||||
}
|
||||
}
|
||||
return PARSER_OK;
|
||||
}
|
||||
|
||||
ParserResult AvcVideoParser::FindFreeInDecBufPool() {
|
||||
int dec_buf_index;
|
||||
|
||||
if (curr_pic_.pic_structure == kFrame || !second_field_) {
|
||||
// Find a free buffer in decode buffer pool
|
||||
for (dec_buf_index = 0; dec_buf_index < dec_buf_pool_size_; dec_buf_index++) {
|
||||
if (decode_buffer_pool_[dec_buf_index].use_status == kNotUsed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dec_buf_index == dec_buf_pool_size_) {
|
||||
ERR("Could not find a free buffer in decode buffer pool.");
|
||||
return PARSER_NOT_FOUND;
|
||||
}
|
||||
|
||||
curr_pic_.dec_buf_idx = dec_buf_index;
|
||||
if ( curr_pic_.pic_structure != kFrame) {
|
||||
first_field_dec_buf_idx_ = dec_buf_index;
|
||||
}
|
||||
} else {
|
||||
curr_pic_.dec_buf_idx = first_field_dec_buf_idx_;
|
||||
}
|
||||
|
||||
return PARSER_OK;
|
||||
}
|
||||
|
||||
ParserResult AvcVideoParser::FindFreeBufInDpb() {
|
||||
int i;
|
||||
if (curr_pic_.pic_structure == kFrame || !second_field_) {
|
||||
@@ -2584,18 +2601,18 @@ ParserResult AvcVideoParser::FindFreeBufInDpb() {
|
||||
}
|
||||
|
||||
for (i = 0; i < dpb_buffer_.dpb_size; i++) {
|
||||
if (dpb_buffer_.frame_buffer_list[i].use_status == 0) {
|
||||
if (dpb_buffer_.frame_buffer_list[i].use_status == kNotUsed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
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;
|
||||
curr_pic_.use_status = kFrameUsedForDecode;
|
||||
} else if (curr_pic_.pic_structure == kTopField) {
|
||||
curr_pic_.use_status = 1;
|
||||
curr_pic_.use_status = kTopFieldUsedForDecode;
|
||||
} else {
|
||||
curr_pic_.use_status = 2;
|
||||
curr_pic_.use_status = kBottomFieldUsedForDecode;
|
||||
}
|
||||
} else {
|
||||
ERR("Could not find any free frame buffer in DPB.");
|
||||
@@ -2608,9 +2625,9 @@ ParserResult AvcVideoParser::FindFreeBufInDpb() {
|
||||
} else {
|
||||
curr_pic_.pic_idx = first_field_pic_idx_;
|
||||
if (curr_pic_.pic_structure == kTopField) {
|
||||
curr_pic_.use_status = 1;
|
||||
curr_pic_.use_status = kTopFieldUsedForDecode;
|
||||
} else {
|
||||
curr_pic_.use_status = 2;
|
||||
curr_pic_.use_status = kBottomFieldUsedForDecode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2982,12 +2999,14 @@ ParserResult AvcVideoParser::BumpPicFromDpb() {
|
||||
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++;
|
||||
if (pfn_display_picture_cb_) {
|
||||
if (num_output_pics_ >= dec_buf_pool_size_) {
|
||||
ERR("Error! Decode buffer pool overflow!");
|
||||
return PARSER_OUT_OF_RANGE;
|
||||
} else {
|
||||
output_pic_list_[num_output_pics_] = dpb_buffer_.frame_buffer_list[min_poc_pic_idx_ref].dec_buf_idx;
|
||||
num_output_pics_++;
|
||||
}
|
||||
}
|
||||
}
|
||||
min_poc_ref = 0x7FFFFFFF;
|
||||
@@ -3008,16 +3027,19 @@ ParserResult AvcVideoParser::BumpPicFromDpb() {
|
||||
}
|
||||
|
||||
// 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++;
|
||||
if (pfn_display_picture_cb_) {
|
||||
if (num_output_pics_ >= dec_buf_pool_size_) {
|
||||
ERR("Error! Decode buffer pool overflow!");
|
||||
return PARSER_OUT_OF_RANGE;
|
||||
} else {
|
||||
output_pic_list_[num_output_pics_] = dpb_buffer_.frame_buffer_list[min_poc_pic_idx_no_ref].dec_buf_idx;
|
||||
num_output_pics_++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove it from DPB.
|
||||
dpb_buffer_.frame_buffer_list[min_poc_pic_idx_no_ref].use_status = 0;
|
||||
// Remove it from DPB and mark unused for decode in decode buffer pool
|
||||
dpb_buffer_.frame_buffer_list[min_poc_pic_idx_no_ref].use_status = kNotUsed;
|
||||
decode_buffer_pool_[dpb_buffer_.frame_buffer_list[min_poc_pic_idx_no_ref].dec_buf_idx].use_status &= ~kFrameUsedForDecode;
|
||||
if (dpb_buffer_.dpb_fullness > 0 ) {
|
||||
dpb_buffer_.dpb_fullness--;
|
||||
}
|
||||
@@ -3069,7 +3091,7 @@ ParserResult AvcVideoParser::InsertCurrPicIntoDpb() {
|
||||
}
|
||||
dpb_buffer_.frame_buffer_list[i].pic_order_cnt = dpb_buffer_.frame_buffer_list[i].top_field_order_cnt <= dpb_buffer_.frame_buffer_list[i].bottom_field_order_cnt ? dpb_buffer_.frame_buffer_list[i].top_field_order_cnt : dpb_buffer_.frame_buffer_list[i].bottom_field_order_cnt;
|
||||
dpb_buffer_.frame_buffer_list[i].pic_output_flag = curr_pic_.pic_output_flag;
|
||||
dpb_buffer_.frame_buffer_list[i].use_status = 3;
|
||||
dpb_buffer_.frame_buffer_list[i].use_status = kFrameUsedForDecode;
|
||||
if (dpb_buffer_.frame_buffer_list[i].pic_output_flag) {
|
||||
dpb_buffer_.num_pics_needed_for_output++;
|
||||
}
|
||||
@@ -3081,6 +3103,13 @@ ParserResult AvcVideoParser::InsertCurrPicIntoDpb() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as used in decode buffer pool
|
||||
decode_buffer_pool_[curr_pic_.dec_buf_idx].use_status |= kFrameUsedForDecode;
|
||||
if (pfn_display_picture_cb_ && curr_pic_.pic_output_flag) {
|
||||
decode_buffer_pool_[curr_pic_.dec_buf_idx].use_status |= kFrameUsedForDisplay;
|
||||
}
|
||||
decode_buffer_pool_[curr_pic_.dec_buf_idx].pic_order_cnt = curr_pic_.pic_order_cnt;
|
||||
} else {
|
||||
ERR("Could not find the reserved frame buffer for the current picture in DPB.");
|
||||
return PARSER_FAIL;
|
||||
@@ -3097,6 +3126,8 @@ ParserResult AvcVideoParser::FlushDpb() {
|
||||
// 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;
|
||||
dpb_buffer_.field_pic_list[i * 2].is_reference = kUnusedForReference;
|
||||
dpb_buffer_.field_pic_list[i * 2 + 1].is_reference = kUnusedForReference;
|
||||
}
|
||||
// Bump the remaining pictures
|
||||
while (dpb_buffer_.num_pics_needed_for_output) {
|
||||
@@ -3104,12 +3135,20 @@ ParserResult AvcVideoParser::FlushDpb() {
|
||||
return PARSER_FAIL;
|
||||
}
|
||||
}
|
||||
if (pfn_display_picture_cb_ && dpb_buffer_.num_output_pics > 0) {
|
||||
if (OutputDecodedPictures() != PARSER_OK) {
|
||||
return PARSER_FAIL;
|
||||
}
|
||||
}
|
||||
if (pfn_display_picture_cb_ && num_output_pics_ > 0) {
|
||||
if (OutputDecodedPictures(true) != PARSER_OK) {
|
||||
return PARSER_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
// Empty DPB
|
||||
for (int i = 0; i < AVC_MAX_DPB_FRAMES; i++) {
|
||||
dpb_buffer_.frame_buffer_list[i].use_status = kNotUsed;
|
||||
dpb_buffer_.field_pic_list[i * 2].use_status = kNotUsed;
|
||||
dpb_buffer_.field_pic_list[i * 2 + 1].use_status = kNotUsed;
|
||||
decode_buffer_pool_[dpb_buffer_.frame_buffer_list[i].dec_buf_idx].use_status = kNotUsed;
|
||||
}
|
||||
return PARSER_OK;
|
||||
}
|
||||
|
||||
@@ -3340,11 +3379,10 @@ void AvcVideoParser::PrintDpb() {
|
||||
MSG("second_field_ = " << second_field_);
|
||||
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 << ", pic_output_flag = " << p_buf->pic_output_flag);
|
||||
MSG("Frame buffer " << i << ": pic_idx = " << p_buf->pic_idx << ", dec_buf_idx = " << p_buf->dec_buf_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("Field picture store:");
|
||||
@@ -3353,12 +3391,20 @@ void AvcVideoParser::PrintDpb() {
|
||||
MSG("Field picture " << 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("");
|
||||
if (dpb_buffer_.num_output_pics) {
|
||||
|
||||
|
||||
MSG("Decode buffer pool:");
|
||||
for(i = 0; i < dec_buf_pool_size_; i++) {
|
||||
DecodeFrameBuffer *p_dec_buf = &decode_buffer_pool_[i];
|
||||
MSG("Decode buffer " << i << ": use_status = " << p_dec_buf->use_status << ", pic_order_cnt = " << p_dec_buf->pic_order_cnt);
|
||||
}
|
||||
MSG("num_output_pics_ = " << num_output_pics_);
|
||||
if (num_output_pics_) {
|
||||
MSG("output_pic_list:");
|
||||
for (i = 0; i < dpb_buffer_.num_output_pics; i++) {
|
||||
MSG_NO_NEWLINE(dpb_buffer_.output_pic_list[i] << ", ");
|
||||
for (i = 0; i < num_output_pics_; i++) {
|
||||
MSG_NO_NEWLINE(output_pic_list_[i] << ", ");
|
||||
}
|
||||
MSG("");
|
||||
MSG("");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ public:
|
||||
|
||||
typedef struct {
|
||||
int pic_idx; // picture index or id
|
||||
int dec_buf_idx; // frame index in decode buffer pool
|
||||
PictureStructure pic_structure;
|
||||
int32_t pic_order_cnt;
|
||||
int32_t top_field_order_cnt;
|
||||
@@ -70,7 +71,7 @@ public:
|
||||
int32_t long_term_pic_num; // LongTermPicNum
|
||||
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 use_status; // refer to FrameBufUseStatus
|
||||
uint32_t pic_output_flag; // OutputFlag
|
||||
} AvcPicture;
|
||||
|
||||
@@ -134,6 +135,7 @@ protected:
|
||||
uint32_t field_pic_count_;
|
||||
int second_field_;
|
||||
int first_field_pic_idx_;
|
||||
int first_field_dec_buf_idx_;
|
||||
|
||||
// DPB
|
||||
AvcPicture curr_pic_;
|
||||
@@ -150,11 +152,6 @@ protected:
|
||||
*/
|
||||
ParserResult SendPicForDecode();
|
||||
|
||||
/*! \brief Function to output decoded pictures from DPB for post-processing.
|
||||
* \return Return code in ParserResult form
|
||||
*/
|
||||
ParserResult OutputDecodedPictures();
|
||||
|
||||
/*! \brief Callback function to send parsed SEI playload to decoder.
|
||||
*/
|
||||
void SendSeiMsgPayload();
|
||||
@@ -263,6 +260,11 @@ protected:
|
||||
*/
|
||||
ParserResult CheckDpbAndOutput();
|
||||
|
||||
/*! \brief Function to find a free buffer in the decode buffer pool
|
||||
* \return <tt>ParserResult</tt>
|
||||
*/
|
||||
ParserResult FindFreeInDecBufPool();
|
||||
|
||||
/*! \brief Function to find a free buffer in DPB for the current picture
|
||||
* \return <tt>ParserResult</tt>
|
||||
*/
|
||||
|
||||
@@ -78,9 +78,6 @@ rocDecStatus HevcVideoParser::UnInitialize() {
|
||||
|
||||
rocDecStatus HevcVideoParser::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;
|
||||
@@ -111,8 +108,8 @@ rocDecStatus HevcVideoParser::ParseVideoData(RocdecSourceDataPacket *p_data) {
|
||||
}
|
||||
|
||||
// Output decoded pictures from DPB if any are ready
|
||||
if (pfn_display_picture_cb_ && dpb_buffer_.num_output_pics > 0) {
|
||||
if (OutputDecodedPictures() != PARSER_OK) {
|
||||
if (pfn_display_picture_cb_ && num_output_pics_ > 0) {
|
||||
if (OutputDecodedPictures(false) != PARSER_OK) {
|
||||
return ROCDEC_RUNTIME_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -144,7 +141,7 @@ int HevcVideoParser::FillSeqCallbackFn(HevcSeqParamSet* sps_data) {
|
||||
video_format_params_.progressive_sequence = 0;
|
||||
else // default value
|
||||
video_format_params_.progressive_sequence = 1;
|
||||
video_format_params_.min_num_decode_surfaces = dpb_buffer_.dpb_size;
|
||||
video_format_params_.min_num_decode_surfaces = dec_buf_pool_size_;
|
||||
video_format_params_.coded_width = sps_data->pic_width_in_luma_samples;
|
||||
video_format_params_.coded_height = sps_data->pic_height_in_luma_samples;
|
||||
video_format_params_.chroma_format = static_cast<rocDecVideoChromaFormat>(sps_data->chroma_format_idc);
|
||||
@@ -237,7 +234,7 @@ void HevcVideoParser::SendSeiMsgPayload() {
|
||||
sei_message_info_params_.sei_message_count = sei_message_count_;
|
||||
sei_message_info_params_.sei_message = sei_message_list_.data();
|
||||
sei_message_info_params_.sei_data = (void*)sei_payload_buf_;
|
||||
sei_message_info_params_.picIdx = curr_pic_info_.pic_idx;
|
||||
sei_message_info_params_.picIdx = curr_pic_info_.dec_buf_idx;
|
||||
|
||||
// callback function with RocdecSeiMessageInfo params filled out
|
||||
if (pfn_get_sei_message_cb_) pfn_get_sei_message_cb_(parser_params_.user_data, &sei_message_info_params_);
|
||||
@@ -251,7 +248,7 @@ int HevcVideoParser::SendPicForDecode() {
|
||||
|
||||
dec_pic_params_.pic_width = sps_ptr->pic_width_in_luma_samples;
|
||||
dec_pic_params_.pic_height = sps_ptr->pic_height_in_luma_samples;
|
||||
dec_pic_params_.curr_pic_idx = curr_pic_info_.pic_idx;
|
||||
dec_pic_params_.curr_pic_idx = curr_pic_info_.dec_buf_idx;
|
||||
dec_pic_params_.field_pic_flag = sps_ptr->profile_tier_level.general_interlaced_source_flag;
|
||||
dec_pic_params_.bottom_field_flag = 0; // For now. Need to parse VUI/SEI pic_timing()
|
||||
dec_pic_params_.second_field = 0; // For now. Need to parse VUI/SEI pic_timing()
|
||||
@@ -270,14 +267,14 @@ int HevcVideoParser::SendPicForDecode() {
|
||||
RocdecHevcPicParams *pic_param_ptr = &dec_pic_params_.pic_params.hevc;
|
||||
|
||||
// Current picture
|
||||
pic_param_ptr->curr_pic.pic_idx = curr_pic_info_.pic_idx;
|
||||
pic_param_ptr->curr_pic.pic_idx = curr_pic_info_.dec_buf_idx;
|
||||
pic_param_ptr->curr_pic.poc = curr_pic_info_.pic_order_cnt;
|
||||
|
||||
// Reference pictures
|
||||
ref_idx = 0;
|
||||
for (i = 0; i < num_poc_st_curr_before_; i++) {
|
||||
buf_idx = ref_pic_set_st_curr_before_[i]; // buffer index in DPB
|
||||
pic_param_ptr->ref_frames[ref_idx].pic_idx = dpb_buffer_.frame_buffer_list[buf_idx].pic_idx;
|
||||
pic_param_ptr->ref_frames[ref_idx].pic_idx = dpb_buffer_.frame_buffer_list[buf_idx].dec_buf_idx;
|
||||
pic_param_ptr->ref_frames[ref_idx].poc = dpb_buffer_.frame_buffer_list[buf_idx].pic_order_cnt;
|
||||
pic_param_ptr->ref_frames[ref_idx].flags = 0; // assume frame picture for now
|
||||
pic_param_ptr->ref_frames[ref_idx].flags |= RocdecHevcPicture_RPS_ST_CURR_BEFORE;
|
||||
@@ -286,7 +283,7 @@ int HevcVideoParser::SendPicForDecode() {
|
||||
|
||||
for (i = 0; i < num_poc_st_curr_after_; i++) {
|
||||
buf_idx = ref_pic_set_st_curr_after_[i]; // buffer index in DPB
|
||||
pic_param_ptr->ref_frames[ref_idx].pic_idx = dpb_buffer_.frame_buffer_list[buf_idx].pic_idx;
|
||||
pic_param_ptr->ref_frames[ref_idx].pic_idx = dpb_buffer_.frame_buffer_list[buf_idx].dec_buf_idx;
|
||||
pic_param_ptr->ref_frames[ref_idx].poc = dpb_buffer_.frame_buffer_list[buf_idx].pic_order_cnt;
|
||||
pic_param_ptr->ref_frames[ref_idx].flags = 0; // assume frame picture for now
|
||||
pic_param_ptr->ref_frames[ref_idx].flags |= RocdecHevcPicture_RPS_ST_CURR_AFTER;
|
||||
@@ -295,7 +292,7 @@ int HevcVideoParser::SendPicForDecode() {
|
||||
|
||||
for (i = 0; i < num_poc_lt_curr_; i++) {
|
||||
buf_idx = ref_pic_set_lt_curr_[i]; // buffer index in DPB
|
||||
pic_param_ptr->ref_frames[ref_idx].pic_idx = dpb_buffer_.frame_buffer_list[buf_idx].pic_idx;
|
||||
pic_param_ptr->ref_frames[ref_idx].pic_idx = dpb_buffer_.frame_buffer_list[buf_idx].dec_buf_idx;
|
||||
pic_param_ptr->ref_frames[ref_idx].poc = dpb_buffer_.frame_buffer_list[buf_idx].pic_order_cnt;
|
||||
pic_param_ptr->ref_frames[ref_idx].flags = 0; // assume frame picture for now
|
||||
pic_param_ptr->ref_frames[ref_idx].flags |= RocdecHevcPicture_LONG_TERM_REFERENCE | RocdecHevcPicture_RPS_LT_CURR;
|
||||
@@ -304,7 +301,7 @@ int HevcVideoParser::SendPicForDecode() {
|
||||
|
||||
for (i = 0; i < num_poc_st_foll_; i++) {
|
||||
buf_idx = ref_pic_set_st_foll_[i]; // buffer index in DPB
|
||||
pic_param_ptr->ref_frames[ref_idx].pic_idx = dpb_buffer_.frame_buffer_list[buf_idx].pic_idx;
|
||||
pic_param_ptr->ref_frames[ref_idx].pic_idx = dpb_buffer_.frame_buffer_list[buf_idx].dec_buf_idx;
|
||||
pic_param_ptr->ref_frames[ref_idx].poc = dpb_buffer_.frame_buffer_list[buf_idx].pic_order_cnt;
|
||||
pic_param_ptr->ref_frames[ref_idx].flags = 0; // assume frame picture for now
|
||||
ref_idx++;
|
||||
@@ -312,7 +309,7 @@ int HevcVideoParser::SendPicForDecode() {
|
||||
|
||||
for (i = 0; i < num_poc_lt_foll_; i++) {
|
||||
buf_idx = ref_pic_set_lt_foll_[i]; // buffer index in DPB
|
||||
pic_param_ptr->ref_frames[ref_idx].pic_idx = dpb_buffer_.frame_buffer_list[buf_idx].pic_idx;
|
||||
pic_param_ptr->ref_frames[ref_idx].pic_idx = dpb_buffer_.frame_buffer_list[buf_idx].dec_buf_idx;
|
||||
pic_param_ptr->ref_frames[ref_idx].poc = dpb_buffer_.frame_buffer_list[buf_idx].pic_order_cnt;
|
||||
pic_param_ptr->ref_frames[ref_idx].flags = 0; // assume frame picture for now
|
||||
ref_idx++;
|
||||
@@ -424,8 +421,9 @@ int HevcVideoParser::SendPicForDecode() {
|
||||
if (p_slice_header->slice_type != HEVC_SLICE_TYPE_I) {
|
||||
for (i = 0; i <= p_slice_header->num_ref_idx_l0_active_minus1; i++) {
|
||||
int idx = p_slice_info->ref_pic_list_0_[i]; // pic_idx of the ref pic
|
||||
int dec_buf_idx = dpb_buffer_.frame_buffer_list[idx].dec_buf_idx;
|
||||
for (j = 0; j < 15; j++) {
|
||||
if (pic_param_ptr->ref_frames[j].pic_idx == idx) {
|
||||
if (pic_param_ptr->ref_frames[j].pic_idx == dec_buf_idx) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -440,8 +438,9 @@ int HevcVideoParser::SendPicForDecode() {
|
||||
if (p_slice_header->slice_type == HEVC_SLICE_TYPE_B) {
|
||||
for (i = 0; i <= p_slice_header->num_ref_idx_l1_active_minus1; i++) {
|
||||
int idx = p_slice_info->ref_pic_list_1_[i]; // pic_idx of the ref pic
|
||||
int dec_buf_idx = dpb_buffer_.frame_buffer_list[idx].dec_buf_idx;
|
||||
for (j = 0; j < 15; j++) {
|
||||
if (pic_param_ptr->ref_frames[j].pic_idx == idx) {
|
||||
if (pic_param_ptr->ref_frames[j].pic_idx == dec_buf_idx) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -532,6 +531,10 @@ int HevcVideoParser::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;
|
||||
@@ -540,20 +543,6 @@ int HevcVideoParser::SendPicForDecode() {
|
||||
}
|
||||
}
|
||||
|
||||
int HevcVideoParser::OutputDecodedPictures() {
|
||||
RocdecParserDispInfo disp_info = {0};
|
||||
disp_info.progressive_frame = m_sps_[m_active_sps_id_].profile_tier_level.general_progressive_source_flag;
|
||||
disp_info.top_field_first = 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;
|
||||
}
|
||||
|
||||
ParserResult HevcVideoParser::ParsePictureData(const uint8_t* p_stream, uint32_t pic_data_size) {
|
||||
ParserResult ret = PARSER_OK;
|
||||
ParserResult ret2;
|
||||
@@ -667,6 +656,11 @@ ParserResult HevcVideoParser::ParsePictureData(const uint8_t* p_stream, uint32_t
|
||||
// Get POC. 8.3.1.
|
||||
CalculateCurrPoc();
|
||||
|
||||
// Locate a free buffer for the current picutre in decode buffer pool before output picture marking (C.5.2.2)
|
||||
if (FindFreeInDecBufPool() != PARSER_OK) {
|
||||
return PARSER_FAIL;
|
||||
}
|
||||
|
||||
// Decode RPS. 8.3.2.
|
||||
DecodeRps();
|
||||
}
|
||||
@@ -683,9 +677,13 @@ ParserResult HevcVideoParser::ParsePictureData(const uint8_t* p_stream, uint32_t
|
||||
}
|
||||
|
||||
// C.5.2.3. Find a free buffer in DPB and mark as used. (After 8.3.2.)
|
||||
if (FindFreeBufAndMark() != PARSER_OK) {
|
||||
if (FindFreeInDpbAndMark() != PARSER_OK) {
|
||||
return PARSER_FAIL;
|
||||
}
|
||||
|
||||
#if DBGINFO
|
||||
PrintDpb();
|
||||
#endif // DBGINFO
|
||||
}
|
||||
num_slices_++;
|
||||
break;
|
||||
@@ -1552,8 +1550,8 @@ ParserResult HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcS
|
||||
if (m_active_sps_id_ != pps_ptr->pps_seq_parameter_set_id) {
|
||||
m_active_sps_id_ = pps_ptr->pps_seq_parameter_set_id;
|
||||
sps_ptr = &m_sps_[m_active_sps_id_];
|
||||
// Re-set DPB size. We add 2 addition buffers to avoid overwritting buffer needed for output in certain cases.
|
||||
dpb_buffer_.dpb_size = sps_ptr->sps_max_dec_pic_buffering_minus1[sps_ptr->sps_max_sub_layers_minus1] + 3;
|
||||
// Re-set DPB size.
|
||||
dpb_buffer_.dpb_size = sps_ptr->sps_max_dec_pic_buffering_minus1[sps_ptr->sps_max_sub_layers_minus1] + 1;
|
||||
dpb_buffer_.dpb_size = dpb_buffer_.dpb_size > HEVC_MAX_DPB_FRAMES ? HEVC_MAX_DPB_FRAMES : dpb_buffer_.dpb_size;
|
||||
new_sps_activated_ = true; // Note: clear this flag after the actions are taken.
|
||||
}
|
||||
@@ -1573,12 +1571,17 @@ ParserResult HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcS
|
||||
pic_width_ = sps_ptr->pic_width_in_luma_samples;
|
||||
pic_height_ = sps_ptr->pic_height_in_luma_samples;
|
||||
// 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. We add 2 addition buffers to avoid overwritting buffer needed for output in certain cases.
|
||||
dpb_buffer_.dpb_size = sps_ptr->sps_max_dec_pic_buffering_minus1[sps_ptr->sps_max_sub_layers_minus1] + 3;
|
||||
// Re-set DPB size.
|
||||
dpb_buffer_.dpb_size = sps_ptr->sps_max_dec_pic_buffering_minus1[sps_ptr->sps_max_sub_layers_minus1] + 1;
|
||||
dpb_buffer_.dpb_size = dpb_buffer_.dpb_size > HEVC_MAX_DPB_FRAMES ? HEVC_MAX_DPB_FRAMES : dpb_buffer_.dpb_size;
|
||||
new_sps_activated_ = true; // Note: clear this flag after the actions are taken.
|
||||
}
|
||||
|
||||
// Check and adjust decode buffer pool size if needed
|
||||
if (new_sps_activated_) {
|
||||
CheckAndAdjustDecBufPoolSize(dpb_buffer_.dpb_size);
|
||||
}
|
||||
|
||||
// Set frame rate if available
|
||||
if (new_sps_activated_) {
|
||||
if (m_vps_[m_active_vps_id_].vps_timing_info_present_flag) {
|
||||
@@ -2130,25 +2133,23 @@ void HevcVideoParser::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].pic_output_flag = 0;
|
||||
dpb_buffer_.frame_buffer_list[i].use_status = 0;
|
||||
dpb_buffer_.output_pic_list[i] = 0xFF;
|
||||
dpb_buffer_.frame_buffer_list[i].use_status = kNotUsed;
|
||||
}
|
||||
dpb_buffer_.dpb_size = 0;
|
||||
dpb_buffer_.dpb_fullness = 0;
|
||||
dpb_buffer_.num_pics_needed_for_output = 0;
|
||||
dpb_buffer_.num_output_pics = 0;
|
||||
}
|
||||
|
||||
void HevcVideoParser::EmptyDpb() {
|
||||
for (int i = 0; i < HEVC_MAX_DPB_FRAMES; i++) {
|
||||
dpb_buffer_.frame_buffer_list[i].is_reference = kUnusedForReference;
|
||||
dpb_buffer_.frame_buffer_list[i].pic_output_flag = 0;
|
||||
dpb_buffer_.frame_buffer_list[i].use_status = 0;
|
||||
dpb_buffer_.output_pic_list[i] = 0xFF;
|
||||
dpb_buffer_.frame_buffer_list[i].use_status = kNotUsed;
|
||||
decode_buffer_pool_[dpb_buffer_.frame_buffer_list[i].dec_buf_idx].use_status = kNotUsed;
|
||||
}
|
||||
dpb_buffer_.dpb_fullness = 0;
|
||||
dpb_buffer_.num_pics_needed_for_output = 0;
|
||||
dpb_buffer_.num_output_pics = 0;
|
||||
num_output_pics_ = 0;
|
||||
}
|
||||
|
||||
int HevcVideoParser::FlushDpb() {
|
||||
@@ -2159,12 +2160,13 @@ int HevcVideoParser::FlushDpb() {
|
||||
return PARSER_FAIL;
|
||||
}
|
||||
}
|
||||
if (pfn_display_picture_cb_ && dpb_buffer_.num_output_pics > 0) {
|
||||
if (OutputDecodedPictures() != PARSER_OK) {
|
||||
return PARSER_FAIL;
|
||||
}
|
||||
}
|
||||
if (pfn_display_picture_cb_ && num_output_pics_ > 0) {
|
||||
if (OutputDecodedPictures(true) != PARSER_OK) {
|
||||
return PARSER_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return PARSER_OK;
|
||||
}
|
||||
|
||||
@@ -2185,11 +2187,16 @@ int HevcVideoParser::MarkOutputPictures() {
|
||||
}
|
||||
}
|
||||
|
||||
// We can still have remaining undisplayed frames due to display delay feature
|
||||
if (num_output_pics_) {
|
||||
OutputDecodedPictures(true);
|
||||
}
|
||||
EmptyDpb();
|
||||
} else {
|
||||
for (i = 0; i < HEVC_MAX_DPB_FRAMES; i++) {
|
||||
if (dpb_buffer_.frame_buffer_list[i].is_reference == kUnusedForReference && dpb_buffer_.frame_buffer_list[i].pic_output_flag == 0 && dpb_buffer_.frame_buffer_list[i].use_status) {
|
||||
dpb_buffer_.frame_buffer_list[i].use_status = 0;
|
||||
dpb_buffer_.frame_buffer_list[i].use_status = kNotUsed;
|
||||
decode_buffer_pool_[dpb_buffer_.frame_buffer_list[i].dec_buf_idx].use_status &= ~kFrameUsedForDecode;
|
||||
if (dpb_buffer_.dpb_fullness > 0) {
|
||||
dpb_buffer_.dpb_fullness--;
|
||||
} else {
|
||||
@@ -2222,27 +2229,34 @@ int HevcVideoParser::MarkOutputPictures() {
|
||||
return PARSER_OK;
|
||||
}
|
||||
|
||||
int HevcVideoParser::FindFreeBufAndMark() {
|
||||
ParserResult HevcVideoParser::FindFreeInDecBufPool() {
|
||||
int dec_buf_index;
|
||||
|
||||
// Find a free buffer in decode buffer pool
|
||||
for (dec_buf_index = 0; dec_buf_index < dec_buf_pool_size_; dec_buf_index++) {
|
||||
if (decode_buffer_pool_[dec_buf_index].use_status == kNotUsed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dec_buf_index == dec_buf_pool_size_) {
|
||||
ERR("Could not find a free buffer in decode buffer pool.");
|
||||
return PARSER_NOT_FOUND;
|
||||
}
|
||||
curr_pic_info_.dec_buf_idx = dec_buf_index;
|
||||
return PARSER_OK;
|
||||
}
|
||||
|
||||
ParserResult HevcVideoParser::FindFreeInDpbAndMark() {
|
||||
int i, j;
|
||||
|
||||
// Look for an empty buffer with longest decode history (lowest decode count)
|
||||
// Look for an empty buffer in DPB with longest decode history (lowest decode count)
|
||||
uint32_t min_decode_order_count = 0xFFFFFFFF;
|
||||
int index = dpb_buffer_.dpb_size;
|
||||
for (i = 0; i < dpb_buffer_.dpb_size; i++) {
|
||||
if (dpb_buffer_.frame_buffer_list[i].use_status == 0) {
|
||||
if (dpb_buffer_.frame_buffer_list[i].use_status == kNotUsed) {
|
||||
if (dpb_buffer_.frame_buffer_list[i].decode_order_count < min_decode_order_count) {
|
||||
// Check if this picture has been bumped to the output/display list. If yes, skip it because we do not want to
|
||||
// decode the current picture into any buffers in the output list
|
||||
bool is_in_output_list = false;
|
||||
for (j = 0; j < dpb_buffer_.num_output_pics; j++) {
|
||||
if (dpb_buffer_.output_pic_list[j] == i) {
|
||||
is_in_output_list = true;
|
||||
}
|
||||
}
|
||||
if (!is_in_output_list) {
|
||||
min_decode_order_count = dpb_buffer_.frame_buffer_list[i].decode_order_count;
|
||||
index = i;
|
||||
}
|
||||
min_decode_order_count = dpb_buffer_.frame_buffer_list[i].decode_order_count;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2254,6 +2268,7 @@ int HevcVideoParser::FindFreeBufAndMark() {
|
||||
curr_pic_info_.pic_idx = index;
|
||||
curr_pic_info_.is_reference = kUsedForShortTerm;
|
||||
// dpb_buffer_.frame_buffer_list[i].pic_idx is already set in InitDpb().
|
||||
dpb_buffer_.frame_buffer_list[index].dec_buf_idx = curr_pic_info_.dec_buf_idx;
|
||||
dpb_buffer_.frame_buffer_list[index].pic_order_cnt = curr_pic_info_.pic_order_cnt;
|
||||
dpb_buffer_.frame_buffer_list[index].prev_poc_lsb = curr_pic_info_.prev_poc_lsb;
|
||||
dpb_buffer_.frame_buffer_list[index].prev_poc_msb = curr_pic_info_.prev_poc_msb;
|
||||
@@ -2261,19 +2276,25 @@ int HevcVideoParser::FindFreeBufAndMark() {
|
||||
dpb_buffer_.frame_buffer_list[index].decode_order_count = curr_pic_info_.decode_order_count;
|
||||
dpb_buffer_.frame_buffer_list[index].pic_output_flag = curr_pic_info_.pic_output_flag;
|
||||
dpb_buffer_.frame_buffer_list[index].is_reference = kUsedForShortTerm;
|
||||
dpb_buffer_.frame_buffer_list[index].use_status = 3;
|
||||
dpb_buffer_.frame_buffer_list[index].use_status = kFrameUsedForDecode;
|
||||
|
||||
if (dpb_buffer_.frame_buffer_list[index].pic_output_flag) {
|
||||
dpb_buffer_.num_pics_needed_for_output++;
|
||||
}
|
||||
dpb_buffer_.dpb_fullness++;
|
||||
|
||||
// Mark as used in decode buffer pool
|
||||
decode_buffer_pool_[curr_pic_info_.dec_buf_idx].use_status |= kFrameUsedForDecode;
|
||||
if (pfn_display_picture_cb_ && curr_pic_info_.pic_output_flag) {
|
||||
decode_buffer_pool_[curr_pic_info_.dec_buf_idx].use_status |= kFrameUsedForDisplay;
|
||||
}
|
||||
decode_buffer_pool_[curr_pic_info_.dec_buf_idx].pic_order_cnt = curr_pic_info_.pic_order_cnt;
|
||||
|
||||
HevcSeqParamSet *sps_ptr = &m_sps_[m_active_sps_id_];
|
||||
uint32_t highest_tid = sps_ptr->sps_max_sub_layers_minus1; // HighestTid
|
||||
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_pics_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,19 +2331,22 @@ int HevcVideoParser::BumpPicFromDpb() {
|
||||
|
||||
// If it is not used for reference, empty it.
|
||||
if (dpb_buffer_.frame_buffer_list[min_poc_pic_idx].is_reference == kUnusedForReference) {
|
||||
dpb_buffer_.frame_buffer_list[min_poc_pic_idx].use_status = 0;
|
||||
dpb_buffer_.frame_buffer_list[min_poc_pic_idx].use_status = kNotUsed;
|
||||
decode_buffer_pool_[dpb_buffer_.frame_buffer_list[min_poc_pic_idx].dec_buf_idx].use_status &= ~kFrameUsedForDecode;
|
||||
if (dpb_buffer_.dpb_fullness > 0 ) {
|
||||
dpb_buffer_.dpb_fullness--;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert into output/display picture list
|
||||
if (dpb_buffer_.num_output_pics >= HEVC_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;
|
||||
dpb_buffer_.num_output_pics++;
|
||||
if (pfn_display_picture_cb_) {
|
||||
if (num_output_pics_ >= dec_buf_pool_size_) {
|
||||
ERR("Error! Decode buffer pool overflow!");
|
||||
return PARSER_OUT_OF_RANGE;
|
||||
} else {
|
||||
output_pic_list_[num_output_pics_] = dpb_buffer_.frame_buffer_list[min_poc_pic_idx].dec_buf_idx;
|
||||
num_output_pics_++;
|
||||
}
|
||||
}
|
||||
|
||||
return PARSER_OK;
|
||||
@@ -2630,7 +2654,7 @@ void HevcVideoParser::PrintSliceSegHeader(HevcSliceSegHeader *slice_header_ptr)
|
||||
MSG("slice_qp_delta = " << slice_header_ptr->slice_qp_delta);
|
||||
MSG("slice_cb_qp_offset = " << slice_header_ptr->slice_cb_qp_offset);
|
||||
MSG("slice_cr_qp_offset = " << slice_header_ptr->slice_cr_qp_offset);
|
||||
MSG("cu_chroma_qp_offset_enabled_flag = " << slice_header_ptr->cu_chroma_qp_offset_enabled_flag);
|
||||
MSG("cu_chroma_qp_offset_enabled_flag = " << static_cast<uint32_t>(slice_header_ptr->cu_chroma_qp_offset_enabled_flag));
|
||||
MSG("deblocking_filter_override_flag = " << slice_header_ptr->deblocking_filter_override_flag);
|
||||
MSG("slice_deblocking_filter_disabled_flag = " << slice_header_ptr->slice_deblocking_filter_disabled_flag);
|
||||
MSG("slice_beta_offset_div2 = " << slice_header_ptr->slice_beta_offset_div2);
|
||||
@@ -2644,18 +2668,18 @@ void HevcVideoParser::PrintSliceSegHeader(HevcSliceSegHeader *slice_header_ptr)
|
||||
|
||||
void HevcVideoParser::PrintStRps(HevcShortTermRps *rps_ptr) {
|
||||
MSG("==== Short-term reference picture set =====")
|
||||
MSG("inter_ref_pic_set_prediction_flag = " << rps_ptr->inter_ref_pic_set_prediction_flag);
|
||||
MSG("inter_ref_pic_set_prediction_flag = " << static_cast<uint32_t>(rps_ptr->inter_ref_pic_set_prediction_flag));
|
||||
MSG("delta_idx_minus1 = " << rps_ptr->delta_idx_minus1);
|
||||
MSG("delta_rps_sign = " << rps_ptr->delta_rps_sign);
|
||||
MSG("delta_rps_sign = " << static_cast<uint32_t>(rps_ptr->delta_rps_sign));
|
||||
MSG("abs_delta_rps_minus1 = " << rps_ptr->abs_delta_rps_minus1);
|
||||
MSG_NO_NEWLINE("rps->used_by_curr_pic_flag[]:");
|
||||
for(int j = 0; j < 16; j++) {
|
||||
MSG_NO_NEWLINE(" " << rps_ptr->used_by_curr_pic_flag[j]);
|
||||
MSG_NO_NEWLINE(" " << static_cast<uint32_t>(rps_ptr->used_by_curr_pic_flag[j]));
|
||||
}
|
||||
MSG("");
|
||||
MSG_NO_NEWLINE("use_delta_flag[]:");
|
||||
for(int j = 0; j < 16; j++) {
|
||||
MSG_NO_NEWLINE(" " << rps_ptr->use_delta_flag[j]);
|
||||
MSG_NO_NEWLINE(" " << static_cast<uint32_t>(rps_ptr->use_delta_flag[j]));
|
||||
}
|
||||
MSG("");
|
||||
MSG("num_negative_pics = " << rps_ptr->num_negative_pics);
|
||||
@@ -2669,7 +2693,7 @@ void HevcVideoParser::PrintStRps(HevcShortTermRps *rps_ptr) {
|
||||
MSG("");
|
||||
MSG_NO_NEWLINE("used_by_curr_pic_s0_flag[]:");
|
||||
for(int j = 0; j < 16; j++) {
|
||||
MSG_NO_NEWLINE(" " << rps_ptr->used_by_curr_pic_s0_flag[j]);
|
||||
MSG_NO_NEWLINE(" " << static_cast<uint32_t>(rps_ptr->used_by_curr_pic_s0_flag[j]));
|
||||
}
|
||||
MSG("");
|
||||
MSG_NO_NEWLINE("delta_poc_s1_minus1[]:");
|
||||
@@ -2679,7 +2703,7 @@ void HevcVideoParser::PrintStRps(HevcShortTermRps *rps_ptr) {
|
||||
MSG("");
|
||||
MSG_NO_NEWLINE("used_by_curr_pic_s1_flag[]:");
|
||||
for(int j = 0; j < 16; j++) {
|
||||
MSG_NO_NEWLINE(" " << rps_ptr->used_by_curr_pic_s1_flag[j]);
|
||||
MSG_NO_NEWLINE(" " << static_cast<uint32_t>(rps_ptr->used_by_curr_pic_s1_flag[j]));
|
||||
}
|
||||
MSG("");
|
||||
|
||||
@@ -2695,12 +2719,12 @@ void HevcVideoParser::PrintStRps(HevcShortTermRps *rps_ptr) {
|
||||
MSG("");
|
||||
MSG_NO_NEWLINE("used_by_curr_pic_s0[16]:");
|
||||
for(int j = 0; j < 16; j++) {
|
||||
MSG_NO_NEWLINE(" " << rps_ptr->used_by_curr_pic_s0[j]);
|
||||
MSG_NO_NEWLINE(" " << static_cast<uint32_t>(rps_ptr->used_by_curr_pic_s0[j]));
|
||||
}
|
||||
MSG("");
|
||||
MSG_NO_NEWLINE("used_by_curr_pic_s1[16]:");
|
||||
for(int j = 0; j < 16; j++) {
|
||||
MSG_NO_NEWLINE(" " << rps_ptr->used_by_curr_pic_s1[j]);
|
||||
MSG_NO_NEWLINE(" " << static_cast<uint32_t>(rps_ptr->used_by_curr_pic_s1[j]));
|
||||
}
|
||||
MSG("");
|
||||
}
|
||||
@@ -2719,4 +2743,71 @@ void HevcVideoParser::PrintLtRefInfo(HevcLongTermRps *lt_info_ptr) {
|
||||
}
|
||||
MSG("");
|
||||
}
|
||||
|
||||
void HevcVideoParser::PrintDpb() {
|
||||
uint32_t i;
|
||||
|
||||
MSG("=======================");
|
||||
MSG("DPB buffer content: ");
|
||||
MSG("=======================");
|
||||
MSG("dpb_size = " << dpb_buffer_.dpb_size);
|
||||
MSG("num_pics_needed_for_output = " << dpb_buffer_.num_pics_needed_for_output);
|
||||
MSG("dpb_fullness = " << dpb_buffer_.dpb_fullness);
|
||||
MSG("Frame buffer store:");
|
||||
for (i = 0; i < HEVC_MAX_DPB_FRAMES; i++) {
|
||||
HevcPicInfo *p_buf = &dpb_buffer_.frame_buffer_list[i];
|
||||
MSG("Frame buffer " << i << ": pic_idx = " << p_buf->pic_idx << ", dec_buf_idx = " << p_buf->dec_buf_idx << ", pic_order_cnt = " << p_buf->pic_order_cnt << ", slice_pic_order_cnt_lsb = " << p_buf->slice_pic_order_cnt_lsb << ", decode_order_count = " << p_buf->decode_order_count << ", is_reference = " << p_buf->is_reference << ", use_status = " << p_buf->use_status << ", pic_output_flag = " << p_buf->pic_output_flag);
|
||||
}
|
||||
MSG("");
|
||||
|
||||
MSG("Decode buffer pool:");
|
||||
for(i = 0; i < dec_buf_pool_size_; i++) {
|
||||
DecodeFrameBuffer *p_dec_buf = &decode_buffer_pool_[i];
|
||||
MSG("Decode buffer " << i << ": use_status = " << p_dec_buf->use_status << ", pic_order_cnt = " << p_dec_buf->pic_order_cnt);
|
||||
}
|
||||
MSG("num_output_pics_ = " << num_output_pics_);
|
||||
if (num_output_pics_) {
|
||||
MSG("output_pic_list:");
|
||||
for (i = 0; i < num_output_pics_; i++) {
|
||||
MSG_NO_NEWLINE(output_pic_list_[i] << ", ");
|
||||
}
|
||||
MSG("");
|
||||
}
|
||||
}
|
||||
|
||||
void HevcVideoParser::PrintVappiBufInfo() {
|
||||
RocdecHevcPicParams *p_pic_param = &dec_pic_params_.pic_params.hevc;
|
||||
MSG("=======================");
|
||||
MSG("VAAPI Buffer Info: ");
|
||||
MSG("=======================");
|
||||
MSG("Current buffer:");
|
||||
MSG_NO_NEWLINE("pic_idx = " << p_pic_param->curr_pic.pic_idx << ", poc = " << p_pic_param->curr_pic.poc);
|
||||
MSG(", flags = 0x" << std::hex << p_pic_param->curr_pic.flags);
|
||||
MSG(std::dec);
|
||||
|
||||
MSG("Reference pictures:");
|
||||
for (int i = 0; i < 15; i++) {
|
||||
RocdecHevcPicture *p_ref_pic = &p_pic_param->ref_frames[i];
|
||||
MSG_NO_NEWLINE("Ref pic " << i << ": " << "pic_idx = " << p_ref_pic->pic_idx << ", poc = " << p_ref_pic->poc);
|
||||
MSG(", flags = 0x" << std::hex << p_ref_pic->flags);
|
||||
MSG_NO_NEWLINE(std::dec);
|
||||
}
|
||||
|
||||
MSG("Slice ref lists:")
|
||||
for (int slice_index = 0; slice_index < num_slices_; slice_index++) {
|
||||
RocdecHevcSliceParams *p_slice_param = &slice_param_list_[slice_index];
|
||||
HevcSliceInfo *p_slice_info = &slice_info_list_[slice_index];
|
||||
MSG("Slice " << slice_index << " ref list 0:");
|
||||
for (int i = 0; i <= p_slice_info->slice_header.num_ref_idx_l0_active_minus1; i++) {
|
||||
MSG("Index " << i << ": " << static_cast<uint32_t>(p_slice_param->ref_pic_list[0][i]));
|
||||
}
|
||||
if (p_slice_info->slice_header.slice_type == HEVC_SLICE_TYPE_B) {
|
||||
MSG("Slice " << slice_index << " ref list 1: ");
|
||||
for (int i = 0; i <= p_slice_info->slice_header.num_ref_idx_l1_active_minus1; i++) {
|
||||
MSG("Index " << i << ": " << static_cast<uint32_t>(p_slice_param->ref_pic_list[1][i]));
|
||||
}
|
||||
}
|
||||
MSG("");
|
||||
}
|
||||
}
|
||||
#endif // DBGINFO
|
||||
@@ -98,6 +98,7 @@ protected:
|
||||
*/
|
||||
typedef struct {
|
||||
int pic_idx; // picture index or id
|
||||
int dec_buf_idx; // frame index in decode buffer pool
|
||||
// POC info
|
||||
int32_t pic_order_cnt; // PicOrderCnt
|
||||
int32_t prev_poc_lsb; // prevPicOrderCntLsb
|
||||
@@ -107,7 +108,7 @@ protected:
|
||||
|
||||
uint32_t pic_output_flag; // PicOutputFlag
|
||||
uint32_t is_reference;
|
||||
uint32_t use_status; // 0 = empty; 1 = top used; 2 = bottom used; 3 = both fields or frame used
|
||||
uint32_t use_status; // refer to FrameBufUseStatus
|
||||
} HevcPicInfo;
|
||||
|
||||
/*! \brief Decoded picture buffer
|
||||
@@ -118,9 +119,6 @@ protected:
|
||||
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];
|
||||
|
||||
uint32_t num_output_pics; // number of pictures that are output after the decode call
|
||||
uint32_t output_pic_list[HEVC_MAX_DPB_FRAMES]; // sorted output picuture index to frame_buffer_list[]
|
||||
} DecodedPictureBuffer;
|
||||
|
||||
// Data members of HEVC class
|
||||
@@ -308,11 +306,16 @@ protected:
|
||||
*/
|
||||
int MarkOutputPictures();
|
||||
|
||||
/*! \brief Function to find a free buffer in the decode buffer pool
|
||||
* \return <tt>ParserResult</tt>
|
||||
*/
|
||||
ParserResult FindFreeInDecBufPool();
|
||||
|
||||
/*! \brief Function to find a free buffer in DPB for the current picture and mark it. Additional picture
|
||||
* bumping is done if needed. C.5.2.3.
|
||||
* \return Code in ParserResult form.
|
||||
* \return <tt>ParserResult</tt>
|
||||
*/
|
||||
int FindFreeBufAndMark();
|
||||
ParserResult FindFreeInDpbAndMark();
|
||||
|
||||
/*! \brief Function to bump one picture out of DPB. C.5.2.4.
|
||||
* \return Code in ParserResult form.
|
||||
@@ -333,6 +336,8 @@ protected:
|
||||
void PrintSliceSegHeader(HevcSliceSegHeader *slice_header_ptr);
|
||||
void PrintStRps(HevcShortTermRps *rps_ptr);
|
||||
void PrintLtRefInfo(HevcLongTermRps *lt_info_ptr);
|
||||
void PrintDpb();
|
||||
void PrintVappiBufInfo();
|
||||
#endif // DBGINFO
|
||||
|
||||
private:
|
||||
@@ -349,11 +354,6 @@ private:
|
||||
*/
|
||||
int SendPicForDecode();
|
||||
|
||||
/*! \brief Callback function to output decoded pictures from DPB for post-processing.
|
||||
* \return Return code in ParserResult form
|
||||
*/
|
||||
int OutputDecodedPictures();
|
||||
|
||||
bool IsIdrPic(HevcNalUnitHeader *nal_header_ptr);
|
||||
bool IsCraPic(HevcNalUnitHeader *nal_header_ptr);
|
||||
bool IsBlaPic(HevcNalUnitHeader *nal_header_ptr);
|
||||
|
||||
@@ -57,16 +57,65 @@ rocDecStatus RocVideoParser::Initialize(RocdecParserParams *pParams) {
|
||||
return ROCDEC_NOT_INITIALIZED;
|
||||
}
|
||||
// Initialize callback function pointers
|
||||
pfn_sequece_cb_ = pParams->pfn_sequence_callback; /**< Called before decoding frames and/or whenever there is a fmt change */
|
||||
pfn_sequece_cb_ = pParams->pfn_sequence_callback; /**< Called before decoding frames and/or whenever there is a fmt change */
|
||||
pfn_decode_picture_cb_ = pParams->pfn_decode_picture; /**< Called when a picture is ready to be decoded (decode order) */
|
||||
pfn_display_picture_cb_ = pParams->pfn_display_picture; /**< Called whenever a picture is ready to be displayed (display order) */
|
||||
pfn_get_sei_message_cb_ = pParams->pfn_get_sei_msg; /**< Called when all SEI messages are parsed for particular frame */
|
||||
pfn_display_picture_cb_ = pParams->pfn_display_picture; /**< Called whenever a picture is ready to be displayed (display order) */
|
||||
pfn_get_sei_message_cb_ = pParams->pfn_get_sei_msg; /**< Called when all SEI messages are parsed for particular frame */
|
||||
|
||||
parser_params_ = *pParams;
|
||||
|
||||
dec_buf_pool_size_ = parser_params_.max_num_decode_surfaces;
|
||||
decode_buffer_pool_.resize(dec_buf_pool_size_, {0});
|
||||
output_pic_list_.resize(dec_buf_pool_size_, 0xFF);
|
||||
InitDecBufPool();
|
||||
|
||||
return ROCDEC_SUCCESS;
|
||||
}
|
||||
|
||||
void RocVideoParser::InitDecBufPool() {
|
||||
for (int i = 0; i < dec_buf_pool_size_; i++) {
|
||||
decode_buffer_pool_[i].use_status = kNotUsed;
|
||||
decode_buffer_pool_[i].pic_order_cnt = 0;
|
||||
output_pic_list_[i] = 0xFF;
|
||||
}
|
||||
num_output_pics_ = 0;
|
||||
}
|
||||
|
||||
void RocVideoParser::CheckAndAdjustDecBufPoolSize(int dpb_size) {
|
||||
int min_dec_buf_pool_size = dpb_size + (parser_params_.max_display_delay > DECODE_BUF_POOL_EXTENSION ? parser_params_.max_display_delay : DECODE_BUF_POOL_EXTENSION);
|
||||
if ( dec_buf_pool_size_ < min_dec_buf_pool_size) {
|
||||
dec_buf_pool_size_ = min_dec_buf_pool_size;
|
||||
decode_buffer_pool_.resize(dec_buf_pool_size_, {0});
|
||||
output_pic_list_.resize(dec_buf_pool_size_, 0xFF);
|
||||
InitDecBufPool();
|
||||
}
|
||||
}
|
||||
|
||||
ParserResult RocVideoParser::OutputDecodedPictures(bool no_delay) {
|
||||
RocdecParserDispInfo disp_info = {0};
|
||||
disp_info.progressive_frame = 1; // not used
|
||||
disp_info.top_field_first = 1; // not used
|
||||
|
||||
int disp_delay = no_delay ? 0 : parser_params_.max_display_delay;
|
||||
if (num_output_pics_ > disp_delay) {
|
||||
int num_disp = num_output_pics_ - disp_delay;
|
||||
for (int i = 0; i < num_disp; i++) {
|
||||
disp_info.picture_index = output_pic_list_[i];
|
||||
pfn_display_picture_cb_(parser_params_.user_data, &disp_info);
|
||||
decode_buffer_pool_[output_pic_list_[i]].use_status &= ~kFrameUsedForDisplay;
|
||||
}
|
||||
|
||||
num_output_pics_ = disp_delay;
|
||||
// Shift the remaining frames to the top
|
||||
if (num_output_pics_) {
|
||||
for (int i = 0; i < num_output_pics_; i++) {
|
||||
output_pic_list_[i] = output_pic_list_[i + num_disp];
|
||||
}
|
||||
}
|
||||
}
|
||||
return PARSER_OK;
|
||||
}
|
||||
|
||||
ParserResult RocVideoParser::GetNalUnit() {
|
||||
bool start_code_found = false;
|
||||
|
||||
|
||||
@@ -78,6 +78,15 @@ typedef struct {
|
||||
#define INIT_SLICE_LIST_NUM 16 // initial slice information/parameter struct list size
|
||||
#define INIT_SEI_MESSAGE_COUNT 16 // initial SEI message count
|
||||
#define INIT_SEI_PAYLOAD_BUF_SIZE 1024 * 1024 // initial SEI payload buffer size, 1 MB
|
||||
#define DECODE_BUF_POOL_EXTENSION 2
|
||||
|
||||
enum {
|
||||
kNotUsed = 0,
|
||||
kTopFieldUsedForDecode = 1,
|
||||
kBottomFieldUsedForDecode = 1 << 1,
|
||||
kFrameUsedForDecode = kTopFieldUsedForDecode | kBottomFieldUsedForDecode,
|
||||
kFrameUsedForDisplay = 1 << 2
|
||||
} FrameBufUseStatus;
|
||||
|
||||
/**
|
||||
* @brief Base class for video parsing
|
||||
@@ -109,6 +118,21 @@ protected:
|
||||
uint32_t pic_height_;
|
||||
bool new_sps_activated_;
|
||||
|
||||
// Decoded buffer pool
|
||||
typedef struct {
|
||||
uint32_t use_status; // refer to FrameBufUseStatus
|
||||
uint32_t pic_order_cnt;
|
||||
} DecodeFrameBuffer;
|
||||
uint32_t dec_buf_pool_size_; /* Number of decoded frame surfaces in the pool which are recycled. The size should be greater
|
||||
than or equal to DPB size (normally greater to guarantee smooth operations). The value is
|
||||
set to max_num_decode_surfaces from the decoder but parser checks and increases if needed. */
|
||||
/* This array maps to VA surface array allocated at VA-API layer. A frame in the pool is identified by its index in the array, which
|
||||
* is used to retrieve the VA surface Id.
|
||||
*/
|
||||
std::vector<DecodeFrameBuffer> decode_buffer_pool_;
|
||||
uint32_t num_output_pics_; // number of pictures that are ready to be ouput
|
||||
std::vector<uint32_t> output_pic_list_; // sorted output frame index to decode_buffer_pool_
|
||||
|
||||
Rational frame_rate_;
|
||||
|
||||
RocdecVideoFormat video_format_params_;
|
||||
@@ -141,6 +165,17 @@ protected:
|
||||
uint32_t sei_payload_buf_size_;
|
||||
uint32_t sei_payload_size_; // total SEI payload size of the current frame
|
||||
|
||||
/*! \brief Function to check the initially set (by decoder) decode buffer pool size and adjust if needed
|
||||
* \param dpb_size The DPB buffer size of the current sequence
|
||||
*/
|
||||
void CheckAndAdjustDecBufPoolSize(int dpb_size);
|
||||
|
||||
/*! \brief Callback function to output decoded pictures from DPB for post-processing.
|
||||
* \param [in] no_delay Indicator to override the display delay parameter wth no delay
|
||||
* \return <tt>ParserResult</tt>
|
||||
*/
|
||||
ParserResult OutputDecodedPictures(bool no_delay);
|
||||
|
||||
/*! \brief Function to get the NAL Unit data
|
||||
* \return Returns OK if successful, else error code
|
||||
*/
|
||||
@@ -161,6 +196,10 @@ protected:
|
||||
* \return No return value
|
||||
*/
|
||||
void ParseSeiMessage(uint8_t *nalu, size_t size);
|
||||
|
||||
/*! \brief Function to initialize the decoded buffer pool
|
||||
*/
|
||||
void InitDecBufPool();
|
||||
};
|
||||
|
||||
// helpers
|
||||
|
||||
@@ -23,9 +23,9 @@ THE SOFTWARE.
|
||||
#include "roc_video_dec.h"
|
||||
|
||||
RocVideoDecoder::RocVideoDecoder(int device_id, OutputSurfaceMemoryType out_mem_type, rocDecVideoCodec codec, bool force_zero_latency,
|
||||
const Rect *p_crop_rect, bool extract_user_sei_Message, int max_width, int max_height, uint32_t clk_rate) :
|
||||
const Rect *p_crop_rect, bool extract_user_sei_Message, uint32_t disp_delay, int max_width, int max_height, uint32_t clk_rate) :
|
||||
device_id_{device_id}, out_mem_type_(out_mem_type), codec_id_(codec), b_force_zero_latency_(force_zero_latency),
|
||||
b_extract_sei_message_(extract_user_sei_Message), max_width_ (max_width), max_height_(max_height) {
|
||||
b_extract_sei_message_(extract_user_sei_Message), disp_delay_(disp_delay), max_width_ (max_width), max_height_(max_height) {
|
||||
|
||||
if (!InitHIP(device_id_)) {
|
||||
THROW("Failed to initilize the HIP");
|
||||
@@ -39,9 +39,9 @@ RocVideoDecoder::RocVideoDecoder(int device_id, OutputSurfaceMemoryType out_mem_
|
||||
// create rocdec videoparser
|
||||
RocdecParserParams parser_params = {};
|
||||
parser_params.codec_type = codec_id_;
|
||||
parser_params.max_num_decode_surfaces = 1;
|
||||
parser_params.max_num_decode_surfaces = 1; // let the parser to determine the decode buffer pool size
|
||||
parser_params.clock_rate = clk_rate;
|
||||
parser_params.max_display_delay = 0;
|
||||
parser_params.max_display_delay = disp_delay_;
|
||||
parser_params.user_data = this;
|
||||
parser_params.pfn_sequence_callback = HandleVideoSequenceProc;
|
||||
parser_params.pfn_decode_picture = HandlePictureDecodeProc;
|
||||
|
||||
@@ -50,7 +50,8 @@ extern "C" {
|
||||
* \brief AMD The rocDecode video decoder for AMD’s GPUs.
|
||||
*/
|
||||
|
||||
#define MAX_FRAME_NUM 16
|
||||
#define MAX_FRAME_NUM 16
|
||||
|
||||
typedef int (ROCDECAPI *PFNRECONFIGUEFLUSHCALLBACK)(void *, uint32_t, void *);
|
||||
|
||||
typedef enum SeiAvcHevcPayloadType_enum {
|
||||
@@ -177,7 +178,7 @@ class RocVideoDecoder {
|
||||
* @param force_zero_latency
|
||||
*/
|
||||
RocVideoDecoder(int device_id, OutputSurfaceMemoryType out_mem_type, rocDecVideoCodec codec, bool force_zero_latency = false,
|
||||
const Rect *p_crop_rect = nullptr, bool extract_user_SEI_Message = false, int max_width = 0, int max_height = 0,
|
||||
const Rect *p_crop_rect = nullptr, bool extract_user_SEI_Message = false, uint32_t disp_delay = 0, int max_width = 0, int max_height = 0,
|
||||
uint32_t clk_rate = 1000);
|
||||
~RocVideoDecoder();
|
||||
|
||||
@@ -426,6 +427,7 @@ class RocVideoDecoder {
|
||||
OutputSurfaceMemoryType out_mem_type_ = OUT_SURFACE_MEM_DEV_INTERNAL;
|
||||
bool b_extract_sei_message_ = false;
|
||||
bool b_force_zero_latency_ = false;
|
||||
uint32_t disp_delay_;
|
||||
ReconfigParams *p_reconfig_params_ = nullptr;
|
||||
int32_t num_frames_flushed_during_reconfig_ = 0;
|
||||
hipDeviceProp_t hip_dev_prop_;
|
||||
|
||||
Reference in New Issue
Block a user