From 4ca0d02bb04bbadbd2d2a1c765b199e6c58219f7 Mon Sep 17 00:00:00 2001 From: Lakshmi Kumar Date: Thu, 5 Oct 2023 08:20:07 -0700 Subject: [PATCH] HEVC Parser (#9) * basic parser create * adding data_stream * buildable parser * query output and required fucntions * latest changes * alloc buffer and other functions * parses first frame * parser finds all frames * parser dump size correct - dump file included * clean up * merge conflicts and file restructure * uses updated video demuxer * undoing changes to sample app * cleaning code * cleaning code * removing dwarf flag from compile * formatting changes * change variable names as per google standard * struct naming convention * struct name * remove parser data class and combine into parser buffer * remove context class and clean up * remove log file and use commons * move class to .h file * removing unused functions * removes platform.h * removing datastream class * formatting * remove byte_array, rename enums * clean up * spacing * rearrange to fit master * removes bit_strea_parser class, combines common stuff to roc_video_parser file --- .gitignore | 4 +- src/parser/hevc_parser.cpp | 1092 ++++++++++++++++++++++++++++++++- src/parser/hevc_parser.h | 572 ++++++++++++++++- src/parser/parser_buffer.cpp | 108 ++++ src/parser/parser_buffer.h | 69 +++ src/parser/roc_video_parser.h | 114 ++++ 6 files changed, 1950 insertions(+), 9 deletions(-) create mode 100644 src/parser/parser_buffer.cpp create mode 100644 src/parser/parser_buffer.h diff --git a/.gitignore b/.gitignore index 6975aef378..d8f0fbed2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ build/ samples/*/build -.vscode/ \ No newline at end of file +.vscode/ +samples/videoDecode/videodecode_test.cpp +samples/videoDecodeCMakeLists_test.txt \ No newline at end of file diff --git a/src/parser/hevc_parser.cpp b/src/parser/hevc_parser.cpp index 4cc5dabe42..264da52cd6 100644 --- a/src/parser/hevc_parser.cpp +++ b/src/parser/hevc_parser.cpp @@ -22,12 +22,28 @@ THE SOFTWARE. #include "hevc_parser.h" +//size_id = 0 +extern int scaling_list_default_0[1][6][16]; +//size_id = 1, 2 +extern int scaling_list_default_1_2[2][6][64]; +//size_id = 3 +extern int scaling_list_default_3[1][2][64]; + /** - * @brief Constructs a new HEVCParser object + * @brief Constructs a new HEVCVideoParser object * */ -HEVCVideoParser::HEVCVideoParser() { - +HEVCVideoParser::HEVCVideoParser() : + m_use_start_codes_(false), + m_current_frame_timestamp_(0), + m_packet_count_(0), + m_eof_(false), + m_fps_(0), + m_max_frames_number_(0) { + m_pmemory_ = new uint8_t [DATA_STREAM_SIZE]; + m_allocated_size_ = DATA_STREAM_SIZE; + m_memory_size_ = sizeof(m_pmemory_); + m_pos_ = 0; } /** @@ -48,5 +64,1071 @@ rocDecStatus HEVCVideoParser::Initialize(RocdecParserParams *pParams) { * @return rocDecStatus */ rocDecStatus HEVCVideoParser::ParseVideoData(RocdecSourceDataPacket *pData) { - return ROCDEC_NOT_IMPLEMENTED; -} \ No newline at end of file + if (!CheckDataStreamEof(pData->payload_size)) { + Write(pData->payload, pData->payload_size, NULL); + Seek(PARSER_SEEK_BEGIN, 0, NULL); + FindSPSandPPS(); + + ParserBuffer* outputBuffer; + outputBuffer = NULL; + QueryOutput(&outputBuffer); + } + return ROCDEC_SUCCESS; +} + +void HEVCVideoParser::FindFirstFrameSPSandPPS() { + Seek(PARSER_SEEK_BEGIN, 0, NULL); + FindSPSandPPS(); +} + +HEVCVideoParser::~HEVCVideoParser() { + std::cout << "parsed frames: " << m_packet_count_ << std::endl; + Close(); +} + +ParserResult HEVCVideoParser::ReInit() { + m_current_frame_timestamp_ = 0; + Seek(PARSER_SEEK_BEGIN, 0, NULL); + m_packet_count_ = 0; + m_eof_ = false; + return PARSER_OK; +} + +static const int s_win_unit_x[]={1,2,2,1}; +static const int s_win_unit_y[]={1,2,1,1}; + +static int GetWinUnitX (int chromaFormatIdc) { return s_win_unit_x[chromaFormatIdc]; } +// static int GetWinUnitX (int chromaFormatIdc) { return s_win_unit_y[chromaFormatIdc]; } + +void HEVCVideoParser::SetFrameRate(double fps) { + m_fps_ = fps; +} + +double HEVCVideoParser::GetFrameRate() const { + if(m_fps_ != 0) { + return m_fps_; + } + if(m_sps_map_.size() > 0) { + const SpsData &sps = m_sps_map_.cbegin()->second; + if(sps.vui_parameters_present_flag && sps.vui_parameters.vui_timing_info_present_flag && sps.vui_parameters.vui_num_units_in_tick) { + // according to the latest h264 standard nuit_field_based_flag is always = 1 and therefore this must be divided by two + // some old clips may get wrong FPS. This is just a sample. Use container information + return (double)sps.vui_parameters.vui_time_scale / sps.vui_parameters.vui_num_units_in_tick / 2; + } + } + return 25.0; +} + +HEVCVideoParser::NalUnitHeader HEVCVideoParser::ReadNextNaluUnit(size_t *offset, size_t *nalu, size_t *size) { + *size = 0; + size_t start_offset = *offset; + + bool new_nal_found = false; + size_t zeros_count = 0; + + while (!new_nal_found) { + // read next portion if needed + size_t ready = m_read_data_.GetSize() - *offset; + printf("ReadNextNaluUnit: remaining data size for read: %zu\n", ready); + if (ready == 0) { + if (m_eof_ == false) { + m_read_data_.SetSize(m_read_data_.GetSize() + m_read_size_); + ready = 0; + Read(m_read_data_.GetData() + *offset, m_read_size_, &ready); + } + if (ready != m_read_size_ && ready != 0) { + m_read_data_.SetSize(m_read_data_.GetSize() - (m_read_size_ - ready)); + } + if (ready == 0 ) { + if (m_eof_ == false) + m_read_data_.SetSize(m_read_data_.GetSize() - m_read_size_); + + //m_eof_ = true; + new_nal_found = start_offset != *offset; + *offset = m_read_data_.GetSize(); + break; // EOF + } + } + + uint8_t* data = m_read_data_.GetData(); + if (data == nullptr) { // check data before adding the offset + NalUnitHeader header_nalu; + header_nalu.nal_unit_type = NAL_UNIT_INVALID; + return header_nalu; // no data read + } + data += *offset; // don't forget the offset! + + for (size_t i = 0; i < ready; i++) { + uint8_t ch = *data++; + if (0 == ch) { + zeros_count++; + } + else { + if (1 == ch && zeros_count >=2) { // We found a start code in Annex B stream + if (*offset + (i - zeros_count) > start_offset) { + ready = i - zeros_count; + new_nal_found = true; // new NAL + break; + } + else { + *nalu = *offset + zeros_count + 1; + } + } + zeros_count = 0; + } + } + // if zeros found but not a new NAL - continue with zeros_count on the next iteration + *offset += ready; + } + if (!new_nal_found) { + NalUnitHeader header_nalu; + header_nalu.nal_unit_type = NAL_UNIT_INVALID; + return header_nalu; // EOF + } + *size = *offset - *nalu; + // get NAL type + return GetNaluUnitType(m_read_data_.GetData() + *nalu); +} + +ParserResult HEVCVideoParser::QueryOutput(ParserBuffer** pp_data) { + if ((m_eof_ && m_read_data_.GetSize() == 0) || m_max_frames_number_ && m_packet_count_ >= m_max_frames_number_) { + return PARSER_EOF; + } + bool new_picture_detected = false; + size_t packet_size = 0; + size_t read_size = 0; + std::vector nalu_starts; + std::vector nalu_sizes; + size_t data_offset = 0; + bool b_slice_found = false; + uint32_t prev_slice_nal_unit_type = 0; + + do { + size_t nalu_size = 0; + size_t nalu_offset = 0; + size_t nalu_annex_boffset = data_offset; + NalUnitHeader nalu_header = ReadNextNaluUnit(&data_offset, &nalu_offset, &nalu_size); + if (b_slice_found == true) { + if (prev_slice_nal_unit_type != nalu_header.nal_unit_type) { + new_picture_detected = true; + } + } + + if (NAL_UNIT_ACCESS_UNIT_DELIMITER == nalu_header.nal_unit_type) { + if (packet_size > 0) { + new_picture_detected = true; + } + } + else if (NAL_UNIT_PREFIX_SEI == nalu_header.nal_unit_type) { + if (b_slice_found) { + new_picture_detected = true; + } + } + else if ( + NAL_UNIT_CODED_SLICE_TRAIL_R == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_TRAIL_N == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_TLA_R == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_TSA_N == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_STSA_R == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_STSA_N == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_BLA_W_LP == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_BLA_W_RADL == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_BLA_N_LP == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_IDR_W_RADL == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_IDR_N_LP == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_CRA == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_RADL_N == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_RADL_R == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_RASL_N == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_RASL_R == nalu_header.nal_unit_type + ) { + if (b_slice_found == true) { + if (prev_slice_nal_unit_type != nalu_header.nal_unit_type) { + new_picture_detected = true; + } + else { + AccessUnitSigns nalu_access_units_signs; + nalu_access_units_signs.Parse(m_read_data_.GetData() + nalu_offset, nalu_size, m_sps_map_, m_pps_map_); + new_picture_detected = nalu_access_units_signs.IsNewPicture() && b_slice_found; + } + b_slice_found = true; + prev_slice_nal_unit_type = nalu_header.nal_unit_type; + } + else { + AccessUnitSigns nalu_access_units_signs; + nalu_access_units_signs.Parse(m_read_data_.GetData() + nalu_offset, nalu_size, m_sps_map_, m_pps_map_); + new_picture_detected = nalu_access_units_signs.IsNewPicture() && b_slice_found; + b_slice_found = true; + prev_slice_nal_unit_type = nalu_header.nal_unit_type; + } + } + + if (nalu_size > 0 && !new_picture_detected ) { + packet_size += nalu_size; + if (!m_use_start_codes_) { + packet_size += nal_unit_length_size_; + nalu_starts.push_back(nalu_offset); + nalu_sizes.push_back(nalu_size); + } + else { + size_t startCodeSize = nalu_offset - nalu_annex_boffset; + packet_size += startCodeSize; + } + } + if (!new_picture_detected) { + read_size = data_offset; + } + if (nalu_header.nal_unit_type == NAL_UNIT_INVALID) { + break; + } + } while (!new_picture_detected); + + ParserResult ar = ParserBuffer::AllocBuffer(PARSER_MEMORY_HOST, packet_size, pp_data); + if (ar != PARSER_OK) { + return ar; + } + + uint8_t *data = (uint8_t*)(*pp_data)->GetNative(); + if (m_use_start_codes_) { + memcpy(data, m_read_data_.GetData(), packet_size); + } + else { + for (size_t i=0; i < nalu_starts.size(); i++) { + // copy size + uint32_t nalu_size= (uint32_t)nalu_sizes[i]; + *data++ = (nalu_size >> 24); + *data++ = static_cast(((nalu_size & 0x00FF0000) >> 16)); + *data++ = ((nalu_size & 0x0000FF00) >> 8); + *data++ = ((nalu_size & 0x000000FF)); + memcpy(data, m_read_data_.GetData() + nalu_starts[i], nalu_size); + data += nalu_size; + } + } + (*pp_data)->SetPts(m_current_frame_timestamp_); + int64_t frame_duration = int64_t(PARSER_SECOND / GetFrameRate()); // In 100 NanoSeconds + (*pp_data)->SetDuration(frame_duration); + m_current_frame_timestamp_ += frame_duration; + + // shift remaining data in m_ReadData + size_t remaining_data = m_read_data_.GetSize() - read_size; + memmove(m_read_data_.GetData(), m_read_data_.GetData()+read_size, remaining_data); + m_read_data_.SetSize(remaining_data); + + m_packet_count_++; + + return PARSER_OK; +} + +void HEVCVideoParser::FindSPSandPPS() { + ExtraDataBuilder extra_data_builder; + + size_t data_offset = 0; + do { + + size_t nalu_size = 0; + size_t nalu_offset = 0; + NalUnitHeader nalu_header = ReadNextNaluUnit(&data_offset, &nalu_offset, &nalu_size); + + if (nalu_header.nal_unit_type == NAL_UNIT_INVALID ) { + break; // EOF + } + + if (nalu_header.nal_unit_type == NAL_UNIT_SPS) { + m_EBSP_to_RBSP_data_.SetSize(nalu_size); + memcpy(m_EBSP_to_RBSP_data_.GetData(), m_read_data_.GetData() + nalu_offset, nalu_size); + size_t newNaluSize = EBSPtoRBSP(m_EBSP_to_RBSP_data_.GetData(),0, nalu_size); + + SpsData sps; + sps.Parse(m_EBSP_to_RBSP_data_.GetData(), newNaluSize); + m_sps_map_[sps.sps_video_parameter_set_id] = sps; + extra_data_builder.AddSPS(m_read_data_.GetData()+nalu_offset, nalu_size); + } + else if (nalu_header.nal_unit_type == NAL_UNIT_PPS) { + m_EBSP_to_RBSP_data_.SetSize(nalu_size); + memcpy(m_EBSP_to_RBSP_data_.GetData(), m_read_data_.GetData() + nalu_offset, nalu_size); + size_t newNaluSize = EBSPtoRBSP(m_EBSP_to_RBSP_data_.GetData(),0, nalu_size); + + PpsData pps; + pps.Parse(m_EBSP_to_RBSP_data_.GetData(), newNaluSize); + m_pps_map_[pps.pps_pic_parameter_set_id] = pps; + extra_data_builder.AddPPS(m_read_data_.GetData()+nalu_offset, nalu_size); + } + else if ( + NAL_UNIT_CODED_SLICE_TRAIL_R == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_TRAIL_N == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_TLA_R == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_TSA_N == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_STSA_R == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_STSA_N == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_BLA_W_LP == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_BLA_W_RADL == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_BLA_N_LP == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_IDR_W_RADL == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_IDR_N_LP == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_CRA == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_RADL_N == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_RADL_R == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_RASL_N == nalu_header.nal_unit_type + || NAL_UNIT_CODED_SLICE_RASL_R == nalu_header.nal_unit_type + ) { + break; // frame data + } + } while (true); + + Seek(PARSER_SEEK_BEGIN, 0, NULL); + m_read_data_.SetSize(0); + // It will fail if SPS or PPS are absent + extra_data_builder.GetExtradata(m_extra_data_); +} + +bool HEVCVideoParser::SpsData::Parse(uint8_t *nalu, size_t size) { + size_t offset = 16; // 2 bytes NALU header + + uint32_t active_vps = Parser::ReadBits(nalu, offset,4); + uint32_t max_sub_layer_minus1 = Parser::ReadBits(nalu, offset,3); + sps_temporal_id_nesting_flag = Parser::GetBit(nalu, offset); + H265ProfileTierLevel ptl; + memset (&ptl,0,sizeof(ptl)); + ParsePTL(&ptl, true, max_sub_layer_minus1, nalu, size, offset); + uint32_t sps_id = Parser::ExpGolomb::ReadUe(nalu, offset); + + sps_video_parameter_set_id = active_vps; + sps_max_sub_layers_minus1 = max_sub_layer_minus1; + memcpy (&profile_tier_level,&ptl,sizeof(ptl)); + sps_seq_parameter_set_id = sps_id; + + chroma_format_idc = Parser::ExpGolomb::ReadUe(nalu, offset); + if (chroma_format_idc == 3) { + separate_colour_plane_flag = Parser::GetBit(nalu, offset); + } + pic_width_in_luma_samples = Parser::ExpGolomb::ReadUe(nalu, offset); + pic_height_in_luma_samples = Parser::ExpGolomb::ReadUe(nalu, offset); + conformance_window_flag = Parser::GetBit(nalu, offset); + if (conformance_window_flag) { + conf_win_left_offset = Parser::ExpGolomb::ReadUe(nalu, offset); + conf_win_right_offset = Parser::ExpGolomb::ReadUe(nalu, offset); + conf_win_top_offset = Parser::ExpGolomb::ReadUe(nalu, offset); + conf_win_bottom_offset = Parser::ExpGolomb::ReadUe(nalu, offset); + } + bit_depth_luma_minus8 = Parser::ExpGolomb::ReadUe(nalu, offset); + bit_depth_chroma_minus8 = Parser::ExpGolomb::ReadUe(nalu, offset); + log2_max_pic_order_cnt_lsb_minus4 = Parser::ExpGolomb::ReadUe(nalu, offset); + sps_sub_layer_ordering_info_present_flag = Parser::GetBit(nalu, offset); + for (uint32_t i = (sps_sub_layer_ordering_info_present_flag?0:sps_max_sub_layers_minus1); i <= sps_max_sub_layers_minus1; i++) { + sps_max_dec_pic_buffering_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + sps_max_num_reorder_pics[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + sps_max_latency_increase_plus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + } + log2_min_luma_coding_block_size_minus3 = Parser::ExpGolomb::ReadUe(nalu, offset); + + int log2_min_cu_size = log2_min_luma_coding_block_size_minus3 +3; + + log2_diff_max_min_luma_coding_block_size = Parser::ExpGolomb::ReadUe(nalu, offset); + + int max_cu_depth_delta = log2_diff_max_min_luma_coding_block_size; + max_cu_width = ( 1<<(log2_min_cu_size + max_cu_depth_delta) ); + max_cu_height = ( 1<<(log2_min_cu_size + max_cu_depth_delta) ); + + log2_min_transform_block_size_minus2 = Parser::ExpGolomb::ReadUe(nalu, offset); + + uint32_t quadtree_tu_log2_min_size = log2_min_transform_block_size_minus2 + 2; + int add_cu_depth = std::max (0, log2_min_cu_size - (int)quadtree_tu_log2_min_size ); + max_cu_depth = (max_cu_depth_delta + add_cu_depth); + + log2_diff_max_min_transform_block_size = Parser::ExpGolomb::ReadUe(nalu, offset); + max_transform_hierarchy_depth_inter = Parser::ExpGolomb::ReadUe(nalu, offset); + max_transform_hierarchy_depth_intra = Parser::ExpGolomb::ReadUe(nalu, offset); + scaling_list_enabled_flag = Parser::GetBit(nalu, offset); + if (scaling_list_enabled_flag) { + sps_scaling_list_data_present_flag = Parser::GetBit(nalu, offset); + if (sps_scaling_list_data_present_flag) { + ParseScalingList(&scaling_list_data, nalu, size, offset); + } + } + amp_enabled_flag = Parser::GetBit(nalu, offset); + sample_adaptive_offset_enabled_flag = Parser::GetBit(nalu, offset); + pcm_enabled_flag = Parser::GetBit(nalu, offset); + if (pcm_enabled_flag) { + pcm_sample_bit_depth_luma_minus1 = Parser::ReadBits(nalu, offset,4); + pcm_sample_bit_depth_chroma_minus1 = Parser::ReadBits(nalu, offset,4); + log2_min_pcm_luma_coding_block_size_minus3 = Parser::ExpGolomb::ReadUe(nalu, offset); + log2_diff_max_min_pcm_luma_coding_block_size = Parser::ExpGolomb::ReadUe(nalu, offset); + pcm_loop_filter_disabled_flag = Parser::GetBit(nalu, offset); + } + num_short_term_ref_pic_sets = Parser::ExpGolomb::ReadUe(nalu, offset); + for (uint32_t i=0; igeneral_profile_space = Parser::ReadBits(nalu, offset,2); + ptl->general_tier_flag = Parser::GetBit(nalu, offset); + ptl->general_profile_idc = Parser::ReadBits(nalu, offset,5); + for (int i = 0; i < 32; i++) { + ptl->general_profile_compatibility_flag[i] = Parser::GetBit(nalu, offset); + } + ptl->general_progressive_source_flag = Parser::GetBit(nalu, offset); + ptl->general_interlaced_source_flag = Parser::GetBit(nalu, offset); + ptl->general_non_packed_constraint_flag = Parser::GetBit(nalu, offset); + ptl->general_frame_only_constraint_flag = Parser::GetBit(nalu, offset); + //ReadBits is limited to 32 + //ptl->general_reserved_zero_44bits = Parser::ReadBits(nalu, offset,44); + offset += 44; + } + + ptl->general_level_idc = Parser::ReadBits(nalu, offset,8); + for(uint32_t i = 0; i < max_num_sub_layers_minus1; i++) { + ptl->sub_layer_profile_present_flag[i] = Parser::GetBit(nalu, offset); + ptl->sub_layer_level_present_flag[i] = Parser::GetBit(nalu, offset); + } + if (max_num_sub_layers_minus1 > 0) { + for(uint32_t i=max_num_sub_layers_minus1; i<8; i++) { + ptl->reserved_zero_2bits[i] = Parser::ReadBits(nalu, offset,2); + } + } + for (uint32_t i = 0; i < max_num_sub_layers_minus1; i++) { + if (ptl->sub_layer_profile_present_flag[i]) { + ptl->sub_layer_profile_space[i] = Parser::ReadBits(nalu, offset,2); + ptl->sub_layer_tier_flag[i] = Parser::GetBit(nalu, offset); + ptl->sub_layer_profile_idc[i] = Parser::ReadBits(nalu, offset,5); + for (int j = 0; j < 32; j++) { + ptl->sub_layer_profile_compatibility_flag[i][j] = Parser::GetBit(nalu, offset); + } + ptl->sub_layer_progressive_source_flag[i] = Parser::GetBit(nalu, offset); + ptl->sub_layer_interlaced_source_flag[i] = Parser::GetBit(nalu, offset); + ptl->sub_layer_non_packed_constraint_flag[i] = Parser::GetBit(nalu, offset); + ptl->sub_layer_frame_only_constraint_flag[i] = Parser::GetBit(nalu, offset); + ptl->sub_layer_reserved_zero_44bits[i] = Parser::ReadBits(nalu, offset,44); + } + if (ptl->sub_layer_level_present_flag[i]) { + ptl->sub_layer_level_idc[i] = Parser::ReadBits(nalu, offset,8); + } + } +} + +void HEVCVideoParser::SpsData::ParseSubLayerHrdParameters(H265SubLayerHrdParameters *sub_hrd, uint32_t CpbCnt, bool sub_pic_hrd_params_present_flag, uint8_t *nalu, size_t /*size*/, size_t& offset) { + for (uint32_t i = 0; i <= CpbCnt; i++) { + sub_hrd->bit_rate_value_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + sub_hrd->cpb_size_value_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + if(sub_pic_hrd_params_present_flag) { + sub_hrd->cpb_size_du_value_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + sub_hrd->bit_rate_du_value_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + } + sub_hrd->cbr_flag[i] = Parser::GetBit(nalu, offset); + } +} + +void HEVCVideoParser::SpsData::ParseHrdParameters(H265HrdParameters *hrd, bool common_inf_present_flag, uint32_t max_num_sub_layers_minus1, uint8_t *nalu, size_t size,size_t &offset) { + if (common_inf_present_flag) { + hrd->nal_hrd_parameters_present_flag = Parser::GetBit(nalu, offset); + hrd->vcl_hrd_parameters_present_flag = Parser::GetBit(nalu, offset); + if (hrd->nal_hrd_parameters_present_flag || hrd->vcl_hrd_parameters_present_flag) { + hrd->sub_pic_hrd_params_present_flag = Parser::GetBit(nalu, offset); + if (hrd->sub_pic_hrd_params_present_flag) { + hrd->tick_divisor_minus2 = Parser::ReadBits(nalu, offset,8); + hrd->du_cpb_removal_delay_increment_length_minus1 = Parser::ReadBits(nalu, offset,5); + hrd->sub_pic_cpb_params_in_pic_timing_sei_flag = Parser::GetBit(nalu, offset); + hrd->dpb_output_delay_du_length_minus1 = Parser::ReadBits(nalu, offset,5); + } + hrd->bit_rate_scale = Parser::ReadBits(nalu, offset,4); + hrd->cpb_size_scale = Parser::ReadBits(nalu, offset,4); + if (hrd->sub_pic_hrd_params_present_flag) { + hrd->cpb_size_du_scale = Parser::ReadBits(nalu, offset,4); + } + hrd->initial_cpb_removal_delay_length_minus1 = Parser::ReadBits(nalu, offset,5); + hrd->au_cpb_removal_delay_length_minus1 = Parser::ReadBits(nalu, offset,5); + hrd->dpb_output_delay_length_minus1 = Parser::ReadBits(nalu, offset,5); + } + } + for (uint32_t i = 0; i <= max_num_sub_layers_minus1; i++) { + hrd->fixed_pic_rate_general_flag[i] = Parser::GetBit(nalu, offset); + if (!hrd->fixed_pic_rate_general_flag[i]) { + hrd->fixed_pic_rate_within_cvs_flag[i] = Parser::GetBit(nalu, offset); + } + else { + hrd->fixed_pic_rate_within_cvs_flag[i] = hrd->fixed_pic_rate_general_flag[i]; + } + + if (hrd->fixed_pic_rate_within_cvs_flag[i]) { + hrd->elemental_duration_in_tc_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + } + else { + hrd->low_delay_hrd_flag[i] = Parser::GetBit(nalu, offset); + } + if (!hrd->low_delay_hrd_flag[i]) { + hrd->cpb_cnt_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset); + } + if (hrd->nal_hrd_parameters_present_flag) { + //sub_layer_hrd_parameters( i ) + ParseSubLayerHrdParameters(&hrd->sub_layer_hrd_parameters_0[i], hrd->cpb_cnt_minus1[i], hrd->sub_pic_hrd_params_present_flag, nalu, size, offset); + } + if (hrd->vcl_hrd_parameters_present_flag) { + //sub_layer_hrd_parameters( i ) + ParseSubLayerHrdParameters(&hrd->sub_layer_hrd_parameters_1[i], hrd->cpb_cnt_minus1[i], hrd->sub_pic_hrd_params_present_flag, nalu, size, offset); + } + } +} + +void HEVCVideoParser::SpsData::ParseScalingList(H265ScalingListData * s_data, uint8_t *nalu, size_t /*size*/, size_t& offset) { + for (int size_id = 0; size_id < 4; size_id++) { + for (int matrix_id = 0; matrix_id < ((size_id == 3) ? 2:6); matrix_id++) { + s_data->scaling_list_pred_mode_flag[size_id][matrix_id] = Parser::GetBit(nalu, offset); + if(!s_data->scaling_list_pred_mode_flag[size_id][matrix_id]) { + s_data->scaling_list_pred_matrix_id_delta[size_id][matrix_id] = Parser::ExpGolomb::ReadUe(nalu, offset); + + int ref_matrix_id = matrix_id - s_data->scaling_list_pred_matrix_id_delta[size_id][matrix_id]; + int coef_num = std::min(64, (1<< (4 + (size_id<<1)))); + + //fill in scaling_list_dc_coef_minus8 + if (!s_data->scaling_list_pred_matrix_id_delta[size_id][matrix_id]) { + if (size_id > 1) { + s_data->scaling_list_dc_coef_minus8[size_id-2][matrix_id] = 8; + } + } + else { + if (size_id > 1) { + s_data->scaling_list_dc_coef_minus8[size_id-2][matrix_id] = s_data->scaling_list_dc_coef_minus8[size_id-2][ref_matrix_id]; + } + } + + for (int i = 0; i < coef_num; i++) { + if (s_data->scaling_list_pred_matrix_id_delta[size_id][matrix_id] == 0) { + if (size_id == 0) { + s_data->scaling_list[size_id][matrix_id][i] = scaling_list_default_0[size_id][matrix_id][i]; + } + else if(size_id == 1 || size_id == 2) { + s_data->scaling_list[size_id][matrix_id][i] = scaling_list_default_1_2[size_id][matrix_id][i]; + } + else if(size_id == 3) { + s_data->scaling_list[size_id][matrix_id][i] = scaling_list_default_3[size_id][matrix_id][i]; + } + } + else { + s_data->scaling_list[size_id][matrix_id][i] = s_data->scaling_list[size_id][ref_matrix_id][i]; + } + } + } + else { + int next_coef = 8; + int coef_num = std::min(64, (1 << (4 + (size_id << 1)))); + if (size_id > 1) { + s_data->scaling_list_dc_coef_minus8[size_id-2][matrix_id] = Parser::ExpGolomb::ReadSe(nalu, offset); + next_coef = s_data->scaling_list_dc_coef_minus8[size_id-2][matrix_id] + 8; + } + for (int i = 0; i < coef_num; i++) { + s_data->scaling_list_delta_coef = Parser::ExpGolomb::ReadSe(nalu, offset); + next_coef = (next_coef + s_data->scaling_list_delta_coef +256)%256; + s_data->scaling_list[size_id][matrix_id][i] = next_coef; + } + } + } + } +} + +void HEVCVideoParser::SpsData::ParseShortTermRefPicSet(H265ShortTermRPS *rps, int32_t st_rps_idx, uint32_t number_short_term_ref_pic_sets, H265ShortTermRPS rps_ref[], uint8_t *nalu, size_t /*size*/, size_t& offset) { + uint32_t inter_rps_pred = 0; + uint32_t delta_idx_minus1 = 0; + int32_t i = 0; + + if (st_rps_idx != 0) { + inter_rps_pred = Parser::GetBit(nalu, offset); + } + if (inter_rps_pred) { + uint32_t delta_rps_sign, abs_delta_rps_minus1; + bool used_by_curr_pic_flag[16] = {0}; + bool use_delta_flag[16] = {0}; + if (unsigned(st_rps_idx) == number_short_term_ref_pic_sets) { + delta_idx_minus1 = Parser::ExpGolomb::ReadUe(nalu, offset); + } + delta_rps_sign = Parser::GetBit(nalu, offset); + abs_delta_rps_minus1 = Parser::ExpGolomb::ReadUe(nalu, offset); + int32_t delta_rps = (int32_t) (1 - 2 * delta_rps_sign) * (abs_delta_rps_minus1 + 1); + int32_t ref_idx = st_rps_idx - delta_idx_minus1 - 1; + for (int j = 0; j <= (rps_ref[ref_idx].num_negative_pics + rps_ref[ref_idx].num_positive_pics); j++) { + used_by_curr_pic_flag[j] = Parser::GetBit(nalu, offset); + if (!used_by_curr_pic_flag[j]) { + use_delta_flag[j] = Parser::GetBit(nalu, offset); + } + else { + use_delta_flag[j] = 1; + } + } + + for (int j = rps_ref[ref_idx].num_positive_pics - 1; j >= 0; j--) { + int32_t delta_poc = delta_rps + rps_ref[ref_idx].delta_poc[rps_ref[ref_idx].num_negative_pics + j]; //positive delta_poc from ref_rps + if (delta_poc < 0 && use_delta_flag[rps_ref[ref_idx].num_negative_pics + j]) { + rps->delta_poc[i] = delta_poc; + rps->used_by_curr_pic[i++] = used_by_curr_pic_flag[rps_ref[ref_idx].num_negative_pics + j]; + } + } + if (delta_rps < 0 && use_delta_flag[rps_ref[ref_idx].num_of_pics]) { + rps->delta_poc[i] = delta_rps; + rps->used_by_curr_pic[i++] = used_by_curr_pic_flag[rps_ref[ref_idx].num_of_pics]; + } + for (int j = 0; j < rps_ref[ref_idx].num_negative_pics; j++) { + int32_t delta_poc = delta_rps + rps_ref[ref_idx].delta_poc[j]; + if (delta_poc < 0 && use_delta_flag[j]) { + rps->delta_poc[i]=delta_poc; + rps->used_by_curr_pic[i++] = used_by_curr_pic_flag[j]; + } + } + rps->num_negative_pics = i; + + + for (int j = rps_ref[ref_idx].num_negative_pics - 1; j >= 0; j--) { + int32_t delta_poc = delta_rps + rps_ref[ref_idx].delta_poc[j]; //positive delta_poc from ref_rps + if (delta_poc > 0 && use_delta_flag[j]) { + rps->delta_poc[i] = delta_poc; + rps->used_by_curr_pic[i++] = used_by_curr_pic_flag[j]; + } + } + if (delta_rps > 0 && use_delta_flag[rps_ref[ref_idx].num_of_pics]) { + rps->delta_poc[i] = delta_rps; + rps->used_by_curr_pic[i++] = used_by_curr_pic_flag[rps_ref[ref_idx].num_of_pics]; + } + for (int j = 0; j < rps_ref[ref_idx].num_positive_pics; j++) { + int32_t delta_poc = delta_rps + rps_ref[ref_idx].delta_poc[rps_ref[ref_idx].num_negative_pics+j]; + if (delta_poc > 0 && use_delta_flag[rps_ref[ref_idx].num_negative_pics+j]) { + rps->delta_poc[i]=delta_poc; + rps->used_by_curr_pic[i++] = used_by_curr_pic_flag[rps_ref[ref_idx].num_negative_pics+j]; + } + } + rps->num_positive_pics = i - rps->num_negative_pics ; + rps->num_of_delta_poc = rps_ref[ref_idx].num_negative_pics + rps_ref[ref_idx].num_positive_pics; + rps->num_of_pics = i; + } + else { + rps->num_negative_pics = Parser::ExpGolomb::ReadUe(nalu, offset); + rps->num_positive_pics = Parser::ExpGolomb::ReadUe(nalu, offset); + int32_t prev = 0; + int32_t poc; + uint32_t delta_poc_s0_minus1,delta_poc_s1_minus1; + for (int j = 0; j < rps->num_negative_pics; j++) { + delta_poc_s0_minus1 = Parser::ExpGolomb::ReadUe(nalu, offset); + poc = prev - delta_poc_s0_minus1 - 1; + prev = poc; + rps->delta_poc[j] = poc; + rps->used_by_curr_pic[j] = Parser::GetBit(nalu, offset); + } + prev = 0; + for (int j = rps->num_negative_pics; j < rps->num_negative_pics + rps->num_positive_pics; j++) { + delta_poc_s1_minus1 = Parser::ExpGolomb::ReadUe(nalu, offset); + poc = prev + delta_poc_s1_minus1 + 1; + prev = poc; + rps->delta_poc[j] = poc; + rps->used_by_curr_pic[j] = Parser::GetBit(nalu, offset); + } + rps->num_of_pics = rps->num_negative_pics + rps->num_positive_pics; + rps->num_of_delta_poc = rps->num_negative_pics + rps->num_positive_pics; + } +} + +void HEVCVideoParser::SpsData::ParseVUI(H265VuiParameters *vui, uint32_t max_num_sub_layers_minus1, uint8_t *nalu, size_t size, size_t &offset) { + vui->aspect_ratio_info_present_flag = Parser::GetBit(nalu, offset); + if (vui->aspect_ratio_info_present_flag) { + vui->aspect_ratio_idc = Parser::ReadBits(nalu, offset,8); + if (vui->aspect_ratio_idc == 255) { + vui->sar_width = Parser::ReadBits(nalu, offset,16); + vui->sar_height = Parser::ReadBits(nalu, offset,16); + } + } + vui->overscan_info_present_flag = Parser::GetBit(nalu, offset); + if (vui->overscan_info_present_flag) { + vui->overscan_appropriate_flag = Parser::GetBit(nalu, offset); + } + vui->video_signal_type_present_flag = Parser::GetBit(nalu, offset); + if (vui->video_signal_type_present_flag) { + vui->video_format = Parser::ReadBits(nalu, offset,3); + vui->video_full_range_flag = Parser::GetBit(nalu, offset); + vui->colour_description_present_flag = Parser::GetBit(nalu, offset); + if (vui->colour_description_present_flag) { + vui->colour_primaries = Parser::ReadBits(nalu, offset,8); + vui->transfer_characteristics = Parser::ReadBits(nalu, offset,8); + vui->matrix_coeffs = Parser::ReadBits(nalu, offset,8); + } + } + vui->chroma_loc_info_present_flag = Parser::GetBit(nalu, offset); + if (vui->chroma_loc_info_present_flag) { + vui->chroma_sample_loc_type_top_field = Parser::ExpGolomb::ReadUe(nalu, offset); + vui->chroma_sample_loc_type_bottom_field = Parser::ExpGolomb::ReadUe(nalu, offset); + } + vui->neutral_chroma_indication_flag = Parser::GetBit(nalu, offset); + vui->field_seq_flag = Parser::GetBit(nalu, offset); + vui->frame_field_info_present_flag = Parser::GetBit(nalu, offset); + vui->default_display_window_flag = Parser::GetBit(nalu, offset); + if (vui->default_display_window_flag) { + vui->def_disp_win_left_offset = Parser::ExpGolomb::ReadUe(nalu, offset); + vui->def_disp_win_right_offset = Parser::ExpGolomb::ReadUe(nalu, offset); + vui->def_disp_win_top_offset = Parser::ExpGolomb::ReadUe(nalu, offset); + vui->def_disp_win_bottom_offset = Parser::ExpGolomb::ReadUe(nalu, offset); + } + vui->vui_timing_info_present_flag = Parser::GetBit(nalu, offset); + if (vui->vui_timing_info_present_flag) { + vui->vui_num_units_in_tick = Parser::ReadBits(nalu, offset,32); + vui->vui_time_scale = Parser::ReadBits(nalu, offset,32); + vui->vui_poc_proportional_to_timing_flag = Parser::GetBit(nalu, offset); + if (vui->vui_poc_proportional_to_timing_flag) { + vui->vui_num_ticks_poc_diff_one_minus1 = Parser::ExpGolomb::ReadUe(nalu, offset); + } + vui->vui_hrd_parameters_present_flag = Parser::GetBit(nalu, offset); + if (vui->vui_hrd_parameters_present_flag) { + ParseHrdParameters(&vui->hrd_parameters, 1, max_num_sub_layers_minus1, nalu, size, offset); + } + } + vui->bitstream_restriction_flag = Parser::GetBit(nalu, offset); + if (vui->bitstream_restriction_flag) { + vui->tiles_fixed_structure_flag = Parser::GetBit(nalu, offset); + vui->motion_vectors_over_pic_boundaries_flag = Parser::GetBit(nalu, offset); + vui->restricted_ref_pic_lists_flag = Parser::GetBit(nalu, offset); + vui->min_spatial_segmentation_idc = Parser::ExpGolomb::ReadUe(nalu, offset); + vui->max_bytes_per_pic_denom = Parser::ExpGolomb::ReadUe(nalu, offset); + vui->max_bits_per_min_cu_denom = Parser::ExpGolomb::ReadUe(nalu, offset); + vui->log2_max_mv_length_horizontal = Parser::ExpGolomb::ReadUe(nalu, offset); + vui->log2_max_mv_length_vertical = Parser::ExpGolomb::ReadUe(nalu, offset); + } +} + +bool HEVCVideoParser::AccessUnitSigns::Parse(uint8_t *nalu, size_t /*size*/, std::map&/*sps_map*/, std::map& /*pps_map*/) { + size_t offset = 16; // 2 bytes NALU header + b_new_picture = Parser::GetBit(nalu, offset); + return true; +} + +bool HEVCVideoParser::AccessUnitSigns::IsNewPicture() { + return b_new_picture; +} + +void HEVCVideoParser::ExtraDataBuilder::AddSPS(uint8_t *sps, size_t size) { + m_sps_count_++; + size_t pos = m_sps_.GetSize(); + uint16_t spsSize = size & max_sps_size_; + m_sps_.SetSize(pos + spsSize +2); + uint8_t *data = m_sps_.GetData() + pos; + *data++ = Parser::GetLowByte(spsSize); + *data++ = Parser::GetHiByte(spsSize); + memcpy(data , sps, (size_t)spsSize); +} + +void HEVCVideoParser::ExtraDataBuilder::AddPPS(uint8_t *pps, size_t size) { + m_pps_count_++; + size_t pos = m_pps_.GetSize(); + uint16_t ppsSize = size & max_pps_size_; + m_pps_.SetSize(pos + ppsSize + 2); + uint8_t *data = m_pps_.GetData() + pos; + *data++ = Parser::GetLowByte(ppsSize); + *data++ = Parser::GetHiByte(ppsSize); + memcpy(data , pps, (size_t)ppsSize); +} + +bool HEVCVideoParser::ExtraDataBuilder::GetExtradata(ByteArray &extradata) { + if(m_sps_.GetSize() == 0 || m_pps_ .GetSize() == 0) { + return false; + } + if (m_sps_count_ > 0x1F) { + return false; + } + if (m_sps_.GetSize() < min_sps_size_) { + return false; + } + extradata.SetSize( + 21 + // reserved + 1 + // length size + 1 + // array size + 3 + // SPS type + SPS count (2) + m_sps_.GetSize() + + 3 + // PPS type + PPS count (2) + m_pps_.GetSize() + ); + + uint8_t *data = extradata.GetData(); + + memset(data, 0, extradata.GetSize()); + + *data = 0x01; // configurationVersion + data+=21; + *data++ = (0xFC | (nal_unit_length_size_ - 1)); // reserved(11111100) + lengthSizeMinusOne + + *data++ = static_cast(2); // reserved(11100000) + numOfSequenceParameterSets + + *data++ = NAL_UNIT_SPS; + *data++ = Parser::GetLowByte(static_cast(m_sps_count_)); + *data++ = Parser::GetHiByte(static_cast(m_sps_count_)); + + memcpy(data, m_sps_.GetData(), m_sps_.GetSize()); + data += m_sps_.GetSize(); + + *data++ = NAL_UNIT_PPS; + *data++ = Parser::GetLowByte(static_cast(m_pps_count_)); + *data++ = Parser::GetHiByte(static_cast(m_pps_count_)); + memcpy(data, m_pps_.GetData(), m_pps_.GetSize()); + data += m_pps_.GetSize(); + return true; +} + +bool HEVCVideoParser::CheckDataStreamEof(int n_video_bytes) { + if (n_video_bytes <= 0) { + m_eof_ = true; + return true; + } + return false; +} + +#define ZEROBYTES_SHORTSTARTCODE 2 //indicates the number of zero bytes in the short start-code prefix + +size_t HEVCVideoParser::EBSPtoRBSP(uint8_t *streamBuffer,size_t begin_bytepos, size_t end_bytepos) { + int count = 0; + if (end_bytepos < begin_bytepos) { + return end_bytepos; + } + uint8_t *streamBuffer_i = streamBuffer + begin_bytepos; + uint8_t *streamBuffer_end = streamBuffer + end_bytepos; + int reduce_count = 0; + for (; streamBuffer_i != streamBuffer_end; ) { + //starting from begin_bytepos to avoid header information + //in NAL unit, 0x000000, 0x000001 or 0x000002 shall not occur at any uint8_t-aligned position + uint8_t tmp =* streamBuffer_i; + if (count == ZEROBYTES_SHORTSTARTCODE) { + if (tmp == 0x03) { + //check the 4th uint8_t after 0x000003, except when cabac_zero_word is used, in which case the last three bytes of this NAL unit must be 0x000003 + if ((streamBuffer_i + 1 != streamBuffer_end) && (streamBuffer_i[1] > 0x03)) { + return static_cast(-1); + } + //if cabac_zero_word is used, the final uint8_t of this NAL unit(0x03) is discarded, and the last two bytes of RBSP must be 0x0000 + if (streamBuffer_i + 1 == streamBuffer_end) { + break; + } + memmove(streamBuffer_i, streamBuffer_i + 1, streamBuffer_end-streamBuffer_i - 1); + streamBuffer_end--; + reduce_count++; + count = 0; + tmp = *streamBuffer_i; + } + else if (tmp < 0x03) { + } + } + if (tmp == 0x00) { + count++; + } + else { + count = 0; + } + streamBuffer_i++; + } + return end_bytepos - begin_bytepos + reduce_count; +} + +//data stream functions +ParserResult HEVCVideoParser::Close() { + m_pmemory_ = NULL, + m_memory_size_ = 0, + m_allocated_size_ = 0, + m_pos_ = 0; + return PARSER_OK; +} + +ParserResult HEVCVideoParser::Realloc(size_t size) { + if (size > m_memory_size_) { + uint8_t* p_new_memory = new uint8_t [size]; + if (p_new_memory == NULL) { + return PARSER_OUT_OF_MEMORY; + } + m_allocated_size_ = size; + if (m_pmemory_ != NULL) { + delete m_pmemory_; + } + m_pmemory_ = p_new_memory; + } + m_memory_size_ = size; + return PARSER_OK; +} + +ParserResult HEVCVideoParser::Read(void* p_data, size_t size, size_t* p_read) { + if (p_data == NULL) { + return PARSER_INVALID_POINTER; + } + if (m_pmemory_ == NULL) { + return PARSER_NOT_INITIALIZED; + } + size_t to_read = std::min(size, m_memory_size_ - m_pos_); + memcpy(p_data, m_pmemory_ + m_pos_, to_read); + m_pos_ += to_read; + if(p_read != NULL) { + *p_read = to_read; + } + return PARSER_OK; +} + +ParserResult HEVCVideoParser::Write(const void* p_data, size_t size, size_t* p_written) { + if (p_data == NULL) { + return PARSER_INVALID_POINTER; + } + m_pos_ = 0; + if (Realloc(size)) { + return PARSER_STREAM_NOT_ALLOCATED; + } + + size_t to_write = std::min(size, m_memory_size_); + memcpy(m_pmemory_, p_data, to_write); + + if(p_written != NULL) { + *p_written = to_write; + } + return PARSER_OK; +} + +ParserResult HEVCVideoParser::Seek(ParserSeekOrigin e_origin, int64_t i_position, int64_t* p_new_position) { + switch(e_origin) { + case PARSER_SEEK_BEGIN: + m_pos_ = (size_t)i_position; + break; + + case PARSER_SEEK_CURRENT: + m_pos_ += (size_t)i_position; + break; + + case PARSER_SEEK_END: + m_pos_ = m_memory_size_ - (size_t)i_position; + break; + } + + if(m_pos_ > m_memory_size_) { + m_pos_ = m_memory_size_; + } + if(p_new_position != NULL) { + *p_new_position = m_pos_; + } + return PARSER_OK; +} + +ParserResult HEVCVideoParser::GetSize(int64_t* p_size) { + if (p_size != NULL) { + return PARSER_INVALID_POINTER; + } + *p_size = m_memory_size_; + return PARSER_OK; +} + +//size_id = 0 +int scaling_list_default_0 [1][6][16] = {{{16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16}, + {16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16}, + {16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16}, + {16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16}, + {16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16}, + {16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16}}}; +//size_id = 1, 2 +int scaling_list_default_1_2 [2][6][64] = {{{16,16,16,16,16,16,16,16,16,16,17,16,17,16,17,18,17,18,18,17,18,21,19,20,21,20,19,21,24,22,22,24,24,22,22,24,25,25,27,30,27,25,25,29,31,35,35,31,29,36,41,44,41,36,47,54,54,47,65,70,65,88,88,115}, + {16,16,16,16,16,16,16,16,16,16,17,16,17,16,17,18,17,18,18,17,18,21,19,20,21,20,19,21,24,22,22,24,24,22,22,24,25,25,27,30,27,25,25,29,31,35,35,31,29,36,41,44,41,36,47,54,54,47,65,70,65,88,88,115}, + {16,16,16,16,16,16,16,16,16,16,17,16,17,16,17,18,17,18,18,17,18,21,19,20,21,20,19,21,24,22,22,24,24,22,22,24,25,25,27,30,27,25,25,29,31,35,35,31,29,36,41,44,41,36,47,54,54,47,65,70,65,88,88,115}, + {16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,18,18,18,18,18,18,20,20,20,20,20,20,20,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,28,28,28,28,28,28,33,33,33,33,33,41,41,41,41,54,54,54,71,71,91}, + {16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,18,18,18,18,18,18,20,20,20,20,20,20,20,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,28,28,28,28,28,28,33,33,33,33,33,41,41,41,41,54,54,54,71,71,91}, + {16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,18,18,18,18,18,18,20,20,20,20,20,20,20,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,28,28,28,28,28,28,33,33,33,33,33,41,41,41,41,54,54,54,71,71,91}}, + {{16,16,16,16,16,16,16,16,16,16,17,16,17,16,17,18,17,18,18,17,18,21,19,20,21,20,19,21,24,22,22,24,24,22,22,24,25,25,27,30,27,25,25,29,31,35,35,31,29,36,41,44,41,36,47,54,54,47,65,70,65,88,88,115}, + {16,16,16,16,16,16,16,16,16,16,17,16,17,16,17,18,17,18,18,17,18,21,19,20,21,20,19,21,24,22,22,24,24,22,22,24,25,25,27,30,27,25,25,29,31,35,35,31,29,36,41,44,41,36,47,54,54,47,65,70,65,88,88,115}, + {16,16,16,16,16,16,16,16,16,16,17,16,17,16,17,18,17,18,18,17,18,21,19,20,21,20,19,21,24,22,22,24,24,22,22,24,25,25,27,30,27,25,25,29,31,35,35,31,29,36,41,44,41,36,47,54,54,47,65,70,65,88,88,115}, + {16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,18,18,18,18,18,18,20,20,20,20,20,20,20,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,28,28,28,28,28,28,33,33,33,33,33,41,41,41,41,54,54,54,71,71,91}, + {16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,18,18,18,18,18,18,20,20,20,20,20,20,20,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,28,28,28,28,28,28,33,33,33,33,33,41,41,41,41,54,54,54,71,71,91}, + {16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,18,18,18,18,18,18,20,20,20,20,20,20,20,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,28,28,28,28,28,28,33,33,33,33,33,41,41,41,41,54,54,54,71,71,91}}}; +//size_id = 3 +int scaling_list_default_3 [1][2][64] = {{{16,16,16,16,16,16,16,16,16,16,17,16,17,16,17,18,17,18,18,17,18,21,19,20,21,20,19,21,24,22,22,24,24,22,22,24,25,25,27,30,27,25,25,29,31,35,35,31,29,36,41,44,41,36,47,54,54,47,65,70,65,88,88,115}, + {16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,18,18,18,18,18,18,20,20,20,20,20,20,20,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,28,28,28,28,28,28,33,33,33,33,33,41,41,41,41,54,54,54,71,71,91}}}; \ No newline at end of file diff --git a/src/parser/hevc_parser.h b/src/parser/hevc_parser.h index 385bd78e37..773bb04a65 100644 --- a/src/parser/hevc_parser.h +++ b/src/parser/hevc_parser.h @@ -22,6 +22,90 @@ THE SOFTWARE. #pragma once #include "roc_video_parser.h" +#include "parser_buffer.h" + +#include +#include +#include + +#define PARSER_SECOND 10000000L // 1 second in 100 nanoseconds +#define DATA_STREAM_SIZE 10*1024 // allocating buffer to hold video stream +#define INIT_ARRAY_SIZE 1024 +#define ARRAY_MAX_SIZE (1LL << 60LL) // extremely large maximum size + +class ByteArray { +protected: + uint8_t *m_pdata_; + size_t m_size_; + size_t m_max_size_; +public: + ByteArray() : m_pdata_(0), m_size_(0), m_max_size_(0) {} + ByteArray(const ByteArray &other) : m_pdata_(0), m_size_(0), m_max_size_(0) { + *this = other; + } + ByteArray(size_t num) : m_pdata_(0), m_size_(0), m_max_size_(0) { + SetSize(num); + } + virtual ~ByteArray() { + if (m_pdata_ != 0) { + delete[] m_pdata_; + } + } + void SetSize(size_t num) { + if (num == m_size_) { + return; + } + if (num < m_size_) { + memset(m_pdata_ + num, 0, m_max_size_ - num); + } + else if (num > m_max_size_) { + // This is done to prevent the following error from surfacing + // for the p_new_data allocation on some compilers: + // -Werror=alloc-size-larger-than= + size_t new_size = (num / INIT_ARRAY_SIZE) * INIT_ARRAY_SIZE + INIT_ARRAY_SIZE; + if (new_size > ARRAY_MAX_SIZE) { + return; + } + m_max_size_ = new_size; + + uint8_t *p_new_data = new uint8_t[m_max_size_]; + memset(p_new_data, 0, m_max_size_); + if (m_pdata_ != NULL) { + memcpy(p_new_data, m_pdata_, m_size_); + delete[] m_pdata_; + } + m_pdata_ = p_new_data; + } + m_size_ = num; + } + void Copy(const ByteArray &old) { + if (m_max_size_ < old.m_size_) { + m_max_size_ = old.m_max_size_; + if (m_pdata_ != NULL) { + delete[] m_pdata_; + } + m_pdata_ = new uint8_t[m_max_size_]; + memset(m_pdata_, 0, m_max_size_); + } + memcpy(m_pdata_, old.m_pdata_, old.m_size_); + m_size_ = old.m_size_; + } + uint8_t operator[] (size_t iPos) const { + return m_pdata_[iPos]; + } + uint8_t& operator[] (size_t iPos) { + return m_pdata_[iPos]; + } + ByteArray& operator=(const ByteArray &other) { + SetSize(other.GetSize()); + if (GetSize() > 0) { + memcpy(GetData(), other.GetData(), GetSize()); + } + return *this; + } + uint8_t *GetData() const { return m_pdata_; } + size_t GetSize() const { return m_size_; } +}; class HEVCVideoParser : public RocVideoParser { @@ -36,15 +120,497 @@ public: * * @return rocDecStatus */ - virtual rocDecStatus Initialize(RocdecParserParams *pParams); + virtual rocDecStatus Initialize(RocdecParserParams *pParams); /** * @brief Function to Parse video data: Typically called from application when a demuxed picture is ready to be parsed * * @param pData: Pointer to picture data * @return rocDecStatus: returns success on completion, else error_code for failure */ - virtual rocDecStatus ParseVideoData(RocdecSourceDataPacket *pData); // pure virtual: implemented by derived class + virtual rocDecStatus ParseVideoData(RocdecSourceDataPacket *pData); // pure virtual: implemented by derived class -private: + /** + * @brief HEVCParser object destructor + * + */ + virtual ~HEVCVideoParser(); + + /** + * @brief Function to set the frames per second + * + * @param fps: Value of fps to set in double + * @return void: returns on completion + */ + void SetFrameRate(double fps); + /** + * @brief Function to get the frames per second + * + * @return double: returns fps in double on completion. + */ + double GetFrameRate() const; + /** + * @brief Function to reinitialize the HEVC parser. Resets the timestamp, packet count and pointer to beginning of stream. + * + * @return ParserResult: returns PARSER_OK on successful completion. + */ + ParserResult ReInit(); + /** + * @brief Function to get the output buffer in type ParserBuffer after parsing the HEVC stream. + * + * @param pp_data: Pointer to pointer to the ParserBuffer data which is also the returned. + * @return ParserResult: returns PARSER_OK on successful completion. + */ + ParserResult QueryOutput(ParserBuffer** pp_data); + /** + * @brief Function to set the parser to beginning of frame and call the SPS and PPS funtions. + * + * @return void: returns on completion + */ + void FindFirstFrameSPSandPPS(); + /** + * @brief Function to check if it's the last frame after dumuxing. + * + * @return bool: returns true if last frame, else false. + */ + bool CheckDataStreamEof(int n_video_bytes); + +protected: + // ISO-IEC 14496-15-2004.pdf, page 14, table 1 " NAL unit types in elementary streams. + enum NalUnitType { + NAL_UNIT_CODED_SLICE_TRAIL_N = 0, // 0 + NAL_UNIT_CODED_SLICE_TRAIL_R, // 1 + + NAL_UNIT_CODED_SLICE_TSA_N, // 2 + NAL_UNIT_CODED_SLICE_TLA_R, // 3 + + NAL_UNIT_CODED_SLICE_STSA_N, // 4 + NAL_UNIT_CODED_SLICE_STSA_R, // 5 + + NAL_UNIT_CODED_SLICE_RADL_N, // 6 + NAL_UNIT_CODED_SLICE_RADL_R, // 7 + + NAL_UNIT_CODED_SLICE_RASL_N, // 8 + NAL_UNIT_CODED_SLICE_RASL_R, // 9 + + NAL_UNIT_RESERVED_VCL_N10, + NAL_UNIT_RESERVED_VCL_R11, + NAL_UNIT_RESERVED_VCL_N12, + NAL_UNIT_RESERVED_VCL_R13, + NAL_UNIT_RESERVED_VCL_N14, + NAL_UNIT_RESERVED_VCL_R15, + + NAL_UNIT_CODED_SLICE_BLA_W_LP, // 16 + NAL_UNIT_CODED_SLICE_BLA_W_RADL, // 17 + NAL_UNIT_CODED_SLICE_BLA_N_LP, // 18 + NAL_UNIT_CODED_SLICE_IDR_W_RADL, // 19 + NAL_UNIT_CODED_SLICE_IDR_N_LP, // 20 + NAL_UNIT_CODED_SLICE_CRA, // 21 + NAL_UNIT_RESERVED_IRAP_VCL22, + NAL_UNIT_RESERVED_IRAP_VCL23, + + NAL_UNIT_RESERVED_VCL24, + NAL_UNIT_RESERVED_VCL25, + NAL_UNIT_RESERVED_VCL26, + NAL_UNIT_RESERVED_VCL27, + NAL_UNIT_RESERVED_VCL28, + NAL_UNIT_RESERVED_VCL29, + NAL_UNIT_RESERVED_VCL30, + NAL_UNIT_RESERVED_VCL31, + + NAL_UNIT_VPS, // 32 + NAL_UNIT_SPS, // 33 + NAL_UNIT_PPS, // 34 + NAL_UNIT_ACCESS_UNIT_DELIMITER, // 35 + NAL_UNIT_EOS, // 36 + NAL_UNIT_EOB, // 37 + NAL_UNIT_FILLER_DATA, // 38 + NAL_UNIT_PREFIX_SEI, // 39 + NAL_UNIT_SUFFIX_SEI, // 40 + NAL_UNIT_RESERVED_NVCL41, + NAL_UNIT_RESERVED_NVCL42, + NAL_UNIT_RESERVED_NVCL43, + NAL_UNIT_RESERVED_NVCL44, + NAL_UNIT_RESERVED_NVCL45, + NAL_UNIT_RESERVED_NVCL46, + NAL_UNIT_RESERVED_NVCL47, + NAL_UNIT_UNSPECIFIED_48, + NAL_UNIT_UNSPECIFIED_49, + NAL_UNIT_UNSPECIFIED_50, + NAL_UNIT_UNSPECIFIED_51, + NAL_UNIT_UNSPECIFIED_52, + NAL_UNIT_UNSPECIFIED_53, + NAL_UNIT_UNSPECIFIED_54, + NAL_UNIT_UNSPECIFIED_55, + NAL_UNIT_UNSPECIFIED_56, + NAL_UNIT_UNSPECIFIED_57, + NAL_UNIT_UNSPECIFIED_58, + NAL_UNIT_UNSPECIFIED_59, + NAL_UNIT_UNSPECIFIED_60, + NAL_UNIT_UNSPECIFIED_61, + NAL_UNIT_UNSPECIFIED_62, + NAL_UNIT_UNSPECIFIED_63, + NAL_UNIT_INVALID, + }; + + struct NalUnitHeader { + uint32_t forbidden_zero_bit; + uint32_t nal_unit_type; + uint32_t nuh_layer_id; + uint32_t nuh_temporal_id_plus1; + uint32_t num_emu_byte_removed; + }; + + enum H265ScalingListSize { + H265_SCALING_LIST_4x4 = 0, + H265_SCALING_LIST_8x8, + H265_SCALING_LIST_16x16, + H265_SCALING_LIST_32x32, + H265_SCALING_LIST_SIZE_NUM + }; + + typedef struct { + uint32_t general_profile_space; //u(2) + bool general_tier_flag; //u(1) + uint32_t general_profile_idc; //u(5) + bool general_profile_compatibility_flag[32]; //u(1) + bool general_progressive_source_flag; //u(1) + bool general_interlaced_source_flag; //u(1) + bool general_non_packed_constraint_flag; //u(1) + bool general_frame_only_constraint_flag; //u(1) + uint64_t general_reserved_zero_44bits; //u(44) + uint32_t general_level_idc; //u(8) + //max_num_sub_layers_minus1 max is 7 - 1 = 6 + bool sub_layer_profile_present_flag[6]; //u(1) + bool sub_layer_level_present_flag[6]; //u(1) + + uint32_t reserved_zero_2bits[8]; //u(2) + + uint32_t sub_layer_profile_space[6]; //u(2) + bool sub_layer_tier_flag[6]; //u(1) + uint32_t sub_layer_profile_idc[6]; //u(5) + bool sub_layer_profile_compatibility_flag[6][32]; //u(1) + bool sub_layer_progressive_source_flag[6]; //u(1) + bool sub_layer_interlaced_source_flag[6]; //u(1) + bool sub_layer_non_packed_constraint_flag[6]; //u(1) + bool sub_layer_frame_only_constraint_flag[6]; //u(1) + uint64_t sub_layer_reserved_zero_44bits[6]; //u(44) + uint32_t sub_layer_level_idc[6]; //u(8) + } H265ProfileTierLevel; + +#define H265_SCALING_LIST_NUM 6 ///< list number for quantization matrix +#define H265_SCALING_LIST_MAX_I 64 + + typedef struct { + bool scaling_list_pred_mode_flag[4][6]; //u(1) + uint32_t scaling_list_pred_matrix_id_delta[4][6]; //ue(v) + int32_t scaling_list_dc_coef_minus8[4][6]; //se(v) + int32_t scaling_list_delta_coef; //se(v) could have issues...... + int32_t scaling_list[H265_SCALING_LIST_SIZE_NUM][H265_SCALING_LIST_NUM][H265_SCALING_LIST_MAX_I]; + } H265ScalingListData; + + typedef struct { + int32_t num_negative_pics; + int32_t num_positive_pics; + int32_t num_of_pics; + int32_t num_of_delta_poc; + int32_t delta_poc[16]; + bool used_by_curr_pic[16]; + } H265ShortTermRPS; + + typedef struct { + int32_t num_of_pics; + int32_t POCs[32]; + bool used_by_curr_pic[32]; + } H265LongTermRPS; + + typedef struct { + //CpbCnt = cpb_cnt_minus1 + uint32_t bit_rate_value_minus1[32]; //ue(v) + uint32_t cpb_size_value_minus1[32]; //ue(v) + uint32_t cpb_size_du_value_minus1[32]; //ue(v) + uint32_t bit_rate_du_value_minus1[32]; //ue(v) + bool cbr_flag[32]; //u(1) + } H265SubLayerHrdParameters; + + typedef struct { + bool nal_hrd_parameters_present_flag; //u(1) + bool vcl_hrd_parameters_present_flag; //u(1) + bool sub_pic_hrd_params_present_flag; //u(1) + uint32_t tick_divisor_minus2; //u(8) + uint32_t du_cpb_removal_delay_increment_length_minus1; //u(5) + bool sub_pic_cpb_params_in_pic_timing_sei_flag; //u(1) + uint32_t dpb_output_delay_du_length_minus1; //u(5) + uint32_t bit_rate_scale; //u(4) + uint32_t cpb_size_scale; //u(4) + uint32_t cpb_size_du_scale; //u(4) + uint32_t initial_cpb_removal_delay_length_minus1; //u(5) + uint32_t au_cpb_removal_delay_length_minus1; //u(5) + uint32_t dpb_output_delay_length_minus1; //u(5) + bool fixed_pic_rate_general_flag[7]; //u(1) + bool fixed_pic_rate_within_cvs_flag[7]; //u(1) + uint32_t elemental_duration_in_tc_minus1[7]; //ue(v) + bool low_delay_hrd_flag[7]; //u(1) + uint32_t cpb_cnt_minus1[7]; //ue(v) + //sub_layer_hrd_parameters() + H265SubLayerHrdParameters sub_layer_hrd_parameters_0[7]; + //sub_layer_hrd_parameters() + H265SubLayerHrdParameters sub_layer_hrd_parameters_1[7]; + } H265HrdParameters; + + typedef struct { + bool aspect_ratio_info_present_flag; //u(1) + uint32_t aspect_ratio_idc; //u(8) + uint32_t sar_width; //u(16) + uint32_t sar_height; //u(16) + bool overscan_info_present_flag; //u(1) + bool overscan_appropriate_flag; //u(1) + bool video_signal_type_present_flag; //u(1) + uint32_t video_format; //u(3) + bool video_full_range_flag; //u(1) + bool colour_description_present_flag; //u(1) + uint32_t colour_primaries; //u(8) + uint32_t transfer_characteristics; //u(8) + uint32_t matrix_coeffs; //u(8) + bool chroma_loc_info_present_flag; //u(1) + uint32_t chroma_sample_loc_type_top_field; //ue(v) + uint32_t chroma_sample_loc_type_bottom_field; //ue(v) + bool neutral_chroma_indication_flag; //u(1) + bool field_seq_flag; //u(1) + bool frame_field_info_present_flag; //u(1) + bool default_display_window_flag; //u(1) + uint32_t def_disp_win_left_offset; //ue(v) + uint32_t def_disp_win_right_offset; //ue(v) + uint32_t def_disp_win_top_offset; //ue(v) + uint32_t def_disp_win_bottom_offset; //ue(v) + bool vui_timing_info_present_flag; //u(1) + uint32_t vui_num_units_in_tick; //u(32) + uint32_t vui_time_scale; //u(32) + bool vui_poc_proportional_to_timing_flag; //u(1) + uint32_t vui_num_ticks_poc_diff_one_minus1; //ue(v) + bool vui_hrd_parameters_present_flag; //u(1) + //hrd_parameters() + H265HrdParameters hrd_parameters; + bool bitstream_restriction_flag; //u(1) + bool tiles_fixed_structure_flag; //u(1) + bool motion_vectors_over_pic_boundaries_flag; //u(1) + bool restricted_ref_pic_lists_flag; //u(1) + uint32_t min_spatial_segmentation_idc; //ue(v) + uint32_t max_bytes_per_pic_denom; //ue(v) + uint32_t max_bits_per_min_cu_denom; //ue(v) + uint32_t log2_max_mv_length_horizontal; //ue(v) + uint32_t log2_max_mv_length_vertical; //ue(v) + } H265VuiParameters; + + typedef struct { + uint32_t rbsp_stop_one_bit; /* equal to 1 */ + uint32_t rbsp_alignment_zero_bit; /* equal to 0 */ + } H265RbspTrailingBits; + + struct SpsData { + 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) + //profile_tier_level( sps_max_sub_layers_minus1 ) + H265ProfileTierLevel profile_tier_level; + uint32_t sps_seq_parameter_set_id; //ue(v) + uint32_t chroma_format_idc; //ue(v) + bool separate_colour_plane_flag; //u(1) + uint32_t pic_width_in_luma_samples; //ue(v) + uint32_t pic_height_in_luma_samples; //ue(v) + uint32_t max_cu_width; + uint32_t max_cu_height; + uint32_t max_cu_depth; + bool conformance_window_flag; //u(1) + uint32_t conf_win_left_offset; //ue(v) + uint32_t conf_win_right_offset; //ue(v) + uint32_t conf_win_top_offset; //ue(v) + uint32_t conf_win_bottom_offset; //ue(v) + uint32_t bit_depth_luma_minus8; //ue(v) + uint32_t bit_depth_chroma_minus8; //ue(v) + uint32_t log2_max_pic_order_cnt_lsb_minus4; //ue(v) + bool sps_sub_layer_ordering_info_present_flag; //u(1) + uint32_t sps_max_dec_pic_buffering_minus1[6]; //ue(v) + uint32_t sps_max_num_reorder_pics[6]; //ue(v) + uint32_t sps_max_latency_increase_plus1[6]; //ue(v) + uint32_t log2_min_luma_coding_block_size_minus3; //ue(v) + uint32_t log2_diff_max_min_luma_coding_block_size; //ue(v) + uint32_t log2_min_transform_block_size_minus2; //ue(v) + uint32_t log2_diff_max_min_transform_block_size; //ue(v) + uint32_t max_transform_hierarchy_depth_inter; //ue(v) + uint32_t max_transform_hierarchy_depth_intra; //ue(v) + bool scaling_list_enabled_flag; //u(1) + bool sps_scaling_list_data_present_flag; //u(1) + //scaling_list_data() + H265ScalingListData scaling_list_data; + bool amp_enabled_flag; //u(1) + bool sample_adaptive_offset_enabled_flag; //u(1) + bool pcm_enabled_flag; //u(1) + uint32_t pcm_sample_bit_depth_luma_minus1; //u(4) + uint32_t pcm_sample_bit_depth_chroma_minus1; //u(4) + uint32_t log2_min_pcm_luma_coding_block_size_minus3; //ue(v) + uint32_t log2_diff_max_min_pcm_luma_coding_block_size; //ue(v) + bool pcm_loop_filter_disabled_flag; //u(1) + uint32_t num_short_term_ref_pic_sets; //ue(v) + //short_term_ref_pic_set(i) max is 64 + H265ShortTermRPS stRPS[64]; + H265LongTermRPS ltRPS; + //H265_short_term_ref_pic_set_t short_term_ref_pic_set[64]; + bool long_term_ref_pics_present_flag; //u(1) + uint32_t num_long_term_ref_pics_sps; //ue(v) + //max is 32 + uint32_t lt_ref_pic_poc_lsb_sps[32]; //u(v) + bool used_by_curr_pic_lt_sps_flag[32]; //u(1) + bool sps_temporal_mvp_enabled_flag; //u(1) + bool strong_intra_smoothing_enabled_flag; //u(1) + bool vui_parameters_present_flag; //u(1) + //vui_parameters() + H265VuiParameters vui_parameters; + bool sps_extension_flag; //u(1) + bool sps_extension_data_flag; //u(1) + //rbsp_trailing_bits( ) + H265RbspTrailingBits rbsp_trailing_bits; + + SpsData(void) { + memset(this, 0, sizeof(*this)); + } + + bool Parse(uint8_t *data, size_t size); + void ParsePTL(H265ProfileTierLevel *ptl, bool profile_present_flag, uint32_t max_num_sub_layers_minus1, uint8_t *nalu, size_t size, size_t &offset); + void ParseSubLayerHrdParameters(H265SubLayerHrdParameters *sub_hrd, uint32_t CpbCnt, bool sub_pic_hrd_params_present_flag, uint8_t *nalu, size_t size, size_t &offset); + void ParseHrdParameters(H265HrdParameters *hrd, bool common_inf_present_flag, uint32_t max_num_sub_layers_minus1, uint8_t *nalu, size_t size, size_t &offset); + static void ParseScalingList(H265ScalingListData * s_data, uint8_t *data, size_t size,size_t &offset); + void ParseVUI(H265VuiParameters *vui, uint32_t max_num_sub_layers_minus1, uint8_t *data, size_t size,size_t &offset); + void ParseShortTermRefPicSet(H265ShortTermRPS *rps, int32_t st_rps_idx, uint32_t num_short_term_ref_pic_sets, H265ShortTermRPS rps_ref[], uint8_t *data, size_t size,size_t &offset); + }; + + struct PpsData { + 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) + bool output_flag_present_flag; //u(1) + uint32_t num_extra_slice_header_bits; //u(3) + bool sign_data_hiding_enabled_flag; //u(1) + bool cabac_init_present_flag; //u(1) + uint32_t num_ref_idx_l0_default_active_minus1; //ue(v) + uint32_t num_ref_idx_l1_default_active_minus1; //ue(v) + int32_t init_qp_minus26; //se(v) + bool constrained_intra_pred_flag; //u(1) + bool transform_skip_enabled_flag; //u(1) + bool cu_qp_delta_enabled_flag; //u(1) + uint32_t diff_cu_qp_delta_depth; //ue(v) + int32_t pps_cb_qp_offset; //se(v) + int32_t pps_cr_qp_offset; //se(v) + bool pps_slice_chroma_qp_offsets_present_flag; //u(1) + bool weighted_pred_flag; //u(1) + bool weighted_bipred_flag; //u(1) + bool transquant_bypass_enabled_flag; //u(1) + bool tiles_enabled_flag; //u(1) + bool entropy_coding_sync_enabled_flag; //u(1) + uint32_t num_tile_columns_minus1; //ue(v) + uint32_t num_tile_rows_minus1; //ue(v) + bool uniform_spacing_flag; //u(1) + //PicWidthInCtbsY = Ceil( pic_width_in_luma_samples / CtbSizeY ) = 256 assume max width is 4096 + //CtbSizeY = 1< &sps_map, std::map &pps_map); + bool IsNewPicture(); + }; + + class ExtraDataBuilder { + public: + ExtraDataBuilder() : m_sps_count_(0), m_pps_count_(0) {} + + void AddSPS(uint8_t *sps, size_t size); + void AddPPS(uint8_t *pps, size_t size); + bool GetExtradata(ByteArray &extradata); + + private: + ByteArray m_sps_; + ByteArray m_pps_; + int32_t m_sps_count_; + int32_t m_pps_count_; + }; + + friend struct AccessUnitSigns; + + static const uint8_t nal_unit_length_size_ = 4U; + + static const size_t m_read_size_ = 1024*4; + + static const uint16_t max_sps_size_ = 0xFFFF; + static const uint16_t min_sps_size_ = 5; + static const uint16_t max_pps_size_ = 0xFFFF; + + NalUnitHeader ReadNextNaluUnit(size_t *offset, size_t *nalu, size_t *size); + void FindSPSandPPS(); + static inline NalUnitHeader GetNaluUnitType(uint8_t *nal_unit) { + NalUnitHeader nalu_header; + nalu_header.num_emu_byte_removed = 0; + //read nalu header + nalu_header.forbidden_zero_bit = (uint32_t) ((nal_unit[0] >> 7)&1); + nalu_header.nal_unit_type = (uint32_t) ((nal_unit[0] >> 1)&63); + nalu_header.nuh_layer_id = (uint32_t) (((nal_unit[0]&1) << 6) | ((nal_unit[1] & 248) >> 3)); + nalu_header.nuh_temporal_id_plus1 = (uint32_t) (nal_unit[1] & 7); + + return nalu_header; + } + size_t EBSPtoRBSP(uint8_t *streamBuffer,size_t begin_bytepos, size_t end_bytepos); + + ByteArray m_read_data_; + ByteArray m_extra_data_; + + ByteArray m_EBSP_to_RBSP_data_; + + bool m_use_start_codes_; + int64_t m_current_frame_timestamp_; + std::map m_sps_map_; + std::map m_pps_map_; + size_t m_packet_count_; + bool m_eof_; + double m_fps_; + size_t m_max_frames_number_; + + // data stream info + uint8_t* m_pmemory_; + size_t m_memory_size_; + size_t m_allocated_size_; + size_t m_pos_; + + ParserResult Close(); + ParserResult Read(void* p_data, size_t size, size_t* p_read); + ParserResult Write(const void* p_data, size_t size, size_t* p_written); + ParserResult Seek(ParserSeekOrigin e_origin, int64_t i_position, int64_t* p_new_position); + ParserResult GetSize(int64_t* p_size); + ParserResult Realloc(size_t size); }; \ No newline at end of file diff --git a/src/parser/parser_buffer.cpp b/src/parser/parser_buffer.cpp new file mode 100644 index 0000000000..a69a7affe4 --- /dev/null +++ b/src/parser/parser_buffer.cpp @@ -0,0 +1,108 @@ +/* +Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "parser_buffer.h" + +ParserBuffer::ParserBuffer() : + m_buffer_(NULL), + m_packet_size_(0), + m_duration_(0), + m_current_timestamp_(0) {} + +ParserBuffer::~ParserBuffer () { + if (m_buffer_) { + delete[] m_buffer_; + } + m_buffer_ = NULL; + m_packet_size_ = 0; + m_duration_ = 0; + m_current_timestamp_ = 0; +} + +int64_t ParserBuffer::GetPts() const { + return m_current_timestamp_; +} + +void ParserBuffer::SetPts(int64_t pts) { + if (pts == m_current_timestamp_) { + return; + } + m_current_timestamp_ = pts; +} + +int64_t ParserBuffer::GetDuration() const { + return m_duration_; +} + +void ParserBuffer::SetDuration(int64_t duration) { + m_duration_ = duration; +} + +bool ParserBuffer::IsReusable() { return PARSER_NOT_IMPLEMENTED; } + +ParserResult ParserBuffer::SetSize(size_t new_size) { + m_packet_size_ = new_size; + return PARSER_OK; +} + +size_t ParserBuffer::GetSize() { + return m_packet_size_; +} + +void* ParserBuffer::GetNative() { + return m_buffer_; +} + +void ParserBuffer::SetNative(size_t size) { + m_buffer_ = new uint8_t[size]; +} + +ParserResult ParserBuffer::AllocBuffer(ParserMemoryType type, size_t size, ParserBuffer** pp_buffer) { + ParserResult res = PARSER_OK; + switch(type) { + case PARSER_MEMORY_HOST: { + ParserBuffer* p_new_buffer = new ParserBuffer; + if (p_new_buffer != NULL) { + p_new_buffer->SetNative(size); + res = p_new_buffer->SetSize(size); + if (res != PARSER_OK) { + return res; + } + *pp_buffer = p_new_buffer; + } + } + break; + case PARSER_MEMORY_HIP: { + res = PARSER_NOT_IMPLEMENTED; + } + break; + case PARSER_MEMORY_UNKNOWN:{ + res = PARSER_NOT_IMPLEMENTED; + } + break; + default: { + res = PARSER_INVALID_ARG; + } + break; + } + return res; +} \ No newline at end of file diff --git a/src/parser/parser_buffer.h b/src/parser/parser_buffer.h new file mode 100644 index 0000000000..085f3ae00d --- /dev/null +++ b/src/parser/parser_buffer.h @@ -0,0 +1,69 @@ +/* +Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef PARSERBUFFER_H +#define PARSERBUFFER_H +#pragma once + +#include +#include +#include +#include +#include +#include "roc_video_parser.h" + +typedef enum ParserMemoryType { + PARSER_MEMORY_UNKNOWN = 0, + PARSER_MEMORY_HOST = 1, + PARSER_MEMORY_HIP = 2, +} ParserMemoryType; + +class ParserBuffer { +public: + ParserBuffer(); + virtual ~ParserBuffer(); + + virtual ParserResult SetSize(size_t new_size); + virtual size_t GetSize(); + virtual void* GetNative(); + virtual void SetNative(size_t size); + + //parser data functions + virtual bool IsReusable(); + virtual void SetPts(int64_t pts); + virtual int64_t GetPts() const; + virtual void SetDuration(int64_t duration); + virtual int64_t GetDuration() const; + + static ParserResult AllocBuffer(ParserMemoryType type, size_t size, ParserBuffer** pp_buffer); + +private: + int64_t m_current_timestamp_; + int64_t m_duration_; + size_t m_packet_size_; + uint8_t* m_buffer_; +}; + +// smart pointer +typedef std::shared_ptr ParserBufferPtr; + +#endif // PARSERBUFFER_H \ No newline at end of file diff --git a/src/parser/roc_video_parser.h b/src/parser/roc_video_parser.h index 12f2370290..5a190aa277 100644 --- a/src/parser/roc_video_parser.h +++ b/src/parser/roc_video_parser.h @@ -51,3 +51,117 @@ protected: PFNVIDDISPLAYCALLBACK pfn_display_picture_cb_; /**< Called whenever a picture is ready to be displayed (display order) */ PFNVIDSEIMSGCALLBACK pfn_get_sei_message_cb_; /**< Called when all SEI messages are parsed for particular frame */ }; + +enum ParserSeekOrigin { + PARSER_SEEK_BEGIN = 0, + PARSER_SEEK_CURRENT = 1, + PARSER_SEEK_END = 2, +}; + +typedef enum ParserResult { + PARSER_OK = 0, + PARSER_FAIL , + +// common errors + PARSER_UNEXPECTED , + + PARSER_ACCESS_DENIED , + PARSER_INVALID_ARG , + PARSER_OUT_OF_RANGE , + + PARSER_OUT_OF_MEMORY , + PARSER_INVALID_POINTER , + + PARSER_NO_INTERFACE , + PARSER_NOT_IMPLEMENTED , + PARSER_NOT_SUPPORTED , + PARSER_NOT_FOUND , + + PARSER_ALREADY_INITIALIZED , + PARSER_NOT_INITIALIZED , + + PARSER_INVALID_FORMAT ,// invalid data format + + PARSER_WRONG_STATE , + PARSER_FILE_NOT_OPEN ,// cannot open file + PARSER_STREAM_NOT_ALLOCATED , + +// device common codes + PARSER_NO_DEVICE , + + //result codes + PARSER_EOF , + PARSER_REPEAT , + + //error codes + PARSER_INVALID_DATA_TYPE ,//invalid data type + PARSER_INVALID_RESOLUTION ,//invalid resolution (width or height) + PARSER_CODEC_NOT_SUPPORTED ,//codec not supported +} ParserResult; + +// helpers +namespace Parser { + inline char GetLowByte(uint16_t data) { + return (data >> 8); + } + + inline char GetHiByte(uint16_t data) { + return (data & 0xFF); + } + + inline bool GetBit(const uint8_t *data, size_t &bit_idx) { + bool ret = (data[bit_idx / 8] >> (7 - bit_idx % 8) & 1); + bit_idx++; + return ret; + } + inline uint32_t GetBitToUint32(const uint8_t *data, size_t &bit_idx) { + uint32_t ret = (data[bit_idx / 8] >> (7 - bit_idx % 8) & 1); + bit_idx++; + return ret; + } + + inline uint32_t ReadBits(const uint8_t *data, size_t &start_bit_idx, size_t bits_to_read) { + if (bits_to_read > 32) { + return 0; // assert(0); + } + uint32_t result = 0; + for (size_t i = 0; i < bits_to_read; i++) { + result = result << 1; + result |= GetBitToUint32(data, start_bit_idx); // start_bit_idx incremented inside + } + return result; + } + + inline size_t CountContiniusZeroBits(const uint8_t *data, size_t &start_bit_idx) { + size_t start_bit_idx_org = start_bit_idx; + while (GetBit(data, start_bit_idx) == false) {} // start_bit_idx incremented inside + start_bit_idx--; // remove non zero + return start_bit_idx - start_bit_idx_org; + } + + namespace ExpGolomb { + inline uint32_t ReadUe(const uint8_t *data, size_t &start_bit_idx) { + size_t zero_bits_count = CountContiniusZeroBits(data, start_bit_idx); // start_bit_idx incremented inside + if (zero_bits_count > 30) { + return 0; // assert(0) + } + + uint32_t left_part = (0x1 << zero_bits_count) - 1; + start_bit_idx++; + uint32_t rightPart = ReadBits(data, start_bit_idx, zero_bits_count); + return left_part + rightPart; + } + + inline uint32_t ReadSe(const uint8_t *data, size_t &start_bit_idx) { + uint32_t ue = ReadUe(data, start_bit_idx); + // se From Ue + uint32_t mod2 = ue % 2; + uint32_t r = ue / 2 + mod2; + + if (mod2 == 0) { + return r * -1; + } + return r; + } + } +} \ No newline at end of file