From 7a537bbb888aff44b022660f3ab04ed1bd3895ae Mon Sep 17 00:00:00 2001 From: jeffqjiangNew <142832361+jeffqjiangNew@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:08:24 -0400 Subject: [PATCH] Added all preparing steps in decode process before calling VA-API. (#32) * rocDecode/HEVC parsing: Implemented correct logic to set active VPS, SPS and PPS: start from slice header and up. Added video image size change detection. Fixed slice_segment_address bits calculation in slice segment header parsing. * rocDecode/HEVC: Changed variable naming to Google style. * rocDecode/HEVC: Added VPS, SPS, PPS, and slice segment header content logging functions for debug purposes. * rocDecode/HEVC: Compacted opening bracket lines to keep coding style consistency. * * rocDecode/HEVC: Fixed an issue in profile-tier-level parsing where 44 bits are skipped in an incorrect way using ReadBits() which can only consume 32 bits max. Also formated SPS parsing code by using pointer instead of array element. * * rocDecode/HEVC: Fixed the incorrect array size for sps_max_dec_pic_buffering_minus1, sps_max_num_reorder_pics and sps_max_num_reorder_pics in SPS structure define. * * rocDecode/HEVC: Modified scaling list parsing to make sure we explicitly follow the spec. * * rocDecode/HEVC: Added a few syntax elements to short team RPS structure, updated RPS parsing function and logging function. * * rocDecode/HEVC: In PPS parsing function, use structure pointer instead of structure array element to improve coding clarity. * * rocDecode/HEVC: Compacted the opening bracket lines. No functional changes. * * rocDecode/HEVC: Added full parsing of slice segment header. Added PPS range extension parsing. * * rocDecode/HEVC: Fixed a build error in debug mode due to merging from master branch: removing a redundant debug function. * * rocDecode/HEVC: Changed the condition for sequence call back from picture size change to more general case where a new SPS is activated. Also moved the call from slice header parsing to upper level where frame data is processed. * * rocDecode: Compacted opening bracket line. No functional changes. * * rocDecode/HEVC: Moved POC calculation from slice header parsing to picture level, since we only need to do the calculation once per picture. * * rocDecode/HEVC: Added RPS decode function. * *rocDecode/HEVC: Added reference picture list construction. * * rocDecode/HEVC: Added current picture marking in DPB. * * rocDecode/HEVC: Removed VA surface id from DPB buffer info structure. * * rocDecode/HEVC: Do not construct ref list for I pictures. --- src/parser/hevc_parser.cpp | 373 +++++++++++++++++++++++++++++++------ src/parser/hevc_parser.h | 98 ++++++++-- 2 files changed, 394 insertions(+), 77 deletions(-) diff --git a/src/parser/hevc_parser.cpp b/src/parser/hevc_parser.cpp index df197078cd..07e1cf7002 100644 --- a/src/parser/hevc_parser.cpp +++ b/src/parser/hevc_parser.cpp @@ -32,7 +32,9 @@ HEVCVideoParser::HEVCVideoParser() { m_pps_ = NULL; m_sh_ = NULL; m_sh_copy_ = NULL; - m_slice_ = NULL; + + memset(&curr_pic_info_, 0, sizeof(HevcPicInfo)); + memset(&dpb_buffer_, 0, sizeof(DecodedPictureBuffer)); } rocDecStatus HEVCVideoParser::Initialize(RocdecParserParams *p_params) { @@ -86,9 +88,6 @@ HEVCVideoParser::~HEVCVideoParser() { if (m_sh_copy_) { delete m_sh_copy_; } - if (m_slice_) { - delete m_slice_; - } } HEVCVideoParser::VpsData* HEVCVideoParser::AllocVps() { @@ -127,18 +126,6 @@ HEVCVideoParser::PpsData* HEVCVideoParser::AllocPps() { return p; } -HEVCVideoParser::SliceData* HEVCVideoParser::AllocSlice() { - SliceData *p = nullptr; - try { - p = new SliceData; - } - catch(const std::exception& e) { - ERR(STR("Failed to alloc Slice Data, ") + STR(e.what())) - } - memset(p, 0, sizeof(SliceData)); - return p; -} - HEVCVideoParser::SliceHeaderData* HEVCVideoParser::AllocSliceHeader() { SliceHeaderData *p = nullptr; try { @@ -156,7 +143,6 @@ ParserResult HEVCVideoParser::Init() { m_vps_ = AllocVps(); m_sps_ = AllocSps(); m_pps_ = AllocPps(); - m_slice_ = AllocSlice(); m_sh_ = AllocSliceHeader(); m_sh_copy_ = AllocSliceHeader(); return PARSER_OK; @@ -248,7 +234,6 @@ void HEVCVideoParser::FillSeqCallbackFn(SpsData* sps_data) { bool HEVCVideoParser::ParseFrameData(const uint8_t* p_stream, uint32_t frame_data_size) { int ret = PARSER_OK; - NalUnitHeader nal_unit_header; frame_data_buffer_ptr_ = (uint8_t*)p_stream; frame_data_size_ = frame_data_size; @@ -272,8 +257,8 @@ bool HEVCVideoParser::ParseFrameData(const uint8_t* p_stream, uint32_t frame_dat // start code + NAL unit header = 5 bytes int ebsp_size = nal_unit_size_ - 5 > RBSP_BUF_SIZE ? RBSP_BUF_SIZE : nal_unit_size_ - 5; // only copy enough bytes for header parsing - nal_unit_header = ParseNalUnitHeader(&frame_data_buffer_ptr_[curr_start_code_offset_ + 3]); - switch (nal_unit_header.nal_unit_type) { + nal_unit_header_ = ParseNalUnitHeader(&frame_data_buffer_ptr_[curr_start_code_offset_ + 3]); + switch (nal_unit_header_.nal_unit_type) { case NAL_UNIT_VPS: { memcpy(m_rbsp_buf_, (frame_data_buffer_ptr_ + curr_start_code_offset_ + 5), ebsp_size); m_rbsp_size_ = EBSPtoRBSP(m_rbsp_buf_, 0, ebsp_size); @@ -315,7 +300,21 @@ bool HEVCVideoParser::ParseFrameData(const uint8_t* p_stream, uint32_t frame_dat m_rbsp_size_ = EBSPtoRBSP(m_rbsp_buf_, 0, ebsp_size); // For each picture, only parse the first slice header if (slice_num_ == 0) { - ParseSliceHeader(nal_unit_header.nal_unit_type, m_rbsp_buf_, m_rbsp_size_); + ParseSliceHeader(nal_unit_header_.nal_unit_type, m_rbsp_buf_, m_rbsp_size_); + + // Get POC + CalculateCurrPOC(); + + // Decode RPS + DeocdeRps(); + + // Construct ref lists + if(m_sh_->slice_type == HEVC_SLICE_TYPE_P || m_sh_->slice_type == HEVC_SLICE_TYPE_B) { + ConstructRefPicLists(); + } + + // Find a free buffer in DPM and mark as used + FindFreeBufAndMark(); } slice_num_++; break; @@ -1192,39 +1191,11 @@ bool HEVCVideoParser::ParseSliceHeader(uint32_t nal_unit_type, uint8_t *nalu, si if (sps_ptr->separate_colour_plane_flag) { m_sh_->colour_plane_id = Parser::ReadBits(nalu, offset, 2); } - if (nal_unit_type == NAL_UNIT_CODED_SLICE_IDR_W_RADL || nal_unit_type == NAL_UNIT_CODED_SLICE_IDR_N_LP) { - m_slice_->curr_poc = 0; - m_slice_->prev_poc = m_slice_->curr_poc; - m_slice_->curr_poc_lsb = 0; - m_slice_->curr_poc_msb = 0; - m_slice_->prev_poc_lsb = m_slice_->curr_poc_lsb; - m_slice_->prev_poc_msb = m_slice_->curr_poc_msb; - } - else { + + if (nal_unit_type != NAL_UNIT_CODED_SLICE_IDR_W_RADL && nal_unit_type != NAL_UNIT_CODED_SLICE_IDR_N_LP) { //length of slice_pic_order_cnt_lsb is log2_max_pic_order_cnt_lsb_minus4 + 4 bits. m_sh_->slice_pic_order_cnt_lsb = Parser::ReadBits(nalu, offset, (sps_ptr->log2_max_pic_order_cnt_lsb_minus4 + 4)); - //get POC - m_slice_->curr_poc_lsb = m_sh_->slice_pic_order_cnt_lsb; - m_slice_->max_poc_lsb = 1 << (sps_ptr->log2_max_pic_order_cnt_lsb_minus4 + 4); - - if (nal_unit_type >= NAL_UNIT_CODED_SLICE_BLA_W_LP && nal_unit_type < NAL_UNIT_CODED_SLICE_CRA_NUT) { - m_slice_->curr_poc_msb = 0; - } - else { - if ((m_slice_->curr_poc_lsb < m_slice_->prev_poc_lsb) && ((m_slice_->prev_poc_lsb - m_slice_->curr_poc_lsb) >= (m_slice_->max_poc_lsb / 2))) - m_slice_->curr_poc_msb = m_slice_->prev_poc_msb + m_slice_->max_poc_lsb; - else if ((m_slice_->curr_poc_lsb > m_slice_->prev_poc_lsb) && ((m_slice_->curr_poc_lsb - m_slice_->prev_poc_lsb) > (m_slice_->max_poc_lsb / 2))) - m_slice_->curr_poc_msb = m_slice_->prev_poc_msb - m_slice_->max_poc_lsb; - else - m_slice_->curr_poc_msb = m_slice_->prev_poc_msb; - } - - m_slice_->curr_poc = m_slice_->curr_poc_lsb + m_slice_->curr_poc_msb; - m_slice_->prev_poc = m_slice_->curr_poc; - m_slice_->prev_poc_lsb = m_slice_->curr_poc_lsb; - m_slice_->prev_poc_msb = m_slice_->curr_poc_msb; - m_sh_->short_term_ref_pic_set_sps_flag = Parser::GetBit(nalu, offset); int32_t pos = offset; if (!m_sh_->short_term_ref_pic_set_sps_flag) { @@ -1273,7 +1244,14 @@ bool HEVCVideoParser::ParseSliceHeader(uint32_t nal_unit_type, uint8_t *nalu, si } m_sh_->delta_poc_msb_present_flag[i] = Parser::GetBit(nalu, offset); if (m_sh_->delta_poc_msb_present_flag[i]) { - m_sh_->delta_poc_msb_cycle_lt[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + // Store DeltaPocMsbCycleLt in delta_poc_msb_cycle_lt for later use + int delta_poc_msb_cycle_lt = Parser::ExpGolomb::ReadUe(nalu, offset); + if ( i == 0 || i == m_sh_->num_long_term_sps) { + m_sh_->delta_poc_msb_cycle_lt[i] = delta_poc_msb_cycle_lt; + } + else { + m_sh_->delta_poc_msb_cycle_lt[i] = delta_poc_msb_cycle_lt + m_sh_->delta_poc_msb_cycle_lt[i - 1]; + } } } } @@ -1308,12 +1286,12 @@ bool HEVCVideoParser::ParseSliceHeader(uint32_t nal_unit_type, uint8_t *nalu, si // 7.3.6.2 Reference picture list modification // Calculate NumPicTotalCurr - int num_pic_total_curr = 0; + num_pic_total_curr_ = 0; H265ShortTermRPS *st_rps_ptr = &m_sh_->st_rps; // Check the combined list for (int i = 0; i < st_rps_ptr->num_of_delta_poc; i++) { if (st_rps_ptr->used_by_curr_pic[i]) { - num_pic_total_curr++; + num_pic_total_curr_++; } } @@ -1321,14 +1299,14 @@ bool HEVCVideoParser::ParseSliceHeader(uint32_t nal_unit_type, uint8_t *nalu, si // Check the combined list for (int i = 0; i < lt_rps_ptr->num_of_pics; i++) { if (lt_rps_ptr->used_by_curr_pic[i]) { - num_pic_total_curr++; + num_pic_total_curr_++; } } - if (pps_ptr->lists_modification_present_flag && num_pic_total_curr > 1) + if (pps_ptr->lists_modification_present_flag && num_pic_total_curr_ > 1) { int list_entry_bits = 0; - while ((1 << list_entry_bits) < num_pic_total_curr) { + while ((1 << list_entry_bits) < num_pic_total_curr_) { list_entry_bits++; } @@ -1431,6 +1409,287 @@ bool HEVCVideoParser::ParseSliceHeader(uint32_t nal_unit_type, uint8_t *nalu, si return false; } +void HEVCVideoParser::CalculateCurrPOC() { + if (nal_unit_header_.nal_unit_type == NAL_UNIT_CODED_SLICE_IDR_W_RADL || nal_unit_header_.nal_unit_type == NAL_UNIT_CODED_SLICE_IDR_N_LP) { + curr_pic_info_.pic_order_cnt = 0; + curr_pic_info_.prev_poc_lsb = 0; + curr_pic_info_.prev_poc_msb = 0; + curr_pic_info_.slice_pic_order_cnt_lsb = 0; + } + else { + int max_poc_lsb = 1 << (m_sps_[m_active_sps_id_].log2_max_pic_order_cnt_lsb_minus4 + 4); // MaxPicOrderCntLsb + int poc_msb; // PicOrderCntMsb + // If the current picture is an IRAP picture with NoRaslOutputFlag equal to 1, PicOrderCntMsb is set equal to 0. + if (nal_unit_header_.nal_unit_type >= NAL_UNIT_CODED_SLICE_BLA_W_LP && nal_unit_header_.nal_unit_type <= NAL_UNIT_RESERVED_IRAP_VCL23) { + poc_msb = 0; + } + else { + if ((m_sh_->slice_pic_order_cnt_lsb < curr_pic_info_.prev_poc_lsb) && ((curr_pic_info_.prev_poc_lsb - m_sh_->slice_pic_order_cnt_lsb) >= (max_poc_lsb / 2))) { + poc_msb = curr_pic_info_.prev_poc_msb + max_poc_lsb; + } + else if ((m_sh_->slice_pic_order_cnt_lsb > curr_pic_info_.prev_poc_lsb) && ((m_sh_->slice_pic_order_cnt_lsb - curr_pic_info_.prev_poc_lsb) > (max_poc_lsb / 2))) { + poc_msb = curr_pic_info_.prev_poc_msb - max_poc_lsb; + } + else { + poc_msb = curr_pic_info_.prev_poc_msb; + } + } + + curr_pic_info_.pic_order_cnt = poc_msb + m_sh_->slice_pic_order_cnt_lsb; + curr_pic_info_.prev_poc_lsb = m_sh_->slice_pic_order_cnt_lsb; + curr_pic_info_.prev_poc_msb = poc_msb; + curr_pic_info_.slice_pic_order_cnt_lsb = m_sh_->slice_pic_order_cnt_lsb; + } +} + +void HEVCVideoParser::DeocdeRps() { + int i, j, k; + int curr_delta_proc_msb_present_flag[HEVC_MAX_NUM_REF_PICS] = {0}; // CurrDeltaPocMsbPresentFlag + int foll_delta_poc_msb_present_flag[HEVC_MAX_NUM_REF_PICS] = {0}; // FollDeltaPocMsbPresentFlag + int max_poc_lsb = 1 << (m_sps_[m_active_sps_id_].log2_max_pic_order_cnt_lsb_minus4 + 4); // MaxPicOrderCntLsb + + // When the current picture is an IRAP picture with NoRaslOutputFlag equal to 1, all reference pictures with + // nuh_layer_id equal to currPicLayerId currently in the DPB (if any) are marked as "unused for reference". + if (nal_unit_header_.nal_unit_type >= NAL_UNIT_CODED_SLICE_BLA_W_LP && nal_unit_header_.nal_unit_type <= NAL_UNIT_RESERVED_IRAP_VCL23) { + for (i = 0; i < HVC_MAX_DPB_FRAMES; i++) { + dpb_buffer_.frame_buffer_list[i].is_reference = kUnusedForReference; + } + } + + if (nal_unit_header_.nal_unit_type == NAL_UNIT_CODED_SLICE_IDR_W_RADL || nal_unit_header_.nal_unit_type == NAL_UNIT_CODED_SLICE_IDR_N_LP) { + num_poc_st_curr_before_ = 0; + num_poc_st_curr_after_ = 0; + num_poc_st_foll_ = 0; + num_poc_lt_curr_ = 0; + num_poc_lt_foll_ = 0; + memset(poc_st_curr_before_, 0, sizeof(int32_t) * HEVC_MAX_NUM_REF_PICS); + memset(poc_st_curr_after_, 0, sizeof(int32_t) * HEVC_MAX_NUM_REF_PICS); + memset(poc_st_foll_, 0, sizeof(int32_t) * HEVC_MAX_NUM_REF_PICS); + memset(poc_lt_curr_, 0, sizeof(int32_t) * HEVC_MAX_NUM_REF_PICS); + memset(poc_lt_foll_, 0, sizeof(int32_t) * HEVC_MAX_NUM_REF_PICS); + } + else { + H265ShortTermRPS *rps_ptr = &m_sh_->st_rps; + for (i = 0, j = 0, k = 0; i < rps_ptr->num_negative_pics; i++) { + if (rps_ptr->used_by_curr_pic[i]) { // UsedByCurrPicS0 + poc_st_curr_before_[j++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc[i]; // DeltaPocS0 + } + else { + poc_st_foll_[k++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc[i]; + } + } + num_poc_st_curr_before_ = j; + + // UsedByCurrPicS1 follows UsedByCurrPicS0 in used_by_curr_pic. DeltaPocS1 follows DeltaPocS0 in delta_poc. + for (j = 0; i < rps_ptr->num_of_delta_poc; i++ ) { + if (rps_ptr->used_by_curr_pic[i]) { // UsedByCurrPicS1 + poc_st_curr_after_[j++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc[i]; // DeltaPocS1 + } + else { + poc_st_foll_[k++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc[i]; // DeltaPocS1 + } + } + num_poc_st_curr_after_ = j; + num_poc_st_foll_ = k; + + H265LongTermRPS *lt_rps_ptr = &m_sh_->lt_rps; + for (i = 0, j = 0, k = 0; i < lt_rps_ptr->num_of_pics; i++) { + uint32_t poc_lt = lt_rps_ptr->pocs[i]; // oocLt + if (m_sh_->delta_poc_msb_present_flag[i]) { + poc_lt += curr_pic_info_.pic_order_cnt - m_sh_->delta_poc_msb_cycle_lt[i] * max_poc_lsb - curr_pic_info_.pic_order_cnt & (max_poc_lsb - 1); + } + + if (lt_rps_ptr->used_by_curr_pic[i]) { + poc_lt_curr_[j] = poc_lt; + curr_delta_proc_msb_present_flag[j++] = m_sh_->delta_poc_msb_present_flag[i]; + } + else { + poc_lt_foll_[k] = poc_lt; + foll_delta_poc_msb_present_flag[k++] = m_sh_->delta_poc_msb_present_flag[i]; + } + } + num_poc_lt_curr_ = j; + num_poc_lt_foll_ = k; + + /* + * RPS derivation and picture marking + */ + // Init as "no reference picture" + for (i = 0; i < HEVC_MAX_NUM_REF_PICS; i++) { + ref_pic_set_st_curr_before_[i] = 0xFF; + ref_pic_set_st_curr_after_[i] = 0xFF; + ref_pic_set_st_foll_[i] = 0xFF; + ref_pic_set_lt_curr_[i] = 0xFF; + ref_pic_set_lt_foll_[i] = 0xFF; + } + + // Mark all in DPB as unused. We will mark them back while we go through the ref lists. The rest will be actually unused. + for (i = 0; i < HVC_MAX_DPB_FRAMES; i++) { + dpb_buffer_.frame_buffer_list[i].is_reference = kUnusedForReference; + } + + /// Short term reference pictures + for (i = 0; i < num_poc_st_curr_before_; i++) { + for (j = 0; j < HVC_MAX_DPB_FRAMES; j++) { + if (poc_st_curr_before_[i] == dpb_buffer_.frame_buffer_list[j].pic_order_cnt) { + ref_pic_set_st_curr_before_[i] = j; // RefPicSetStCurrBefore. Use DPB buffer index for now + dpb_buffer_.frame_buffer_list[j].is_reference = kUsedForShortTerm; + break; + } + } + } + + for (i = 0; i < num_poc_st_curr_after_; i++) { + for (j = 0; j < HVC_MAX_DPB_FRAMES; j++) { + if (poc_st_curr_after_[i] == dpb_buffer_.frame_buffer_list[j].pic_order_cnt) { + ref_pic_set_st_curr_after_[i] = j; // RefPicSetStCurrAfter + dpb_buffer_.frame_buffer_list[j].is_reference = kUsedForShortTerm; + break; + } + } + } + + for ( i = 0; i < num_poc_st_foll_; i++ ) { + for (j = 0; j < HVC_MAX_DPB_FRAMES; j++) { + if (poc_st_foll_[i] == dpb_buffer_.frame_buffer_list[j].pic_order_cnt) { + ref_pic_set_st_foll_[i] = j; // RefPicSetStFoll + dpb_buffer_.frame_buffer_list[j].is_reference = kUsedForShortTerm; + break; + } + } + } + + /// Long term reference pictures + for (i = 0; i < num_poc_lt_curr_; i++) { + for (j = 0; j < HVC_MAX_DPB_FRAMES; j++) { + if(!curr_delta_proc_msb_present_flag[i]) { + if (poc_lt_curr_[i] == (dpb_buffer_.frame_buffer_list[j].pic_order_cnt & (max_poc_lsb - 1))) { + ref_pic_set_lt_curr_[i] = j; // RefPicSetLtCurr + dpb_buffer_.frame_buffer_list[j].is_reference = kUsedForLongTerm; + break; + } + } + else { + if (poc_lt_curr_[i] == dpb_buffer_.frame_buffer_list[j].pic_order_cnt) { + ref_pic_set_lt_curr_[i] = j; // RefPicSetLtCurr + dpb_buffer_.frame_buffer_list[j].is_reference = kUsedForLongTerm; + break; + } + } + } + } + + for (i = 0; i < num_poc_lt_foll_; i++) { + for (j = 0; j < HVC_MAX_DPB_FRAMES; j++) { + if(!foll_delta_poc_msb_present_flag[i]) { + if (poc_lt_foll_[i] == (dpb_buffer_.frame_buffer_list[j].pic_order_cnt & (max_poc_lsb - 1))) { + ref_pic_set_lt_foll_[i] = j; // RefPicSetLtFoll + dpb_buffer_.frame_buffer_list[j].is_reference = kUsedForLongTerm; + break; + } + } + else { + if (poc_lt_foll_[i] == dpb_buffer_.frame_buffer_list[j].pic_order_cnt) { + ref_pic_set_lt_foll_[i] = j; // RefPicSetLtFoll + dpb_buffer_.frame_buffer_list[j].is_reference = kUsedForLongTerm; + break; + } + } + } + } + } +} + +void HEVCVideoParser::ConstructRefPicLists() { + + uint32_t num_rps_curr_temp_list; // NumRpsCurrTempList0 or NumRpsCurrTempList1; + int i, j; + int rIdx; + uint32_t ref_pic_list_temp[HEVC_MAX_NUM_REF_PICS]; // RefPicListTemp0 or RefPicListTemp1 + + /// List 0 + rIdx = 0; + num_rps_curr_temp_list = std::max(m_sh_->num_ref_idx_l0_active_minus1 + 1, num_pic_total_curr_); + + while (rIdx < num_rps_curr_temp_list) { + for (i = 0; i < num_poc_st_curr_before_ && rIdx < num_rps_curr_temp_list; rIdx++, i++) { + ref_pic_list_temp[rIdx] = ref_pic_set_st_curr_before_[i]; + } + + for (i = 0; i < num_poc_st_curr_after_ && rIdx < num_rps_curr_temp_list; rIdx++, i++) { + ref_pic_list_temp[rIdx] = ref_pic_set_st_curr_after_[i]; + } + + for (i = 0; i < num_poc_lt_curr_ && rIdx < num_rps_curr_temp_list; rIdx++, i++) { + ref_pic_list_temp[rIdx] = ref_pic_set_lt_curr_[i]; + } + } + + for( rIdx = 0; rIdx <= m_sh_->num_ref_idx_l0_active_minus1; rIdx++) { + ref_pic_list_0_[rIdx] = m_sh_->ref_pic_list_modification_flag_l0 ? ref_pic_list_temp[m_sh_->list_entry_l0[rIdx]] : ref_pic_list_temp[rIdx]; + } + + /// List 1 + if (m_sh_->slice_type == HEVC_SLICE_TYPE_B) { + rIdx = 0; + num_rps_curr_temp_list = std::max(m_sh_->num_ref_idx_l1_active_minus1 + 1, num_pic_total_curr_); + + while (rIdx < num_rps_curr_temp_list) { + for (i = 0; i < num_poc_st_curr_after_ && rIdx < num_rps_curr_temp_list; rIdx++, i++) { + ref_pic_list_temp[rIdx] = ref_pic_set_st_curr_after_[i]; + } + + for (i = 0; i < num_poc_st_curr_before_ && rIdx < num_rps_curr_temp_list; rIdx++, i++ ) { + ref_pic_list_temp[rIdx] = ref_pic_set_st_curr_before_[i]; + } + + for (i = 0; i < num_poc_lt_curr_ && rIdx < num_rps_curr_temp_list; rIdx++, i++ ) { + ref_pic_list_temp[rIdx] = ref_pic_set_lt_curr_[i]; + } + } + + for( rIdx = 0; rIdx <= m_sh_->num_ref_idx_l1_active_minus1; rIdx++) { + ref_pic_list_1_[rIdx] = m_sh_->ref_pic_list_modification_flag_l1 ? ref_pic_list_temp[m_sh_->list_entry_l1[rIdx]] : ref_pic_list_temp[rIdx]; + } + } +} + +int HEVCVideoParser::FindFreeBufAndMark() { + int i; + + // Clear usage flags. For now, buffers that are unused for refrence are marked as empty. + // Todo: implement HEVC DPU output policy + dpb_buffer_.dpb_fullness = 0; + for (i = 0; i < HVC_MAX_DPB_FRAMES; i++) { + if (dpb_buffer_.frame_buffer_list[i].is_reference == kUnusedForReference) { + dpb_buffer_.frame_buffer_list[i].use_status = 0; + } + else { + dpb_buffer_.frame_buffer_list[i].use_status = 3; // frame used + dpb_buffer_.dpb_fullness++; + } + } + + if (dpb_buffer_.dpb_fullness == HVC_MAX_DPB_FRAMES) { + // Buffer is full + return PARSER_NOT_FOUND; + } + else { + for (i = 0; i < HVC_MAX_DPB_FRAMES; i++) { + if (dpb_buffer_.frame_buffer_list[i].use_status == 0) { + break; + } + } + } + + dpb_buffer_.frame_buffer_list[i] = curr_pic_info_; + dpb_buffer_.frame_buffer_list[i].is_reference = kUsedForShortTerm; + dpb_buffer_.frame_buffer_list[i].use_status = 3; + dpb_buffer_.dpb_fullness++; + + return PARSER_OK; +} + size_t HEVCVideoParser::EBSPtoRBSP(uint8_t *streamBuffer,size_t begin_bytepos, size_t end_bytepos) { int count = 0; if (end_bytepos < begin_bytepos) { diff --git a/src/parser/hevc_parser.h b/src/parser/hevc_parser.h index 02e52be1bc..3436b368ef 100644 --- a/src/parser/hevc_parser.h +++ b/src/parser/hevc_parser.h @@ -41,6 +41,8 @@ extern int scaling_list_default_3[1][2][64]; #define MAX_SPS_COUNT 16 // 7.3.2.2.1 #define MAX_PPS_COUNT 64 // 7.4.3.3.1 #define RBSP_BUF_SIZE 1024 // enough to parse any parameter sets or slice headers +#define HVC_MAX_DPB_FRAMES 16 // (A-2) +#define HEVC_MAX_NUM_REF_PICS 16 class HEVCVideoParser : public RocVideoParser { @@ -248,8 +250,8 @@ protected: */ typedef struct { int32_t num_of_pics; - int32_t pocs[32]; - bool used_by_curr_pic[32]; + int32_t pocs[32]; // PocLsbLt + bool used_by_curr_pic[32]; // UsedByCurrPicLt } H265LongTermRPS; /*! \brief Structure for Sub Layer Hypothetical Reference Decoder Parameters @@ -532,18 +534,6 @@ protected: H265RbspTrailingBits rbsp_trailing_bits; } PpsData; - /*! \brief Structure for Slice Data - */ - typedef struct { - uint32_t prev_poc; - uint32_t curr_poc; - uint32_t prev_poc_lsb; - uint32_t prev_poc_msb; - uint32_t curr_poc_lsb; - uint32_t curr_poc_msb; - uint32_t max_poc_lsb; - } SliceData; - /*! \brief Structure for Slice Header Data */ typedef struct { @@ -624,6 +614,35 @@ protected: return nalu_header; } + enum HevcRefMarking { + kUnusedForReference = 0, + kUsedForShortTerm = 1, + kUsedForLongTerm = 2 + }; + + /*! \brief Picture info for decoding process + */ + typedef struct { + // POC info + int32_t pic_order_cnt; // PicOrderCnt + int32_t prev_poc_lsb; // prevPicOrderCntLsb + int32_t prev_poc_msb; // prevPicOrderCntMsb + uint32_t slice_pic_order_cnt_lsb; // for long term ref pic identification + + uint32_t is_reference; + uint32_t use_status; // 0 = empty; 1 = top used; 2 = bottom used; 3 = both fields or frame used + } HevcPicInfo; + + /*! \brief Decoded picture buffer + */ + typedef struct + { + uint32_t num_pics_not_yet_output; /// number of pictures in DPB that have not been output yet + uint32_t dpb_fullness; /// number of pictures in DPB + + HevcPicInfo frame_buffer_list[HVC_MAX_DPB_FRAMES]; + } DecodedPictureBuffer; + /*! \brief Function to convert from Encapsulated Byte Sequence Packets to Raw Byte Sequence Payload * * \param [inout] stream_buffer A pointer of uint8_t for the converted RBSP buffer. @@ -634,6 +653,7 @@ protected: size_t EBSPtoRBSP(uint8_t *stream_buffer, size_t begin_bytepos, size_t end_bytepos); // Data members of HEVC class + NalUnitHeader nal_unit_header_; int32_t m_active_vps_id_; int32_t m_active_sps_id_; int32_t m_active_pps_id_; @@ -642,13 +662,39 @@ protected: PpsData* m_pps_; SliceHeaderData* m_sh_; SliceHeaderData* m_sh_copy_; - SliceData* m_slice_; + HevcPicInfo curr_pic_info_; bool b_new_picture_; int m_packet_count_; int slice_num_; int m_rbsp_size_; uint8_t m_rbsp_buf_[RBSP_BUF_SIZE]; // to store parameter set or slice header RBSP + // DPB + DecodedPictureBuffer dpb_buffer_; + + uint32_t num_pic_total_curr_; // NumPicTotalCurr + + // Reference picture set + uint32_t num_poc_st_curr_before_; // NumPocStCurrBefore; + uint32_t num_poc_st_curr_after_; // NumPocStCurrAfter; + uint32_t num_poc_st_foll_; // NumPocStFoll; + uint32_t num_poc_lt_curr_; // NumPocLtCurr; + uint32_t num_poc_lt_foll_; // NumPocLtFoll; + + int32_t poc_st_curr_before_[HEVC_MAX_NUM_REF_PICS]; // PocStCurrBefore + int32_t poc_st_curr_after_[HEVC_MAX_NUM_REF_PICS]; // PocStCurrAfter + int32_t poc_st_foll_[HEVC_MAX_NUM_REF_PICS]; // PocStFoll + int32_t poc_lt_curr_[HEVC_MAX_NUM_REF_PICS]; // PocLtCurr + int32_t poc_lt_foll_[HEVC_MAX_NUM_REF_PICS]; // PocLtFoll + uint8_t ref_pic_set_st_curr_before_[HEVC_MAX_NUM_REF_PICS]; // RefPicSetStCurrBefore + uint8_t ref_pic_set_st_curr_after_[HEVC_MAX_NUM_REF_PICS]; // RefPicSetStCurrAfter + uint8_t ref_pic_set_st_foll_[HEVC_MAX_NUM_REF_PICS]; // RefPicSetStFoll + uint8_t ref_pic_set_lt_curr_[HEVC_MAX_NUM_REF_PICS]; // RefPicSetLtCurr + uint8_t ref_pic_set_lt_foll_[HEVC_MAX_NUM_REF_PICS]; // RefPicSetLtFoll + + uint8_t ref_pic_list_0_[HEVC_MAX_NUM_REF_PICS]; // RefPicList0 + uint8_t ref_pic_list_1_[HEVC_MAX_NUM_REF_PICS]; // RefPicList1 + // Frame bit stream info uint8_t *frame_data_buffer_ptr_; // bit stream buffer pointer of the current frame from the demuxer int frame_data_size_; // bit stream size of the current frame @@ -768,6 +814,23 @@ protected: */ bool ParseSliceHeader(uint32_t nal_unit_type, uint8_t *nalu, size_t size); + /*! \brief Function to calculate the picture order count of the current picture (8.3.1) + */ + void CalculateCurrPOC(); + + /*! \brief Function to perform decoding process for reference picture set (8.3.2) + */ + void DeocdeRps(); + + /*! \brief Function to perform decoding process for reference picture lists construction (8.3.4) + */ + void ConstructRefPicLists(); + + /*! \brief Function to find a free buffer in DPM for the current picture and mark it. + * \return Code in ParserResult form. + */ + int FindFreeBufAndMark(); + /*! \brief Function to parse the data received from the demuxer. * \param [in] p_stream A pointer of uint8_t for the input stream to be parsed * \param [in] frame_data_size Size of the input stream @@ -810,11 +873,6 @@ private: */ PpsData* AllocPps(); - /*! \brief Function to allocate memory for Slice Structure - * \return Returns pointer to the allocated memory for SliceData - */ - SliceData* AllocSlice(); - /*! \brief Function to allocate memory for Slice Header Structure * \return Returns pointer to the allocated memory for SliceHeaderData */