From ba36534f1f7c84e9e477378b9039ffffb89a9ffc Mon Sep 17 00:00:00 2001 From: jeffqjiangNew <142832361+jeffqjiangNew@users.noreply.github.com> Date: Fri, 3 May 2024 15:18:08 -0400 Subject: [PATCH] rocDecode: Added error handling of missing headers in cases where they are not parsed but referred in the frame decode process. One example is when frame seek is performed and the target picture is not a random access point. (#335) * * rocDecode: Added error handling of missing headers in cases where they are not parsed but referred in the frame decode process. One example is when frame seek is performed and the target picture is not a random access point. * * rocDecode/HEVC: Added some missing error handlings. --------- Co-authored-by: Aryan Salmanpour --- src/parser/avc_parser.cpp | 8 ++++++++ src/parser/hevc_defines.h | 5 ++++- src/parser/hevc_parser.cpp | 36 +++++++++++++++++++++++++++--------- src/parser/hevc_parser.h | 8 ++++---- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/parser/avc_parser.cpp b/src/parser/avc_parser.cpp index dabed8ea00..25b2fb9b0e 100644 --- a/src/parser/avc_parser.cpp +++ b/src/parser/avc_parser.cpp @@ -1180,9 +1180,17 @@ ParserResult AvcVideoParser::ParseSliceHeader(uint8_t *p_stream, size_t stream_s // Set active SPS and PPS for the current slice active_pps_id_ = p_slice_header->pic_parameter_set_id; p_pps = &pps_list_[active_pps_id_]; + if (p_pps->is_received == 0) { + ERR("Empty PPS is referred."); + return PARSER_WRONG_STATE; + } if (active_sps_id_ != p_pps->seq_parameter_set_id) { active_sps_id_ = p_pps->seq_parameter_set_id; p_sps = &sps_list_[active_sps_id_]; + if ( p_sps->is_received == 0) { + ERR("Empty SPS is referred."); + return PARSER_WRONG_STATE; + } // Re-set DPB size. dpb_buffer_.dpb_size = p_sps->max_num_ref_frames + 3; dpb_buffer_.dpb_size = dpb_buffer_.dpb_size > AVC_MAX_DPB_FRAMES ? AVC_MAX_DPB_FRAMES : dpb_buffer_.dpb_size; diff --git a/src/parser/hevc_defines.h b/src/parser/hevc_defines.h index 91edf90f29..d841b43278 100644 --- a/src/parser/hevc_defines.h +++ b/src/parser/hevc_defines.h @@ -337,7 +337,8 @@ typedef struct { /*! \brief Structure for Video Parameter Set */ -typedef struct{ +typedef struct { + uint32_t is_received; // received with vps_video_parameter_set_id uint32_t vps_video_parameter_set_id; //u(4) uint32_t vps_base_layer_internal_flag; //u(1) uint32_t vps_base_layer_available_flag; //u(1) @@ -377,6 +378,7 @@ typedef struct{ /*! \brief Structure for Sequence Parameter Set */ typedef struct { + uint32_t is_received; // received with sps_seq_parameter_set_id uint32_t sps_video_parameter_set_id; //u(4) uint32_t sps_max_sub_layers_minus1; //u(3) bool sps_temporal_id_nesting_flag; //u(1) @@ -443,6 +445,7 @@ typedef struct { /*! \brief Structure for Picture Parameter Set */ typedef struct { + uint32_t is_received; // received with pps_pic_parameter_set_id uint32_t pps_pic_parameter_set_id; //ue(v) uint32_t pps_seq_parameter_set_id; //ue(v) bool dependent_slice_segments_enabled_flag; //u(1) diff --git a/src/parser/hevc_parser.cpp b/src/parser/hevc_parser.cpp index 5376525099..0ded8882be 100644 --- a/src/parser/hevc_parser.cpp +++ b/src/parser/hevc_parser.cpp @@ -81,8 +81,7 @@ rocDecStatus HevcVideoParser::ParseVideoData(RocdecSourceDataPacket *p_data) { // Clear DPB output/display buffer number dpb_buffer_.num_output_pics = 0; - bool status = ParsePictureData(p_data->payload, p_data->payload_size); - if (!status) { + if (ParsePictureData(p_data->payload, p_data->payload_size) != PARSER_OK) { ERR(STR("Parser failed!")); return ROCDEC_RUNTIME_ERROR; } @@ -550,8 +549,9 @@ int HevcVideoParser::OutputDecodedPictures() { return PARSER_OK; } -bool HevcVideoParser::ParsePictureData(const uint8_t* p_stream, uint32_t pic_data_size) { - int ret = PARSER_OK; +ParserResult HevcVideoParser::ParsePictureData(const uint8_t* p_stream, uint32_t pic_data_size) { + ParserResult ret = PARSER_OK; + ParserResult ret2; pic_data_buffer_ptr_ = (uint8_t*)p_stream; pic_data_size_ = pic_data_size; @@ -568,7 +568,7 @@ bool HevcVideoParser::ParsePictureData(const uint8_t* p_stream, uint32_t pic_dat ret = GetNalUnit(); if (ret == PARSER_NOT_FOUND) { ERR(STR("Error: no start code found in the frame data.")); - return false; + return ret; } // Parse the NAL unit @@ -629,7 +629,9 @@ bool HevcVideoParser::ParsePictureData(const uint8_t* p_stream, uint32_t pic_dat memcpy(rbsp_buf_, (pic_data_buffer_ptr_ + curr_start_code_offset_ + 5), ebsp_size); rbsp_size_ = EbspToRbsp(rbsp_buf_, 0, ebsp_size); HevcSliceSegHeader *p_slice_header = &slice_info_list_[num_slices_].slice_header; - ParseSliceHeader(rbsp_buf_, rbsp_size_, p_slice_header); + if ((ret2 = ParseSliceHeader(rbsp_buf_, rbsp_size_, p_slice_header)) != PARSER_OK) { + return ret2; + } // Start decode process if (num_slices_ == 0) { @@ -726,7 +728,7 @@ bool HevcVideoParser::ParsePictureData(const uint8_t* p_stream, uint32_t pic_dat } } while (1); - return true; + return PARSER_OK; } void HevcVideoParser::ParsePtl(HevcProfileTierLevel *ptl, bool profile_present_flag, uint32_t max_num_sub_layers_minus1, uint8_t *nalu, size_t size, size_t& offset) { @@ -1267,6 +1269,7 @@ void HevcVideoParser::ParseVps(uint8_t *nalu, size_t size) { } } p_vps->vps_extension_flag = Parser::GetBit(nalu, offset); + p_vps->is_received = 1; #if DBGINFO PrintVps(p_vps); @@ -1394,6 +1397,7 @@ void HevcVideoParser::ParseSps(uint8_t *nalu, size_t size) { ParseVui(&sps_ptr->vui_parameters, sps_ptr->sps_max_sub_layers_minus1, nalu, size, offset); } sps_ptr->sps_extension_flag = Parser::GetBit(nalu, offset); + sps_ptr->is_received = 1; #if DBGINFO PrintSps(sps_ptr); @@ -1512,12 +1516,14 @@ void HevcVideoParser::ParsePps(uint8_t *nalu, size_t size) { pps_ptr->log2_sao_offset_scale_chroma = Parser::ExpGolomb::ReadUe(nalu, offset); } + pps_ptr->is_received = 1; + #if DBGINFO PrintPps(pps_ptr); #endif // DBGINFO } -bool HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcSliceSegHeader *p_slice_header) { +ParserResult HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcSliceSegHeader *p_slice_header) { HevcPicParamSet *pps_ptr = nullptr; HevcSeqParamSet *sps_ptr = nullptr; size_t offset = 0; @@ -1534,6 +1540,10 @@ bool HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcSliceSegH m_active_pps_id_ = Parser::ExpGolomb::ReadUe(nalu, offset); temp_sh.slice_pic_parameter_set_id = p_slice_header->slice_pic_parameter_set_id = m_active_pps_id_; pps_ptr = &m_pps_[m_active_pps_id_]; + if ( pps_ptr->is_received == 0) { + ERR("Empty PPS is referred."); + return PARSER_WRONG_STATE; + } 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_]; @@ -1543,7 +1553,15 @@ bool HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcSliceSegH new_sps_activated_ = true; // Note: clear this flag after the actions are taken. } sps_ptr = &m_sps_[m_active_sps_id_]; + if (sps_ptr->is_received == 0) { + ERR("Empty SPS is referred."); + return PARSER_WRONG_STATE; + } m_active_vps_id_ = sps_ptr->sps_video_parameter_set_id; + if (m_vps_[m_active_vps_id_].is_received == 0) { + ERR("Empty VPS is referred."); + return PARSER_WRONG_STATE; + } // Check video dimension change if ( pic_width_ != sps_ptr->pic_width_in_luma_samples || pic_height_ != sps_ptr->pic_height_in_luma_samples) { @@ -1825,7 +1843,7 @@ bool HevcVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size, HevcSliceSegH PrintSliceSegHeader(p_slice_header); #endif // DBGINFO - return false; + return PARSER_OK; } bool HevcVideoParser::IsIdrPic(HevcNalUnitHeader *nal_header_ptr) { diff --git a/src/parser/hevc_parser.h b/src/parser/hevc_parser.h index 679854eb7c..982dfe4dc0 100644 --- a/src/parser/hevc_parser.h +++ b/src/parser/hevc_parser.h @@ -273,9 +273,9 @@ protected: * \param [in] nalu A pointer of uint8_t for the input stream to be parsed * \param [in] size Size of the input stream * \param [out] p_slice_header Pointer to the slice header struct - * \return True is successful, else false + * \return ParserResult */ - bool ParseSliceHeader(uint8_t *nalu, size_t size, HevcSliceSegHeader *p_slice_header); + ParserResult ParseSliceHeader(uint8_t *nalu, size_t size, HevcSliceSegHeader *p_slice_header); /*! \brief Function to calculate the picture order count of the current picture. Once per picutre. (8.3.1) */ @@ -322,9 +322,9 @@ protected: /*! \brief Function to parse one picture bit stream received from the demuxer. * \param [in] p_stream A pointer of uint8_t for the input stream to be parsed * \param [in] pic_data_size Size of the input stream - * \return True is successful, else false + * \return ParserResult */ - bool ParsePictureData(const uint8_t* p_stream, uint32_t pic_data_size); + ParserResult ParsePictureData(const uint8_t* p_stream, uint32_t pic_data_size); #if DBGINFO void PrintVps(HevcVideoParamSet *vps_ptr);