From 395a1249c1310ee00a8c2107cf52eecc40cfd762 Mon Sep 17 00:00:00 2001 From: jeffqjiangNew <142832361+jeffqjiangNew@users.noreply.github.com> Date: Tue, 16 Jan 2024 20:57:40 -0500 Subject: [PATCH] Added initial AVC parser. (#176) * * rocDecode/AVC: Added initial AVC parser. - Added AVC SPS, PPS and slice header parsing functions. - Merged common parsing code from AVC and HEVC parsers to their super class. * * rocDecode/AVC: Formating changes. No functional changes. --- src/parser/avc_defines.h | 334 +++++++ src/parser/avc_parser.cpp | 1279 ++++++++++++++++++++++++ src/parser/avc_parser.h | 153 +++ src/parser/h264_parser.cpp | 62 -- src/parser/h264_parser.h | 58 -- src/parser/hevc_defines.h | 1 - src/parser/hevc_parser.cpp | 149 +-- src/parser/hevc_parser.h | 57 +- src/parser/parser_handle.h | 4 +- src/parser/roc_video_parser.cpp | 82 ++ src/parser/roc_video_parser.h | 130 ++- utils/rocvideodecode/roc_video_dec.cpp | 2 +- 12 files changed, 1966 insertions(+), 345 deletions(-) create mode 100644 src/parser/avc_defines.h create mode 100644 src/parser/avc_parser.cpp create mode 100644 src/parser/avc_parser.h delete mode 100644 src/parser/h264_parser.cpp delete mode 100644 src/parser/h264_parser.h diff --git a/src/parser/avc_defines.h b/src/parser/avc_defines.h new file mode 100644 index 0000000000..43eef3e551 --- /dev/null +++ b/src/parser/avc_defines.h @@ -0,0 +1,334 @@ +/* +Copyright (c) 2023 - 2024 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. +*/ + +#pragma once + +#include + +#define AVC_MAX_SPS_NUM 32 +#define AVC_MAX_PPS_NUM 256 +#define AVC_MAX_SLICE_NUM 256 +#define AVC_MAX_CPB_COUNT 32 +#define AVC_MAX_NUM_SLICE_GROUPS_MINUS 8 +#define AVC_MAX_NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE 256 + +#define AVC_MAX_REF_FRAME_NUM 16 +#define AVC_MAX_REF_PICTURE_NUM 32 +#define AVC_MAX_DPB_FRAMES 16 + +#define AVC_MACRO_BLOCK_SIZE 16 + +// AVC spec. Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes. +enum AvcNalUnitType { + kAvcNalTypeUnspecified = 0, + kAvcNalTypeSlice_Non_IDR = 1, + kAvcNalTypeSlice_Data_Partition_A = 2, + kAvcNalTypeSlice_Data_Partition_B = 3, + kAvcNalTypeSlice_Data_Partition_C = 4, + kAvcNalTypeSlice_IDR = 5, + kAvcNalTypeSEI_Info = 6, + kAvcNalTypeSeq_Parameter_Set = 7, + kAvcNalTypePic_Parameter_Set = 8, + kAvcNalTypeAccess_Unit_Delimiter = 9, + kAvcNalTypeEnd_Of_Seq = 10, + kAvcNalTypeEnd_Of_Stream = 11, + kAvcNalTypeFiller_Data = 12, + kAvcNalTypeSeq_Parameter_Set_Ext = 13, + kAvcNalTypePrefix_NAL_Unit = 14, + kAvcNalTypeSubset_Seq_Parameter_Set = 15, + kAvcNalTypeDepth_Parameter_Set = 16, +}; + +// AVC spec. Table 7-6 – Name association to slice_type. +enum AvcSliceType { + kAvcSliceTypeP = 0, + kAvcSliceTypeB = 1, + kAvcSliceTypeI = 2, + kAvcSliceTypeSP = 3, + kAvcSliceTypeSI = 4, + kAvcSliceTypeP_5 = 5, + kAvcSliceTypeB_6 = 6, + kAvcSliceTypeI_7 = 7, + kAvcSliceTypeSP_8 = 8, + kAvcSliceTypeSI_9 = 9 +}; + +// AVC spec. Annex A.2. +enum AvcProfile { + kAvcBaselineProfile = 66, + kAvcMainProfile = 77, + kAvcExtendedProfile = 88, + kAvcHighProfile = 100, + kAvcHigh10Profile = 110, + kAvcHigh422Profile = 122, + kAvcHigh444Profile = 144 +}; + +// AVC spec. Annex A.3. +enum AvcLevel { + kAvcLevel1 = 10, + kAvcLevel1_1 = 11, + kAvcLevel1_2 = 12, + kAvcLevel1_3 = 13, + kAvcLevel2 = 20, + kAvcLevel2_1 = 21, + kAvcLevel2_2 = 22, + kAvcLevel3 = 30, + kAvcLevel3_1 = 31, + kAvcLevel3_2 = 32, + kAvcLevel4 = 40, + kAvcLevel4_1 = 41, + kAvcLevel4_2 = 42, + kAvcLevel5 = 50, + kAvcLevel5_1 = 51, + kAvcLevel5_2 = 52, + kAvcLevel6 = 60, + kAvcLevel6_1 = 61, + kAvcLevel6_2 = 62 +}; + +// NAL unit header syntax. AVC spec. Section 7.3.1. +typedef struct { + uint32_t forbidden_zero_bit; // f(1) + uint32_t nal_ref_idc; // u(2) + uint32_t nal_unit_type; // u(5) +} AvcNalUnitHeader; + +// HRD parameters syntax. AVC spec. Section E.1.2. +typedef struct { + uint32_t cpb_cnt_minus1; // ue(v) + uint32_t bit_rate_scale; // u(4) + uint32_t cpb_size_scale; // u(4) + uint32_t bit_rate_value_minus1[AVC_MAX_CPB_COUNT]; // ue(v) + uint32_t cpb_size_value_minus1[AVC_MAX_CPB_COUNT]; // ue(v) + uint32_t cbr_flag[AVC_MAX_CPB_COUNT]; // u(1) + uint32_t initial_cpb_removal_delay_length_minus1; // u(5) + uint32_t cpb_removal_delay_length_minus1; // u(5 + uint32_t dpb_output_delay_length_minus1; // u(5) + uint32_t time_offset_length; // u(5) +} AvcHrdParameters; + +// VUI parameters syntax. AVC spec. Section E.1.1. +typedef struct { + uint32_t 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) + uint32_t overscan_info_present_flag; // u(1) + uint32_t overscan_appropriate_flag; // u(1) + uint32_t video_signal_type_present_flag; // u(1) + uint32_t video_format; // u(3) + uint32_t video_full_range_flag; // u(1) + uint32_t colour_description_present_flag; // u(1) + uint32_t colour_primaries; // u(8) + uint32_t transfer_characteristics; // u(8) + uint32_t matrix_coefficients; // u(8) + uint32_t 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) + uint32_t timing_info_present_flag; // u(1) + uint32_t num_units_in_tick; // u(32) + uint32_t time_scale; // u(32) + uint32_t fixed_frame_rate_flag; // u(1) + uint32_t nal_hrd_parameters_present_flag; // u(1) + AvcHrdParameters nal_hrd_parameters; // hrd_paramters() + uint32_t vcl_hrd_parameters_present_flag; // u(1) + AvcHrdParameters vcl_hrd_parameters; // hrd_paramters() + uint32_t low_delay_hrd_flag; // u(1) + uint32_t pic_struct_present_flag; // u(1) + uint32_t bitstream_restriction_flag; // u(1) + uint32_t motion_vectors_over_pic_boundaries_flag; // u(1) + uint32_t max_bytes_per_pic_denom; // ue(v) + uint32_t max_bits_per_mb_denom; // ue(v) + uint32_t log2_max_mv_length_vertical; // ue(v) + uint32_t log2_max_mv_length_horizontal; // ue(v) + uint32_t num_reorder_frames; // ue(v) + uint32_t max_dec_frame_buffering; // ue(v) +} AvcVuiSeqParameters; + +// Sequence parameter set data syntax. AVC spec. 7.3.2.1.1. +typedef struct { + uint32_t is_received; // received with seq_parameter_set_id + uint32_t profile_idc; // u(8) + uint32_t constraint_set0_flag; // u(1) + uint32_t constraint_set1_flag; // u(1) + uint32_t constraint_set2_flag; // u(1) + uint32_t constraint_set3_flag; // u(1) + uint32_t constraint_set4_flag; // u(1) + uint32_t constraint_set5_flag; // u(1) + uint32_t reserved_zero_2bits; // u(2) + uint32_t level_idc; // u(8) + uint32_t seq_parameter_set_id; // ue(v) + uint32_t chroma_format_idc; // ue(v) + uint32_t separate_colour_plane_flag; // u(1) + uint32_t bit_depth_luma_minus8; // ue(v) + uint32_t bit_depth_chroma_minus8; // ue(v) + uint32_t qpprime_y_zero_transform_bypass_flag; // u(1) + uint32_t seq_scaling_matrix_present_flag; // u(1) + uint32_t seq_scaling_list_present_flag[12]; // u(1) + uint32_t scaling_list_4x4[6][16]; // ScalingList4x4 + uint32_t scaling_list_8x8[6][64]; // ScalingList8x8 + uint32_t use_default_scaling_matrix_4x4_flag[6]; // UseDefaultScalingMatrix4x4Flag + uint32_t use_default_scaling_matrix_8x8_flag[6]; // UseDefaultScalingMatrix8x8Flag + uint32_t log2_max_frame_num_minus4; // ue(v) + uint32_t pic_order_cnt_type; // ue(v) + uint32_t log2_max_pic_order_cnt_lsb_minus4; // ue(v) + uint32_t delta_pic_order_always_zero_flag; // u(1) + int32_t offset_for_non_ref_pic; // se(v) + int32_t offset_for_top_to_bottom_field; // se(v) + uint32_t num_ref_frames_in_pic_order_cnt_cycle; // ue(v) + int32_t offset_for_ref_frame[AVC_MAX_NUM_REF_FRAMES_IN_PIC_ORDER_CNT_CYCLE]; // se(v) + uint32_t max_num_ref_frames; // ue(v) + uint32_t gaps_in_frame_num_value_allowed_flag; // u(1) + uint32_t pic_width_in_mbs_minus1; // ue(v) + uint32_t pic_height_in_map_units_minus1; // ue(v) + uint32_t frame_mbs_only_flag; // u(1) + uint32_t mb_adaptive_frame_field_flag; // u(1) + uint32_t direct_8x8_inference_flag; // u(1) + uint32_t frame_cropping_flag; // u(1) + uint32_t frame_crop_left_offset; // ue(v) + uint32_t frame_crop_right_offset; // ue(v) + uint32_t frame_crop_top_offset; // ue(v) + uint32_t frame_crop_bottom_offset; // ue(v) + uint32_t vui_parameters_present_flag; // u(1) + AvcVuiSeqParameters vui_seq_parameters; // vui_parameters() +} AvcSeqParameterSet; + +// Picture parameter set RBSP syntax. AVC Spec. 7.3.2.2. +typedef struct { + uint32_t is_received; // is received with pic_parameter_set_id + uint32_t pic_parameter_set_id; // ue(v) + uint32_t seq_parameter_set_id; // ue(v) + uint32_t entropy_coding_mode_flag; // u(1) + uint32_t bottom_field_pic_order_in_frame_present_flag; // u(1) + uint32_t num_slice_groups_minus1; // ue(v) + uint32_t slice_group_map_type; // ue(v) + uint32_t run_length_minus1[AVC_MAX_NUM_SLICE_GROUPS_MINUS]; // ue(v) + uint32_t top_left[AVC_MAX_NUM_SLICE_GROUPS_MINUS]; // ue(v) + uint32_t bottom_right[AVC_MAX_NUM_SLICE_GROUPS_MINUS]; // ue(v) + uint32_t slice_group_change_direction_flag; // u(1) + uint32_t slice_group_change_rate_minus1; // ue(v) + uint32_t pic_size_in_map_units_minus1; // ue(v) + uint32_t *slice_group_id; // complete MBAmap u(v) + uint32_t num_ref_idx_l0_default_active_minus1; // ue(v) + uint32_t num_ref_idx_l1_default_active_minus1; // ue(v) + uint32_t weighted_pred_flag; // u(1) + uint32_t weighted_bipred_idc; // u(2) + int32_t pic_init_qp_minus26; // se(v) + int32_t pic_init_qs_minus26; // se(v) + int32_t chroma_qp_index_offset; // se(v) + uint32_t deblocking_filter_control_present_flag; // u(1) + uint32_t constrained_intra_pred_flag; // u(1) + uint32_t redundant_pic_cnt_present_flag; // u(1) + uint32_t transform_8x8_mode_flag; // u(1) + uint32_t pic_scaling_matrix_present_flag; // u(1) + uint32_t pic_scaling_list_present_flag[12]; // u(1) + uint32_t scaling_list_4x4[6][16]; // ScalingList4x4 + uint32_t scaling_list_8x8[6][64]; // ScalingList8x8 + uint32_t use_default_scaling_matrix_4x4_flag[6]; // UseDefaultScalingMatrix4x4Flag + uint32_t use_default_scaling_matrix_8x8_flag[6]; // UseDefaultScalingMatrix8x8Flag + int32_t second_chroma_qp_index_offset; // se(v) +} AvcPicParameterSet; + +// Reference picture list modification syntax. AVC spec. 7.3.3.1. +typedef struct { + uint32_t modification_of_pic_nums_idc; // ue(v) + uint32_t abs_diff_pic_num_minus1; // ue(v) + uint32_t long_term_pic_num; // ue(v) +} AvcListMod; + +typedef struct { + uint32_t ref_pic_list_modification_flag_l0; // u(1) + AvcListMod modification_l0[AVC_MAX_REF_PICTURE_NUM]; + uint32_t ref_pic_list_modification_flag_l1; // u(1) + AvcListMod modification_l1[AVC_MAX_REF_PICTURE_NUM]; +} AvcRefPicListMod; + +// Prediction weight table syntax. AVC spec. 7.3.3.2. +typedef struct { + uint32_t luma_weight_l0_flag; // u(1) + int32_t luma_weight_l0; // se(v) + int32_t luma_offset_l0; // se(v) + uint32_t chroma_weight_l0_flag; // u(1) + int32_t chroma_weight_l0[2]; // se(v) + int32_t chroma_offset_l0[2]; // se(v) + uint32_t luma_weight_l1_flag; // u(1) + int32_t luma_weight_l1; // se(v) + int32_t luma_offset_l1; // se(v) + uint32_t chroma_weight_l1_flag; // u(1) + int32_t chroma_weight_l1[2]; // se(v) + int32_t chroma_offset_l1[2]; // se(v) +} AvcWeightFactor; + +typedef struct { + uint32_t luma_log2_weight_denom; // ue(v) + uint32_t chroma_log2_weight_denom; // ue(v) + AvcWeightFactor weight_factor[AVC_MAX_REF_PICTURE_NUM]; +} AvcPredWeightTable; + +// Decoded reference picture marking syntax. AVC spec. 7.3.3.3. +typedef struct { + uint32_t memory_management_control_operation; // ue(v) + uint32_t difference_of_pic_nums_minus1; // ue(v) + uint32_t long_term_pic_num; // ue(v) + uint32_t long_term_frame_idx; // ue(v) + uint32_t max_long_term_frame_idx_plus1; // ue(v) +} AvcMmco; + +typedef struct { + uint32_t no_output_of_prior_pics_flag; // u(1) + uint32_t long_term_reference_flag; // u(1) + uint32_t adaptive_ref_pic_marking_mode_flag; // u(1) + AvcMmco mmco[AVC_MAX_REF_PICTURE_NUM]; + uint32_t mmco_count; +} AvcDecRefPicMarking; + +// Slice header syntax. AVC Spec. 7.3.3. +typedef struct { + uint32_t first_mb_in_slice; // ue(v) + uint32_t slice_type; // ue(v) + uint32_t pic_parameter_set_id; // ue(v) + uint32_t colour_plane_id; // u(2) + uint32_t frame_num; // u(v) + uint32_t field_pic_flag; // u(1) + uint32_t bottom_field_flag; // u(1) + uint32_t idr_pic_id; // ue(v) + uint32_t pic_order_cnt_lsb; // u(v) + int32_t delta_pic_order_cnt_bottom; // se(v) + int32_t delta_pic_order_cnt[2]; // se(v) + uint32_t redundant_pic_cnt; // ue(v) + uint32_t direct_spatial_mv_pred_flag; // u(1) + uint32_t num_ref_idx_active_override_flag; // u(1) + uint32_t num_ref_idx_l0_active_minus1; // ue(v) + uint32_t num_ref_idx_l1_active_minus1; // ue(v) + AvcRefPicListMod ref_pic_list; + AvcPredWeightTable pred_weight_table; + AvcDecRefPicMarking dec_ref_pic_marking; + uint32_t cabac_init_idc; // ue(v) + int32_t slice_qp_delta; // se(v) + uint32_t sp_for_switch_flag; // u(1) + int32_t slice_qs_delta; // se(v) + uint32_t disable_deblocking_filter_idc; // ue(v) + int32_t slice_alpha_c0_offset_div2; // se(v) + int32_t slice_beta_offset_div2; // se(v) + uint32_t slice_group_change_cycle; // u(v) +} AvcSliceHeader; \ No newline at end of file diff --git a/src/parser/avc_parser.cpp b/src/parser/avc_parser.cpp new file mode 100644 index 0000000000..e2f99268e6 --- /dev/null +++ b/src/parser/avc_parser.cpp @@ -0,0 +1,1279 @@ +/* +Copyright (c) 2023 - 2024 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 "avc_parser.h" + +AvcVideoParser::AvcVideoParser() { + prev_has_mmco_5_ = 0; + curr_has_mmco_5_ = 0; + prev_ref_pic_bottom_field_ = 0; + curr_ref_pic_bottom_field_ = 0; +} + +AvcVideoParser::~AvcVideoParser() { +} + +rocDecStatus AvcVideoParser::Initialize(RocdecParserParams *p_params) { + return RocVideoParser::Initialize(p_params); +} + +rocDecStatus AvcVideoParser::UnInitialize() { + //todo:: + return ROCDEC_NOT_IMPLEMENTED; +} + +rocDecStatus AvcVideoParser::ParseVideoData(RocdecSourceDataPacket *p_data) { + if (p_data->payload && p_data->payload_size) { + if (ParsePictureData(p_data->payload, p_data->payload_size) != PARSER_OK) { + ERR(STR("Parser failed!")); + return ROCDEC_RUNTIME_ERROR; + } + + // Init Roc decoder for the first time or reconfigure the existing decoder + /*if (new_sps_activated_) { + if (FillSeqCallbackFn(&pps_list_[active_sps_id_]) != PARSER_OK) { + return ROCDEC_RUNTIME_ERROR; + } + new_sps_activated_ = false; + } + + // Whenever new sei message found + if (pfn_get_sei_message_cb_ && sei_message_count_ > 0) { + FillSeiMessageCallbackFn(); + } + + // Decode the picture + if (SendPicForDecode() != PARSER_OK) { + ERR(STR("Failed to decode!")); + return ROCDEC_RUNTIME_ERROR; + } + + // Output decoded pictures from DPB if any are ready + if (pfn_display_picture_cb_ && dpb_buffer_.num_output_pics > 0) { + if (OutputDecodedPictures() != PARSER_OK) { + return ROCDEC_RUNTIME_ERROR; + } + }*/ + + pic_count_++; + } else if (!(p_data->flags & ROCDEC_PKT_ENDOFSTREAM)) { + // If no payload and EOS is not set, treated as invalid. + return ROCDEC_INVALID_PARAMETER; + } + + /*if (p_data->flags & ROCDEC_PKT_ENDOFSTREAM) { + if (FlushDpb() != PARSER_OK) { + return ROCDEC_RUNTIME_ERROR; + } + }*/ + + return ROCDEC_SUCCESS; +} + +ParserResult AvcVideoParser::ParsePictureData(const uint8_t *p_stream, uint32_t pic_data_size) { + ParserResult ret = PARSER_OK; + + pic_data_buffer_ptr_ = (uint8_t*)p_stream; + pic_data_size_ = pic_data_size; + curr_byte_offset_ = 0; + start_code_num_ = 0; + curr_start_code_offset_ = 0; + next_start_code_offset_ = 0; + + slice_num_ = 0; + sei_message_count_ = 0; + sei_payload_size_ = 0; + + do { + ret = GetNalUnit(); + if (ret == PARSER_NOT_FOUND) { + ERR(STR("Error: no start code found in the frame data.")); + return ret; + } + + // Parse the NAL unit + if (nal_unit_size_) { + // start code + NAL unit header = 4 bytes + int ebsp_size = nal_unit_size_ - 4 > RBSP_BUF_SIZE ? RBSP_BUF_SIZE : nal_unit_size_ - 4; // only copy enough bytes for header parsing + + nal_unit_header_ = ParseNalUnitHeader(pic_data_buffer_ptr_[curr_start_code_offset_ + 3]); + switch (nal_unit_header_.nal_unit_type) { + case kAvcNalTypeSeq_Parameter_Set: { + memcpy(rbsp_buf_, (pic_data_buffer_ptr_ + curr_start_code_offset_ + 4), ebsp_size); + rbsp_size_ = EbspToRbsp(rbsp_buf_, 0, ebsp_size); + ParseSps(rbsp_buf_, rbsp_size_); + break; + } + + case kAvcNalTypePic_Parameter_Set: { + memcpy(rbsp_buf_, (pic_data_buffer_ptr_ + curr_start_code_offset_ + 4), ebsp_size); + rbsp_size_ = EbspToRbsp(rbsp_buf_, 0, ebsp_size); + ParsePps(rbsp_buf_, rbsp_size_); + break; + } + + case kAvcNalTypeSlice_IDR: + case kAvcNalTypeSlice_Non_IDR: + case kAvcNalTypeSlice_Data_Partition_A: + case kAvcNalTypeSlice_Data_Partition_B: + case kAvcNalTypeSlice_Data_Partition_C: { + memcpy(rbsp_buf_, (pic_data_buffer_ptr_ + curr_start_code_offset_ + 4), ebsp_size); + rbsp_size_ = EbspToRbsp(rbsp_buf_, 0, ebsp_size); + // For each picture, only parse the first slice header + if (slice_num_ == 0) { + // Save slice NAL unit header + slice_nal_unit_header_ = nal_unit_header_; + + // Use the data directly from demuxer without copying + pic_stream_data_ptr_ = pic_data_buffer_ptr_ + curr_start_code_offset_; + // Picture stream data size is calculated as the diff between the frame end and the first slice offset. + // This is to consider the possibility of non-slice NAL units between slices. + pic_stream_data_size_ = pic_data_size - curr_start_code_offset_; + + ParseSliceHeader(rbsp_buf_, rbsp_size_, &slice_header_0_); + + // Start decode process + // Todo + } + slice_num_++; + break; + } + + case kAvcNalTypeSEI_Info: { + if (pfn_get_sei_message_cb_) { + // Todo + } + break; + } + + case kAvcNalTypeEnd_Of_Seq: { + break; + } + + case kAvcNalTypeEnd_Of_Stream: { + pic_count_ = 0; + break; + } + + default: + break; + } + } + + // Break if this is the last NAL unit + if (ret == PARSER_EOF) { + break; + } + } while (1); + + return PARSER_OK; +} + +AvcNalUnitHeader AvcVideoParser::ParseNalUnitHeader(uint8_t header_byte) { + size_t bit_offset = 0; + AvcNalUnitHeader nal_header; + + nal_header.forbidden_zero_bit = Parser::GetBit(&header_byte, bit_offset); + nal_header.nal_ref_idc = Parser::ReadBits(&header_byte, bit_offset, 2); + nal_header.nal_unit_type = Parser::ReadBits(&header_byte, bit_offset, 5); + return nal_header; +} + +const int Flat_4x4_16[16] = { + 16,16,16,16, + 16,16,16,16, + 16,16,16,16, + 16,16,16,16 +}; + +const int Flat_8x8_16[64] = { + 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 +}; + +const int Default_4x4_Intra[16] = { + 6, 13, 13, 20, + 20, 20, 28, 28, + 28, 28, 32, 32, + 32, 37, 37, 42 +}; + +const int Default_4x4_Inter[16] = { + 10, 14, 14, 20, + 20, 20, 24, 24, + 24, 24, 27, 27, + 27, 30, 30, 34 +}; + +const int Default_8x8_Intra[64] = { + 6, 10, 10, 13, 11, 13, 16, 16, + 16, 16, 18, 18, 18, 18, 18, 23, + 23, 23, 23, 23, 23, 25, 25, 25, + 25, 25, 25, 25, 27, 27, 27, 27, + 27, 27, 27, 27, 29, 29, 29, 29, + 29, 29, 29, 31, 31, 31, 31, 31, + 31, 33, 33, 33, 33, 33, 36, 36, + 36, 36, 38, 38, 38, 40, 40, 42 +}; + +const int Default_8x8_Inter[64] = { + 9, 13, 13, 15, 13, 15, 17, 17, + 17, 17, 19, 19, 19, 19, 19, 21, + 21, 21, 21, 21, 21, 22, 22, 22, + 22, 22, 22, 22, 24, 24, 24, 24, + 24, 24, 24, 24, 25, 25, 25, 25, + 25, 25, 25, 27, 27, 27, 27, 27, + 27, 28, 28, 28, 28, 28, 30, 30, + 30, 30, 32, 32, 32, 33, 33, 35 +}; + +void AvcVideoParser::ParseSps(uint8_t *p_stream, size_t size) { + size_t offset = 0; // current bit offset + AvcSeqParameterSet *p_sps = nullptr; + + // Parse and temporarily store till set id + uint32_t profile_idc = Parser::ReadBits(p_stream, offset, 8); + uint32_t constraint_set0_flag = Parser::GetBit(p_stream, offset); + uint32_t constraint_set1_flag = Parser::GetBit(p_stream, offset); + uint32_t constraint_set2_flag = Parser::GetBit(p_stream, offset); + uint32_t constraint_set3_flag = Parser::GetBit(p_stream, offset); + uint32_t constraint_set4_flag = Parser::GetBit(p_stream, offset); + uint32_t constraint_set5_flag = Parser::GetBit(p_stream, offset); + uint32_t reserved_zero_2bits = Parser::ReadBits(p_stream, offset, 2); + uint32_t level_idc = Parser::ReadBits(p_stream, offset, 8); + uint32_t seq_parameter_set_id = Parser::ExpGolomb::ReadUe(p_stream, offset); + + p_sps = &sps_list_[seq_parameter_set_id]; + memset(p_sps, 0, sizeof(AvcSeqParameterSet)); + + p_sps->profile_idc = profile_idc; + p_sps->constraint_set0_flag = constraint_set0_flag; + p_sps->constraint_set1_flag = constraint_set1_flag; + p_sps->constraint_set2_flag = constraint_set2_flag; + p_sps->constraint_set3_flag = constraint_set3_flag; + p_sps->constraint_set4_flag = constraint_set4_flag; + p_sps->constraint_set5_flag = constraint_set5_flag; + p_sps->reserved_zero_2bits = reserved_zero_2bits; + p_sps->level_idc = level_idc; + p_sps->seq_parameter_set_id = seq_parameter_set_id; + + if (p_sps->profile_idc == 100 || + p_sps->profile_idc == 110 || + p_sps->profile_idc == 122 || + p_sps->profile_idc == 244 || + p_sps->profile_idc == 44 || + p_sps->profile_idc == 83 || + p_sps->profile_idc == 86 || + p_sps->profile_idc == 118 || + p_sps->profile_idc == 128 || + p_sps->profile_idc == 138 || + p_sps->profile_idc == 139 || + p_sps->profile_idc == 134 || + p_sps->profile_idc == 135) { + p_sps->chroma_format_idc = Parser::ExpGolomb::ReadUe(p_stream, offset); + if (p_sps->chroma_format_idc == 3) { + p_sps->separate_colour_plane_flag = Parser::GetBit(p_stream, offset); + } + + p_sps->bit_depth_luma_minus8 = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_sps->bit_depth_chroma_minus8 = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_sps->qpprime_y_zero_transform_bypass_flag = Parser::GetBit(p_stream, offset); + p_sps->seq_scaling_matrix_present_flag = Parser::GetBit(p_stream, offset); + if (p_sps->seq_scaling_matrix_present_flag == 1) { + for (int i = 0; i < ((p_sps->chroma_format_idc != 3) ? 8 : 12); i++) { + p_sps->seq_scaling_list_present_flag[i] = Parser::GetBit(p_stream, offset); + if (p_sps->seq_scaling_list_present_flag[i] == 1) { + if ( i < 6 ) { + GetScalingList(p_stream, offset, p_sps->scaling_list_4x4[i], 16, &p_sps->use_default_scaling_matrix_4x4_flag[i]); + } else { + GetScalingList(p_stream, offset, p_sps->scaling_list_8x8[i - 6], 64, &p_sps->use_default_scaling_matrix_8x8_flag[i - 6]); + } + } + } + } + } else { + p_sps->chroma_format_idc = 1; + } + + // Setup default scaling list if needed + if (p_sps->seq_scaling_matrix_present_flag == 0) { + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 16; j++) { + p_sps->scaling_list_4x4[i][j] = Flat_4x4_16[j]; + } + } + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 64; j++) { + p_sps->scaling_list_8x8[i][j] = Flat_8x8_16[j]; + } + } + } else { + // 4 x 4 + for (int i = 0; i < 6; i++) { + if (!p_sps->seq_scaling_list_present_flag[i]) { // fall back rule set A + if (i == 0) { + for (int j = 0; j < 16; j++) { + p_sps->scaling_list_4x4[i][j] = Default_4x4_Intra[j]; + } + } else if (i == 3) { + for (int j = 0; j < 16; j++) { + p_sps->scaling_list_4x4[i][j] = Default_4x4_Inter[j]; + } + } else { + for (int j = 0; j < 16; j++) { + p_sps->scaling_list_4x4[i][j] = p_sps->scaling_list_4x4[i - 1][j]; + } + } + } else { + if (p_sps->use_default_scaling_matrix_4x4_flag[i]) { + if (i < 3) { + for (int j = 0; j < 16; j++) { + p_sps->scaling_list_4x4[i][j] = Default_4x4_Intra[j]; + } + } else { + for (int j = 0; j < 16; j++) { + p_sps->scaling_list_4x4[i][j] = Default_4x4_Inter[j]; + } + } + } + } + } + + // 8 x 8 + for (int i = 0; i < 6; i++) { + if(!p_sps->seq_scaling_list_present_flag[i + 6]) { // fall back rule set A + if (i == 0) { + for (int j = 0; j < 64; j++) { + p_sps->scaling_list_8x8[i][j] = Default_8x8_Intra[j]; + } + } else if (i == 1) { + for (int j = 0; j < 64; j++) { + p_sps->scaling_list_8x8[i][j] = Default_8x8_Inter[j]; + } + } else { + for (int j = 0; j < 64; j++) { + p_sps->scaling_list_8x8[i][j] = p_sps->scaling_list_8x8[i - 2][j]; + } + } + } else { + if (p_sps->use_default_scaling_matrix_8x8_flag[i]) { + if (i % 2 == 0) { + for (int j = 0; j < 64; j++) { + p_sps->scaling_list_8x8[i][j] = Default_8x8_Intra[j]; + } + } else { + for (int j = 0; j < 64; j++) { + p_sps->scaling_list_8x8[i][j] = Default_8x8_Inter[j]; + } + } + } + } + } + } + + p_sps->log2_max_frame_num_minus4 = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_sps->pic_order_cnt_type = Parser::ExpGolomb::ReadUe(p_stream, offset); + if (p_sps->pic_order_cnt_type == 0 ) { + p_sps->log2_max_pic_order_cnt_lsb_minus4 = Parser::ExpGolomb::ReadUe(p_stream, offset); + //MaxPicOrderCntLsb = pow(2, p_sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + } else if (p_sps->pic_order_cnt_type == 1) { + p_sps->delta_pic_order_always_zero_flag = Parser::GetBit(p_stream, offset); + p_sps->offset_for_non_ref_pic = Parser::ExpGolomb::ReadSe(p_stream, offset); + p_sps->offset_for_top_to_bottom_field = Parser::ExpGolomb::ReadSe(p_stream, offset); + p_sps->num_ref_frames_in_pic_order_cnt_cycle = Parser::ExpGolomb::ReadUe(p_stream, offset); + for (int i = 0; i < p_sps->num_ref_frames_in_pic_order_cnt_cycle; i++) { + p_sps->offset_for_ref_frame[i] = Parser::ExpGolomb::ReadSe(p_stream, offset); + } + } + + p_sps->max_num_ref_frames = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_sps->gaps_in_frame_num_value_allowed_flag = Parser::GetBit(p_stream, offset); + p_sps->pic_width_in_mbs_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_sps->pic_height_in_map_units_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_sps->frame_mbs_only_flag = Parser::GetBit(p_stream, offset); + if (!p_sps->frame_mbs_only_flag) { + p_sps->mb_adaptive_frame_field_flag = Parser::GetBit(p_stream, offset); + } + + p_sps->direct_8x8_inference_flag = Parser::GetBit(p_stream, offset); + p_sps->frame_cropping_flag = Parser::GetBit(p_stream, offset); + if (p_sps->frame_cropping_flag) { + p_sps->frame_crop_left_offset = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_sps->frame_crop_right_offset = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_sps->frame_crop_top_offset = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_sps->frame_crop_bottom_offset = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + + p_sps->vui_parameters_present_flag = Parser::GetBit(p_stream, offset); + if (p_sps->vui_parameters_present_flag == 1) { + GetVuiParameters(p_stream, offset, &p_sps->vui_seq_parameters); + } + + p_sps->is_received = 1; // confirm SPS with seq_parameter_set_id received (but not activated) + +#if DBGINFO + PrintSps(p_sps); +#endif // DBGINFO +} + +void AvcVideoParser::ParsePps(uint8_t *p_stream, size_t stream_size_in_byte) { + AvcSeqParameterSet *p_sps = nullptr; + AvcPicParameterSet *p_pps = nullptr; + size_t offset = 0; // current bit offset + + // Parse and temporarily store + uint32_t pic_parameter_set_id = Parser::ExpGolomb::ReadUe(p_stream, offset); + uint32_t seq_parameter_set_id = Parser::ExpGolomb::ReadUe(p_stream, offset); + + p_sps = &sps_list_[seq_parameter_set_id]; + p_pps = &pps_list_[pic_parameter_set_id]; + memset(p_pps, 0, sizeof(AvcPicParameterSet)); + + p_pps->pic_parameter_set_id = pic_parameter_set_id; + p_pps->seq_parameter_set_id = seq_parameter_set_id; + + p_pps->entropy_coding_mode_flag = Parser::GetBit(p_stream, offset); + p_pps->bottom_field_pic_order_in_frame_present_flag = Parser::GetBit(p_stream, offset); + + p_pps->num_slice_groups_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + if (p_pps->num_slice_groups_minus1 > 0) { + p_pps->slice_group_map_type = Parser::ExpGolomb::ReadUe(p_stream, offset); + if (p_pps->slice_group_map_type == 0) { + for (int i_group = 0; i_group <= p_pps->num_slice_groups_minus1; i_group++) { + p_pps->run_length_minus1[i_group] = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + } else if (p_pps->slice_group_map_type == 2) { + for (int i_group = 0; i_group < p_pps->num_slice_groups_minus1; i_group++ ) { + p_pps->top_left[i_group] = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_pps->bottom_right[i_group] = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + } else if (p_pps->slice_group_map_type == 3 || p_pps->slice_group_map_type == 4 || p_pps->slice_group_map_type == 5) { + p_pps->slice_group_change_direction_flag = Parser::GetBit(p_stream, offset); + p_pps->slice_group_change_rate_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + } else if (p_pps->slice_group_map_type == 6) { + p_pps->pic_size_in_map_units_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + int slice_group_id_size = ceil(log2(p_pps->num_slice_groups_minus1 + 1)); + for (int i = 0; i <= p_pps->pic_size_in_map_units_minus1; i++) { + //p_pps->slice_group_id[i] = Parser::ReadBits(p_stream, offset, slice_group_id_size); + int temp = Parser::ReadBits(p_stream, offset, slice_group_id_size); + ERR("AVC PPS parsing: slice_group_id memory not allocaed!"); + } + } + } + + p_pps->num_ref_idx_l0_default_active_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_pps->num_ref_idx_l1_default_active_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_pps->weighted_pred_flag = Parser::GetBit(p_stream, offset); + p_pps->weighted_bipred_idc = Parser::ReadBits(p_stream, offset, 2); + p_pps->pic_init_qp_minus26 = Parser::ExpGolomb::ReadSe(p_stream, offset); + p_pps->pic_init_qs_minus26 = Parser::ExpGolomb::ReadSe(p_stream, offset); + p_pps->chroma_qp_index_offset = Parser::ExpGolomb::ReadSe(p_stream, offset); + p_pps->deblocking_filter_control_present_flag = Parser::GetBit(p_stream, offset); + p_pps->constrained_intra_pred_flag = Parser::GetBit(p_stream, offset); + p_pps->redundant_pic_cnt_present_flag = Parser::GetBit(p_stream, offset); + + if (MoreRbspData(p_stream, stream_size_in_byte, offset)) { + p_pps->transform_8x8_mode_flag = Parser::GetBit(p_stream, offset); + p_pps->pic_scaling_matrix_present_flag = Parser::GetBit(p_stream, offset); + if (p_pps->pic_scaling_matrix_present_flag == 1) { + int count = p_sps->chroma_format_idc != 3 ? 2 : 6; + for (int i = 0; i < 6 + count * p_pps->transform_8x8_mode_flag; i++) { + p_pps->pic_scaling_list_present_flag [i] = Parser::GetBit(p_stream, offset); + if (p_pps->pic_scaling_list_present_flag[i] == 1) { + if ( i < 6 ) { + GetScalingList(p_stream, offset, p_pps->scaling_list_4x4[i], 16, &p_pps->use_default_scaling_matrix_4x4_flag[i]); + } else { + GetScalingList(p_stream, offset, p_pps->scaling_list_8x8[i - 6], 64, &p_pps->use_default_scaling_matrix_8x8_flag[i - 6]); + } + } + } + } + p_pps->second_chroma_qp_index_offset = Parser::ExpGolomb::ReadSe(p_stream, offset); + } else { + /// When second_chroma_qp_index_offset is not present, it shall be inferred to be equal to chroma_qp_index_offset. + p_pps->second_chroma_qp_index_offset = p_pps->chroma_qp_index_offset; + } + + // Setup default scaling list if needed + if (p_pps->pic_scaling_matrix_present_flag == 0) { + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 16; j++) { + p_pps->scaling_list_4x4[i][j] = p_sps->scaling_list_4x4[i][j]; + } + } + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 64; j++) { + p_pps->scaling_list_8x8[i][j] = p_sps->scaling_list_8x8[i][j]; + } + } + } else { + // 4 x 4 + for (int i = 0; i < 6; i++) { + if (p_pps->pic_scaling_list_present_flag[i] == 0) { + if (i == 0) { + if ( p_sps->seq_scaling_matrix_present_flag == 0) { // fall back rule set A + for (int j = 0; j < 16; j++) { + p_pps->scaling_list_4x4[i][j] = Default_4x4_Intra[j]; + } + } else { // fall back rule set B + for (int j = 0; j < 16; j++) { + p_pps->scaling_list_4x4[i][j] = p_sps->scaling_list_4x4[i][j]; + } + } + } else if (i == 3) { + if (p_sps->seq_scaling_matrix_present_flag == 0) { // fall back rule set A + for (int j = 0; j < 16; j++) { + p_pps->scaling_list_4x4[i][j] = Default_4x4_Inter[j]; + } + } else { // fall back rule set B + for (int j = 0; j < 16; j++) { + p_pps->scaling_list_4x4[i][j] = p_sps->scaling_list_4x4[i][j]; + } + } + } else { + for (int j = 0; j < 16; j++) { + p_pps->scaling_list_4x4[i][j] = p_pps->scaling_list_4x4[i - 1][j]; + } + } + } else { + if (p_pps->use_default_scaling_matrix_4x4_flag[i]) { + if( i < 3 ) { + for (int j = 0; j < 16; j++) { + p_pps->scaling_list_4x4[i][j] = Default_4x4_Intra[j]; + } + } else { + for (int j = 0; j < 16; j++) { + p_pps->scaling_list_4x4[i][j] = Default_4x4_Inter[j]; + } + } + } + } + } + + // 8 x 8 + for (int i = 0; i < 6; i++) { + if (p_pps->pic_scaling_list_present_flag[i + 6] == 0) { + if (i == 0) { + if ( p_sps->seq_scaling_matrix_present_flag == 0) { // fall back rule set A + for (int j = 0; j < 64; j++) { + p_pps->scaling_list_8x8[i][j] = Default_8x8_Intra[j]; + } + } else { // fall back rule set B + for (int j = 0; j < 64; j++) { + p_pps->scaling_list_8x8[i][j] = p_sps->scaling_list_8x8[i][j]; + } + } + } else if (i == 1) { + if ( p_sps->seq_scaling_matrix_present_flag == 0) { // fall back rule set A + for (int j = 0; j < 64; j++) { + p_pps->scaling_list_8x8[i][j] = Default_8x8_Inter[j]; + } + } else { // fall back rule set B + for (int j = 0; j < 64; j++) { + p_pps->scaling_list_8x8[i][j] = p_sps->scaling_list_8x8[i][j]; + } + } + } else { + for (int j = 0; j < 64; j++) { + p_pps->scaling_list_8x8[i][j] = p_pps->scaling_list_8x8[i - 2][j]; + } + } + } else { + if (p_pps->use_default_scaling_matrix_8x8_flag[i]) { + if ( i % 2 == 0) { + for (int j = 0; j < 64; j++) { + p_pps->scaling_list_8x8[i][j] = Default_8x8_Intra[j]; + } + } else { + for (int j = 0; j < 64; j++) { + p_pps->scaling_list_8x8[i][j] = Default_8x8_Inter[j]; + } + } + } + } + } + } + + p_pps->is_received = 1; // confirm PPS with pic_parameter_set_id received (but not activated) + +#if DBGINFO + PrintPps(p_pps); +#endif // DBGINFO +} + +ParserResult AvcVideoParser::ParseSliceHeader(uint8_t *p_stream, size_t stream_size_in_byte, AvcSliceHeader *p_slice_header) { + int i; + size_t offset = 0; // current bit offset + AvcSeqParameterSet *p_sps = nullptr; + AvcPicParameterSet *p_pps = nullptr; + + curr_has_mmco_5_ = 0; + memset(p_slice_header, 0, sizeof(AvcSliceHeader)); + + p_slice_header->first_mb_in_slice = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_slice_header->slice_type = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_slice_header->pic_parameter_set_id = Parser::ExpGolomb::ReadUe(p_stream, offset); + + // 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 (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_]; + // Re-set DPB size. + dpb_buffer_.dpb_size = p_sps->max_num_ref_frames + 1; + dpb_buffer_.dpb_size = dpb_buffer_.dpb_size > AVC_MAX_DPB_FRAMES ? AVC_MAX_DPB_FRAMES : dpb_buffer_.dpb_size; + new_sps_activated_ = true; // Note: clear this flag after the actions are taken. + } + p_sps = &sps_list_[active_sps_id_]; + + // Check video dimension change + uint32_t curr_pic_width = (p_sps->pic_width_in_mbs_minus1 + 1) * AVC_MACRO_BLOCK_SIZE; + uint32_t curr_pic_height = (2 - p_sps->frame_mbs_only_flag) * (p_sps->pic_height_in_map_units_minus1 + 1) * AVC_MACRO_BLOCK_SIZE; + if ( pic_width_ != curr_pic_width || pic_height_ != curr_pic_height) { + pic_width_ = curr_pic_width; + pic_height_ = curr_pic_height; + // Take care of the case where a new SPS replaces the old SPS with the same id but with different dimensions + // Re-set DPB size. + dpb_buffer_.dpb_size = p_sps->max_num_ref_frames + 1; + dpb_buffer_.dpb_size = dpb_buffer_.dpb_size > AVC_MAX_DPB_FRAMES ? AVC_MAX_DPB_FRAMES : dpb_buffer_.dpb_size; + new_sps_activated_ = true; // Note: clear this flag after the actions are taken. + } + + if (p_sps->separate_colour_plane_flag == 1) { + p_slice_header->colour_plane_id = Parser::ReadBits(p_stream, offset, 2); + } + p_slice_header->frame_num = Parser::ReadBits(p_stream, offset, p_sps->log2_max_frame_num_minus4 + 4); + + if (p_sps->frame_mbs_only_flag != 1) { + p_slice_header->field_pic_flag = Parser::GetBit(p_stream, offset); + if (p_slice_header->field_pic_flag == 1) + { + p_slice_header->bottom_field_flag = Parser::GetBit(p_stream, offset); + } + } else { + p_slice_header->field_pic_flag = 0; + p_slice_header->bottom_field_flag = 0; + } + + if ( nal_unit_header_.nal_ref_idc ) { + curr_ref_pic_bottom_field_ = p_slice_header->bottom_field_flag; + } + + if (nal_unit_header_.nal_unit_type == kAvcNalTypeSlice_IDR) { + p_slice_header->idr_pic_id = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + + if (p_sps->pic_order_cnt_type == 0) { + p_slice_header->pic_order_cnt_lsb = Parser::ReadBits(p_stream, offset, p_sps->log2_max_pic_order_cnt_lsb_minus4 + 4); + if (p_pps->bottom_field_pic_order_in_frame_present_flag == 1 && p_slice_header->field_pic_flag != 1 ) { + p_slice_header->delta_pic_order_cnt_bottom = Parser::ExpGolomb::ReadSe(p_stream, offset); + } + } + + if (p_sps->pic_order_cnt_type == 1 && p_sps->delta_pic_order_always_zero_flag != 1) { + p_slice_header->delta_pic_order_cnt[0] = Parser::ExpGolomb::ReadSe(p_stream, offset); + if (p_pps->bottom_field_pic_order_in_frame_present_flag == 1 && p_slice_header->field_pic_flag != 1) { + p_slice_header->delta_pic_order_cnt[1] = Parser::ExpGolomb::ReadSe(p_stream, offset); + } + } + + if (p_pps->redundant_pic_cnt_present_flag == 1) { + p_slice_header->redundant_pic_cnt = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + + if (p_slice_header->slice_type == kAvcSliceTypeB || p_slice_header->slice_type == kAvcSliceTypeB_6 ) { // B-Slice + p_slice_header->direct_spatial_mv_pred_flag = Parser::GetBit(p_stream, offset); + } + + if (p_slice_header->slice_type == kAvcSliceTypeP || p_slice_header->slice_type == kAvcSliceTypeP_5 || + p_slice_header->slice_type == kAvcSliceTypeSP || p_slice_header->slice_type == kAvcSliceTypeSP_8 || + p_slice_header->slice_type == kAvcSliceTypeB || p_slice_header->slice_type == kAvcSliceTypeB_6) { + p_slice_header->num_ref_idx_active_override_flag = Parser::GetBit(p_stream, offset); + if (p_slice_header->num_ref_idx_active_override_flag == 1) { + p_slice_header->num_ref_idx_l0_active_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + if (p_slice_header->slice_type == kAvcSliceTypeB || p_slice_header->slice_type == kAvcSliceTypeB_6) { + p_slice_header->num_ref_idx_l1_active_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + } else { + p_slice_header->num_ref_idx_l0_active_minus1 = p_pps->num_ref_idx_l0_default_active_minus1; + p_slice_header->num_ref_idx_l1_active_minus1 = p_pps->num_ref_idx_l1_default_active_minus1; + } + } + + // Bail out for NAL unit type 20/21 + if ( nal_unit_header_.nal_unit_type == 21 || nal_unit_header_.nal_unit_type == 21) { + return PARSER_NOT_SUPPORTED; + } + + // Ref picture list modification + int modification_of_pic_nums_idc; + if (p_slice_header->slice_type != kAvcSliceTypeI && p_slice_header->slice_type != kAvcSliceTypeSI && + p_slice_header->slice_type != kAvcSliceTypeI_7 && p_slice_header->slice_type != kAvcSliceTypeSI_9) { + p_slice_header->ref_pic_list.ref_pic_list_modification_flag_l0 = Parser::GetBit(p_stream, offset); + if (p_slice_header->ref_pic_list.ref_pic_list_modification_flag_l0 == 1) { + i = 0; + do { + modification_of_pic_nums_idc = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_slice_header->ref_pic_list.modification_l0[i].modification_of_pic_nums_idc = modification_of_pic_nums_idc; + if (modification_of_pic_nums_idc == 0 || modification_of_pic_nums_idc == 1) { + p_slice_header->ref_pic_list.modification_l0[i].abs_diff_pic_num_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + } else if (modification_of_pic_nums_idc == 2) { + p_slice_header->ref_pic_list.modification_l0[i].long_term_pic_num = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + i++; + } while (modification_of_pic_nums_idc != 3); + } + } + + if (p_slice_header->slice_type == kAvcSliceTypeB || p_slice_header->slice_type == kAvcSliceTypeB_6) { + p_slice_header->ref_pic_list.ref_pic_list_modification_flag_l1 = Parser::GetBit(p_stream, offset); + if (p_slice_header->ref_pic_list.ref_pic_list_modification_flag_l1 == 1) { + i = 0; + do { + modification_of_pic_nums_idc = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_slice_header->ref_pic_list.modification_l1[i].modification_of_pic_nums_idc = modification_of_pic_nums_idc; + if (modification_of_pic_nums_idc == 0 || modification_of_pic_nums_idc == 1) { + p_slice_header->ref_pic_list.modification_l1[i].abs_diff_pic_num_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + } else if(modification_of_pic_nums_idc == 2) { + p_slice_header->ref_pic_list.modification_l1[i].long_term_pic_num = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + i++; + } while (modification_of_pic_nums_idc != 3); + } + } + + // Prediction weight table + if ((p_pps->weighted_pred_flag == 1 && + ((p_slice_header->slice_type == kAvcSliceTypeP || p_slice_header->slice_type == kAvcSliceTypeP_5) || + (p_slice_header->slice_type == kAvcSliceTypeSP || p_slice_header->slice_type == kAvcSliceTypeSP_8))) || + (p_pps->weighted_bipred_idc == 1 && + (p_slice_header->slice_type == kAvcSliceTypeB || p_slice_header->slice_type == kAvcSliceTypeB_6))) { + p_slice_header->pred_weight_table.luma_log2_weight_denom = Parser::ExpGolomb::ReadUe(p_stream, offset); + + int ChromaArrayType = p_sps->separate_colour_plane_flag == 0 ? p_sps->chroma_format_idc : 0; + if (ChromaArrayType != 0) { + p_slice_header->pred_weight_table.chroma_log2_weight_denom = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + + for (i = 0; i <= p_slice_header->num_ref_idx_l0_active_minus1; i++) { + p_slice_header->pred_weight_table.weight_factor[i].luma_weight_l0_flag = Parser::GetBit(p_stream, offset); + if (p_slice_header->pred_weight_table.weight_factor[i].luma_weight_l0_flag == 1) { + p_slice_header->pred_weight_table.weight_factor[i].luma_weight_l0 = Parser::ExpGolomb::ReadSe(p_stream, offset); + p_slice_header->pred_weight_table.weight_factor[i].luma_offset_l0 = Parser::ExpGolomb::ReadSe(p_stream, offset); + } else { + p_slice_header->pred_weight_table.weight_factor[i].luma_weight_l0 = 1 << p_slice_header->pred_weight_table.luma_log2_weight_denom; + p_slice_header->pred_weight_table.weight_factor[i].luma_offset_l0 = 0; + } + + if (ChromaArrayType != 0) { + p_slice_header->pred_weight_table.weight_factor[i].chroma_weight_l0_flag = Parser::GetBit(p_stream, offset); + if (p_slice_header->pred_weight_table.weight_factor[i].chroma_weight_l0_flag == 1) { + for (int j = 0; j < 2; j++) { + p_slice_header->pred_weight_table.weight_factor[i].chroma_weight_l0[j] = Parser::ExpGolomb::ReadSe(p_stream, offset); + p_slice_header->pred_weight_table.weight_factor[i].chroma_offset_l0[j] = Parser::ExpGolomb::ReadSe(p_stream, offset); + } + } else { + for (int j = 0; j < 2; j++) { + p_slice_header->pred_weight_table.weight_factor[i].chroma_weight_l0[j] = 1 << p_slice_header->pred_weight_table.chroma_log2_weight_denom; + p_slice_header->pred_weight_table.weight_factor[i].chroma_offset_l0[j] = 0; + } + } + } + } + + if (p_slice_header->slice_type == kAvcSliceTypeB || p_slice_header->slice_type == kAvcSliceTypeB_6) { + for (int i = 0; i <= p_slice_header->num_ref_idx_l1_active_minus1; i++) { + p_slice_header->pred_weight_table.weight_factor[i].luma_weight_l1_flag = Parser::GetBit(p_stream, offset); + if (p_slice_header->pred_weight_table.weight_factor[i].luma_weight_l1_flag == 1) { + p_slice_header->pred_weight_table.weight_factor[i].luma_weight_l1 = Parser::ExpGolomb::ReadSe(p_stream, offset); + p_slice_header->pred_weight_table.weight_factor[i].luma_offset_l1 = Parser::ExpGolomb::ReadSe(p_stream, offset); + } else { + p_slice_header->pred_weight_table.weight_factor[i].luma_weight_l1 = 1 << p_slice_header->pred_weight_table.luma_log2_weight_denom; + p_slice_header->pred_weight_table.weight_factor[i].luma_offset_l1 = 0; + } + + if (ChromaArrayType != 0 ) { + p_slice_header->pred_weight_table.weight_factor[i].chroma_weight_l1_flag = Parser::GetBit(p_stream, offset); + if (p_slice_header->pred_weight_table.weight_factor[i].chroma_weight_l1_flag == 1) { + for (int j = 0; j < 2; j++) { + p_slice_header->pred_weight_table.weight_factor[i].chroma_weight_l1[j] = Parser::ExpGolomb::ReadSe(p_stream, offset); + p_slice_header->pred_weight_table.weight_factor[i].chroma_offset_l1[j] = Parser::ExpGolomb::ReadSe(p_stream, offset); + } + } else { + for (int j = 0; j < 2; j++) { + p_slice_header->pred_weight_table.weight_factor[i].chroma_weight_l1[j] = 1 << p_slice_header->pred_weight_table.chroma_log2_weight_denom; + p_slice_header->pred_weight_table.weight_factor[i].chroma_offset_l1[j] = 0; + } + } + } + } + } + } + + // Decoded reference picture marking. + int memory_management_control_operation; + if (nal_unit_header_.nal_ref_idc != 0) { + if (nal_unit_header_.nal_unit_type == kAvcNalTypeSlice_IDR) { + p_slice_header->dec_ref_pic_marking.no_output_of_prior_pics_flag = Parser::GetBit(p_stream, offset); + p_slice_header->dec_ref_pic_marking.long_term_reference_flag = Parser::GetBit(p_stream, offset); + } else { + p_slice_header->dec_ref_pic_marking.adaptive_ref_pic_marking_mode_flag = Parser::GetBit(p_stream, offset); + if (p_slice_header->dec_ref_pic_marking.adaptive_ref_pic_marking_mode_flag == 1) { + i = 0; + do { + memory_management_control_operation = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_slice_header->dec_ref_pic_marking.mmco[i].memory_management_control_operation = memory_management_control_operation; + + if (memory_management_control_operation == 1 || memory_management_control_operation == 3) { + p_slice_header->dec_ref_pic_marking.mmco[i].difference_of_pic_nums_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + if (memory_management_control_operation == 2) { + p_slice_header->dec_ref_pic_marking.mmco[i].long_term_pic_num = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + if (memory_management_control_operation == 3 || memory_management_control_operation == 6) { + p_slice_header->dec_ref_pic_marking.mmco[i].long_term_frame_idx = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + if (memory_management_control_operation == 4) { + p_slice_header->dec_ref_pic_marking.mmco[i].max_long_term_frame_idx_plus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + if ( memory_management_control_operation == 5) { + curr_has_mmco_5_ = 1; + } + i++; + } while (memory_management_control_operation != 0); + p_slice_header->dec_ref_pic_marking.mmco_count = i - 1; + } + } + } + + if (p_pps->entropy_coding_mode_flag == 1 && + p_slice_header->slice_type != kAvcSliceTypeI && p_slice_header->slice_type != kAvcSliceTypeSI && + p_slice_header->slice_type != kAvcSliceTypeI_7 && p_slice_header->slice_type != kAvcSliceTypeSI_9) { + p_slice_header->cabac_init_idc = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + p_slice_header->slice_qp_delta = Parser::ExpGolomb::ReadSe(p_stream, offset); + if (p_slice_header->slice_type == kAvcSliceTypeSP || p_slice_header->slice_type == kAvcSliceTypeSI || + p_slice_header->slice_type == kAvcSliceTypeSP_8 || p_slice_header->slice_type == kAvcSliceTypeSI_9) { + if (p_slice_header->slice_type == kAvcSliceTypeSP || p_slice_header->slice_type == kAvcSliceTypeSP_8) { + p_slice_header->sp_for_switch_flag = Parser::GetBit(p_stream, offset); + } + p_slice_header->slice_qs_delta = Parser::ExpGolomb::ReadSe(p_stream, offset); + } + + if (p_pps->deblocking_filter_control_present_flag == 1) { + p_slice_header->disable_deblocking_filter_idc = Parser::ExpGolomb::ReadUe(p_stream, offset); + if (p_slice_header->disable_deblocking_filter_idc != 1) { + p_slice_header->slice_alpha_c0_offset_div2 = Parser::ExpGolomb::ReadSe(p_stream, offset); + p_slice_header->slice_beta_offset_div2 = Parser::ExpGolomb::ReadSe(p_stream, offset); + } + } + if (p_pps->num_slice_groups_minus1 > 0 && p_pps->slice_group_map_type >= 3 && p_pps->slice_group_map_type <= 5) { + int size = ceil(log2((double)(p_sps->pic_height_in_map_units_minus1+1) / (double)(p_pps->slice_group_change_rate_minus1+1) + 1)); + p_slice_header->slice_group_change_cycle = Parser::ReadBits(p_stream, offset, size); + } + +#if DBGINFO + PrintSliceHeader(p_slice_header); +#endif // DBGINFO + + return PARSER_OK; +} + +void AvcVideoParser::GetScalingList(uint8_t *p_stream, size_t &offset, uint32_t *scaling_list, uint32_t list_size, uint32_t *use_default_scaling_matrix_flag) { + int32_t last_scale, next_scale, delta_scale; + + last_scale = 8; + next_scale = 8; + for (int j = 0; j < list_size; j++) { + if (next_scale != 0) { + delta_scale = Parser::ExpGolomb::ReadSe(p_stream, offset); + next_scale = (last_scale + delta_scale + 256) % 256; + *use_default_scaling_matrix_flag = (j == 0 && next_scale == 0); + } + + scaling_list[j] = (next_scale == 0) ? last_scale : next_scale; + last_scale = scaling_list[j]; + } +} + +void AvcVideoParser::GetVuiParameters(uint8_t *p_stream, size_t &offset, AvcVuiSeqParameters *p_vui_params) { + p_vui_params->aspect_ratio_info_present_flag = Parser::GetBit(p_stream, offset); + if (p_vui_params->aspect_ratio_info_present_flag == 1) { + p_vui_params->aspect_ratio_idc = Parser::ReadBits(p_stream, offset, 8); + if (p_vui_params->aspect_ratio_idc == 255 /*Extended_SAR*/) { + p_vui_params->sar_width = Parser::ReadBits(p_stream, offset, 16); + p_vui_params->sar_height = Parser::ReadBits(p_stream, offset, 16); + } + } + + p_vui_params->overscan_info_present_flag = Parser::GetBit(p_stream, offset); + if (p_vui_params->overscan_info_present_flag == 1) { + p_vui_params->overscan_appropriate_flag = Parser::GetBit(p_stream, offset); + } + + p_vui_params->video_signal_type_present_flag = Parser::GetBit(p_stream, offset); + if (p_vui_params->video_signal_type_present_flag == 1) { + p_vui_params->video_format = Parser::ReadBits(p_stream, offset, 3); + p_vui_params->video_full_range_flag = Parser::GetBit(p_stream, offset); + p_vui_params->colour_description_present_flag = Parser::GetBit(p_stream, offset); + if (p_vui_params->colour_description_present_flag == 1) { + p_vui_params->colour_primaries = Parser::ReadBits(p_stream, offset, 8); + p_vui_params->transfer_characteristics = Parser::ReadBits(p_stream, offset, 8); + p_vui_params->matrix_coefficients = Parser::ReadBits(p_stream, offset, 8); + } + } + + p_vui_params->chroma_loc_info_present_flag = Parser::GetBit(p_stream, offset); + if (p_vui_params->chroma_loc_info_present_flag == 1) { + p_vui_params->chroma_sample_loc_type_top_field = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->chroma_sample_loc_type_bottom_field = Parser::ExpGolomb::ReadUe(p_stream, offset); + } + + p_vui_params->timing_info_present_flag = Parser::GetBit(p_stream, offset); + if (p_vui_params->timing_info_present_flag == 1) { + p_vui_params->num_units_in_tick = Parser::ReadBits(p_stream, offset, 32); + p_vui_params->time_scale = Parser::ReadBits(p_stream, offset, 32); + p_vui_params->fixed_frame_rate_flag = Parser::GetBit(p_stream, offset); + } + + p_vui_params->nal_hrd_parameters_present_flag = Parser::GetBit(p_stream, offset); + if (p_vui_params->nal_hrd_parameters_present_flag == 1 ) { + p_vui_params->nal_hrd_parameters.cpb_cnt_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->nal_hrd_parameters.bit_rate_scale = Parser::ReadBits(p_stream, offset, 4); + p_vui_params->nal_hrd_parameters.cpb_size_scale = Parser::ReadBits(p_stream, offset, 4); + for (int SchedSelIdx = 0; SchedSelIdx <= p_vui_params->nal_hrd_parameters.cpb_cnt_minus1; SchedSelIdx ++) { + p_vui_params->nal_hrd_parameters.bit_rate_value_minus1[SchedSelIdx] = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->nal_hrd_parameters.cpb_size_value_minus1[SchedSelIdx] = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->nal_hrd_parameters.cbr_flag[SchedSelIdx] = Parser::ReadBits(p_stream, offset, 1); + } + p_vui_params->nal_hrd_parameters.initial_cpb_removal_delay_length_minus1 = Parser::ReadBits(p_stream, offset, 5); + p_vui_params->nal_hrd_parameters.cpb_removal_delay_length_minus1 = Parser::ReadBits(p_stream, offset, 5); + p_vui_params->nal_hrd_parameters.dpb_output_delay_length_minus1 = Parser::ReadBits(p_stream, offset, 5); + p_vui_params->nal_hrd_parameters.time_offset_length = Parser::ReadBits(p_stream, offset, 5); + } + + p_vui_params->vcl_hrd_parameters_present_flag = Parser::GetBit(p_stream, offset); + if (p_vui_params->vcl_hrd_parameters_present_flag == 1) { + p_vui_params->vcl_hrd_parameters.cpb_cnt_minus1 = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->vcl_hrd_parameters.bit_rate_scale = Parser::ReadBits(p_stream, offset, 4); + p_vui_params->vcl_hrd_parameters.cpb_size_scale = Parser::ReadBits(p_stream, offset, 4); + for (int SchedSelIdx = 0; SchedSelIdx <= p_vui_params->vcl_hrd_parameters.cpb_cnt_minus1; SchedSelIdx ++) { + p_vui_params->vcl_hrd_parameters.bit_rate_value_minus1[SchedSelIdx] = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->vcl_hrd_parameters.cpb_size_value_minus1[SchedSelIdx] = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->vcl_hrd_parameters.cbr_flag[SchedSelIdx] = Parser::GetBit(p_stream, offset); + } + p_vui_params->vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 = Parser::ReadBits(p_stream, offset, 5); + p_vui_params->vcl_hrd_parameters.cpb_removal_delay_length_minus1 = Parser::ReadBits(p_stream, offset, 5); + p_vui_params->vcl_hrd_parameters.dpb_output_delay_length_minus1 = Parser::ReadBits(p_stream, offset, 5); + p_vui_params->vcl_hrd_parameters.time_offset_length = Parser::ReadBits(p_stream, offset, 5); + } + if (p_vui_params->nal_hrd_parameters_present_flag == 1 || p_vui_params->vcl_hrd_parameters_present_flag == 1) { + p_vui_params->low_delay_hrd_flag = Parser::GetBit(p_stream, offset); + } + + p_vui_params->pic_struct_present_flag = Parser::GetBit(p_stream, offset); + p_vui_params->bitstream_restriction_flag = Parser::GetBit(p_stream, offset); + if (p_vui_params->bitstream_restriction_flag) { + p_vui_params->motion_vectors_over_pic_boundaries_flag = Parser::GetBit(p_stream, offset); + p_vui_params->max_bytes_per_pic_denom = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->max_bits_per_mb_denom = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->log2_max_mv_length_horizontal = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->log2_max_mv_length_vertical = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->num_reorder_frames = Parser::ExpGolomb::ReadUe(p_stream, offset); + p_vui_params->max_dec_frame_buffering = Parser::ExpGolomb::ReadUe(p_stream, offset); + } +} + +bool AvcVideoParser::MoreRbspData(uint8_t *p_stream, size_t stream_size_in_byte, size_t bit_offset) { + bool more_rbsp_bits = false; + uint8_t curr_byte = p_stream[bit_offset >> 3]; + uint8_t next_bytes[3]; + uint32_t next_byte_offset = (bit_offset + 7) >> 3; + int bit_offset_in_byte = bit_offset % 8; + + /// If the following bytes are not start code, we have more RBSP data. If we don't have enough bytes + /// in the stream, pad with 0. + next_bytes[0] = next_byte_offset < stream_size_in_byte ? p_stream[next_byte_offset] : 0; + next_bytes[1] = (next_byte_offset + 1) < stream_size_in_byte ? p_stream[next_byte_offset + 1] : 0; + next_bytes[2] = (next_byte_offset + 2) < stream_size_in_byte ? p_stream[next_byte_offset + 2] : 0; + + if ( (next_bytes[0] == 0x00 && next_bytes[1] == 0x00 && next_bytes[2] == 0x00) || // padding zero bytes + (next_bytes[0] == 0x00 && next_bytes[1] == 0x00 && next_bytes[2] == 0x01) ) { // start code + /// Continue checking the existence of the trailing bits in the current byte. + } else { + return true; + } + + /// Check if RBSP trailing bits immediately follow + if ((bit_offset_in_byte) == 0) { + if (curr_byte == 0x80) { // RBSP trailing bits + more_rbsp_bits = false; + } else { + more_rbsp_bits = true; + } + } else { + uint8_t curr_bit = curr_byte & (0x80 >> bit_offset_in_byte); + if ( curr_bit == 0 ) { + more_rbsp_bits = true; // rbsp_stop_one_bit has to be 1. + } else { + /// If this is the last bit, need to grab the next byte + if ( bit_offset_in_byte == 7 ) { + if ( next_bytes[0] != 0 ) { + more_rbsp_bits = true; + } else { + more_rbsp_bits = false; + } + } else { + bit_offset_in_byte++; + for (int i = bit_offset_in_byte; i < 8; i++) { + curr_bit = curr_byte & (0x80 >> i); + if ( curr_bit ) { + more_rbsp_bits = true; + break; + } + } + } + } + } + + return more_rbsp_bits; +} + +#if DBGINFO +void AvcVideoParser::PrintSps(AvcSeqParameterSet *p_sps) { + uint32_t i, j; + + MSG("======================="); + MSG("Sequence parameter set: "); + MSG("======================="); + MSG("profile_idc = " << p_sps->profile_idc); + MSG("level_idc = " << p_sps->level_idc); + MSG("chroma_format_idc = " << p_sps->chroma_format_idc); + MSG("separate_colour_plane_flag = " << p_sps->separate_colour_plane_flag); + MSG("bit_depth_luma_minus8 = " << p_sps->bit_depth_luma_minus8); + MSG("bit_depth_chroma_minus8 = " << p_sps->bit_depth_chroma_minus8); + MSG("qpprime_y_zero_transform_bypass_flag = " << p_sps->qpprime_y_zero_transform_bypass_flag); + MSG("seq_scaling_matrix_present_flag = " << p_sps->seq_scaling_matrix_present_flag); + + MSG_NO_NEWLINE("seq_scaling_list_present_flag[12]: "); + for (i = 0; i < 12; i++) { + MSG_NO_NEWLINE(" " << p_sps->seq_scaling_list_present_flag[i]); + } + MSG(""); + + MSG("scaling_list_4x4[6][16]:"); + for (i = 0; i < 6; i++) { + for (j = 0; j < 16; j++) { + MSG_NO_NEWLINE(" " << p_sps->scaling_list_4x4[i][j]); + } + MSG(""); + } + MSG(""); + + MSG("scaling_list_8x8[6][64]:"); + for (i = 0; i < 6; i++) { + for (j = 0; j < 64; j++) { + MSG_NO_NEWLINE(" " << p_sps->scaling_list_8x8[i][j]); + } + MSG(""); + } + MSG(""); + + MSG_NO_NEWLINE("use_default_scaling_matrix_4x4_flag[6]: "); + for (i = 0; i < 6; i++) { + MSG_NO_NEWLINE(" " << p_sps->use_default_scaling_matrix_4x4_flag[i]); + } + MSG(""); + + MSG_NO_NEWLINE("use_default_scaling_matrix_8x8_flag[6]: "); + for (i = 0; i < 6; i++) { + MSG_NO_NEWLINE(" " << p_sps->use_default_scaling_matrix_8x8_flag[i]); + } + MSG(""); + + MSG("log2_max_frame_num_minus4 = " << p_sps->log2_max_frame_num_minus4); + MSG("pic_order_cnt_type = " << p_sps->pic_order_cnt_type); + MSG("log2_max_pic_order_cnt_lsb_minus4 = " << p_sps->log2_max_pic_order_cnt_lsb_minus4); + MSG("delta_pic_order_always_zero_flag = " << p_sps->delta_pic_order_always_zero_flag); + MSG("offset_for_non_ref_pic = " << p_sps->offset_for_non_ref_pic); + MSG("offset_for_top_to_bottom_field = " << p_sps->offset_for_top_to_bottom_field); + MSG("num_ref_frames_in_pic_order_cnt_cycle = " << p_sps->num_ref_frames_in_pic_order_cnt_cycle); + MSG("offset_for_ref_frame[]: ...."); + MSG("max_num_ref_frames = " << p_sps->max_num_ref_frames); + MSG("gaps_in_frame_num_value_allowed_flag = " << p_sps->gaps_in_frame_num_value_allowed_flag); + MSG("pic_width_in_mbs_minus1 = " << p_sps->pic_width_in_mbs_minus1); + MSG("pic_height_in_map_units_minus1 = " << p_sps->pic_height_in_map_units_minus1); + MSG("frame_mbs_only_flag = " << p_sps->frame_mbs_only_flag); + MSG("mb_adaptive_frame_field_flag = " << p_sps->mb_adaptive_frame_field_flag); + MSG("direct_8x8_inference_flag = " << p_sps->direct_8x8_inference_flag); + MSG("frame_cropping_flag = " << p_sps->frame_cropping_flag); + MSG("frame_crop_left_offset = " << p_sps->frame_crop_left_offset); + MSG("frame_crop_right_offset = " << p_sps->frame_crop_right_offset); + MSG("frame_crop_top_offset = " << p_sps->frame_crop_top_offset); + MSG("frame_crop_bottom_offset = " << p_sps->frame_crop_bottom_offset); + MSG("vui_parameters_present_flag = " << p_sps->vui_parameters_present_flag); + MSG("vui_seq_parameters: ...."); + MSG(""); +} + +void AvcVideoParser::PrintPps(AvcPicParameterSet *p_pps) { + uint32_t i, j; + + MSG("======================="); + MSG("Picture parameter set: "); + MSG("======================="); + MSG("pic_parameter_set_id = " << p_pps->pic_parameter_set_id); + MSG("seq_parameter_set_id = " << p_pps->seq_parameter_set_id); + MSG("entropy_coding_mode_flag = " << p_pps->entropy_coding_mode_flag); + MSG("bottom_field_pic_order_in_frame_present_flag = " << p_pps->bottom_field_pic_order_in_frame_present_flag); + MSG("num_slice_groups_minus1 = " << p_pps->num_slice_groups_minus1); + MSG("slice_group_map_type = " << p_pps->slice_group_map_type); + MSG("run_length_minus1[]: ...."); + MSG("top_left[]: ...."); + MSG("bottom_right[]: ...."); + MSG("slice_group_change_direction_flag = " << p_pps->slice_group_change_direction_flag); + MSG("slice_group_change_rate_minus1 = " << p_pps->slice_group_change_rate_minus1); + MSG("pic_size_in_map_units_minus1 = " << p_pps->pic_size_in_map_units_minus1); + MSG("slice_group_id[]: ...."); + MSG("num_ref_idx_l0_default_active_minus1 = " << p_pps->num_ref_idx_l0_default_active_minus1); + MSG("num_ref_idx_l1_default_active_minus1 = " << p_pps->num_ref_idx_l1_default_active_minus1); + MSG("weighted_pred_flag = " << p_pps->weighted_pred_flag); + MSG("weighted_bipred_idc = " << p_pps->weighted_bipred_idc); + MSG("pic_init_qp_minus26 = " << p_pps->pic_init_qp_minus26); + MSG("pic_init_qs_minus26 = " << p_pps->pic_init_qs_minus26); + MSG("chroma_qp_index_offset = " << p_pps->chroma_qp_index_offset); + MSG("deblocking_filter_control_present_flag = " << p_pps->deblocking_filter_control_present_flag); + MSG("constrained_intra_pred_flag = " << p_pps->constrained_intra_pred_flag); + MSG("redundant_pic_cnt_present_flag = " << p_pps->redundant_pic_cnt_present_flag); + MSG("transform_8x8_mode_flag = " << p_pps->transform_8x8_mode_flag); + MSG("pic_scaling_matrix_present_flag = " << p_pps->pic_scaling_matrix_present_flag); + + MSG_NO_NEWLINE("pic_scaling_list_present_flag[12]: "); + for (i = 0; i < 12; i++) { + MSG_NO_NEWLINE(" " << p_pps->pic_scaling_list_present_flag[i]); + } + MSG(""); + MSG("scaling_list_4x4[6][16]:"); + for (i = 0; i < 6; i++) { + for (j = 0; j < 16; j++) { + MSG_NO_NEWLINE(" " << p_pps->scaling_list_4x4[i][j]); + } + MSG(""); + } + MSG(""); + + MSG("scaling_list_8x8[6][64]:"); + for (i = 0; i < 6; i++) { + for (j = 0; j < 64; j++) { + MSG_NO_NEWLINE(" " << p_pps->scaling_list_8x8[i][j]); + } + MSG(""); + } + MSG(""); + + MSG_NO_NEWLINE("use_default_scaling_matrix_4x4_flag[6]: "); + for (i = 0; i < 6; i++) { + MSG_NO_NEWLINE(" " << p_pps->use_default_scaling_matrix_4x4_flag[i]); + } + MSG(""); + + MSG_NO_NEWLINE("use_default_scaling_matrix_8x8_flag[6]: "); + for (i = 0; i < 6; i++) { + MSG_NO_NEWLINE(" " << p_pps->use_default_scaling_matrix_8x8_flag[i]); + } + MSG(""); + + MSG("second_chroma_qp_index_offset = " << p_pps->second_chroma_qp_index_offset); + MSG(""); +} + +void AvcVideoParser::PrintSliceHeader(AvcSliceHeader *p_slice_header) { + uint32_t i, j; + + MSG("======================"); + MSG("Slice header"); + MSG("======================"); + MSG("first_mb_in_slice = " << p_slice_header->first_mb_in_slice); + MSG("slice_type = " << p_slice_header->slice_type); + MSG("pic_parameter_set_id = " << p_slice_header->pic_parameter_set_id); + MSG("frame_num = " << p_slice_header->frame_num); + MSG("field_pic_flag = " << p_slice_header->field_pic_flag); + MSG("bottom_field_flag = " << p_slice_header->bottom_field_flag); + MSG("idr_pic_id = " << p_slice_header->idr_pic_id); + MSG("pic_order_cnt_lsb = " << p_slice_header->pic_order_cnt_lsb); + MSG("delta_pic_order_cnt_bottom = " << p_slice_header->delta_pic_order_cnt_bottom); + MSG("delta_pic_order_cnt[2] = " << p_slice_header->delta_pic_order_cnt[0] << ", " << p_slice_header->delta_pic_order_cnt[1]); + MSG("redundant_pic_cnt = " << p_slice_header->redundant_pic_cnt); + MSG("direct_spatial_mv_pred_flag = " << p_slice_header->direct_spatial_mv_pred_flag); + MSG("num_ref_idx_active_override_flag = " << p_slice_header->num_ref_idx_active_override_flag); + MSG("num_ref_idx_l0_active_minus1 = " << p_slice_header->num_ref_idx_l0_active_minus1); + MSG("num_ref_idx_l1_active_minus1 = " << p_slice_header->num_ref_idx_l1_active_minus1); + + MSG("Reference picture list modification:"); + MSG("ref_pic_list_modification_flag_l0 = " << p_slice_header->ref_pic_list.ref_pic_list_modification_flag_l0); + if ( p_slice_header->ref_pic_list.ref_pic_list_modification_flag_l0 ){ + MSG("Modification operations for list 0: "); + for (j = 0; j < AVC_MAX_REF_PICTURE_NUM; j++) { + MSG_NO_NEWLINE("(" << p_slice_header->ref_pic_list.modification_l0[j].modification_of_pic_nums_idc << ", " << p_slice_header->ref_pic_list.modification_l0[j].abs_diff_pic_num_minus1 << ", " << p_slice_header->ref_pic_list.modification_l0[j].long_term_pic_num << ") "); + } + MSG(""); + } + MSG("ref_pic_list_modification_flag_l1 = " << p_slice_header->ref_pic_list.ref_pic_list_modification_flag_l1); + if ( p_slice_header->ref_pic_list.ref_pic_list_modification_flag_l1 ) { + MSG("Modification operations for list 1: "); + for (j = 0; j < AVC_MAX_REF_PICTURE_NUM; j++) { + MSG_NO_NEWLINE("(" << p_slice_header->ref_pic_list.modification_l1[j].modification_of_pic_nums_idc << ", " << p_slice_header->ref_pic_list.modification_l1[j].abs_diff_pic_num_minus1 << ", " << p_slice_header->ref_pic_list.modification_l1[j].long_term_pic_num << ") "); + } + MSG(""); + } + + MSG("pred_weight_table: ...."); + + MSG("Decoded reference picture marking:"); + AvcDecRefPicMarking *refMarking = &(p_slice_header->dec_ref_pic_marking); + MSG("no_output_of_prior_pics_flag = " << refMarking->no_output_of_prior_pics_flag); + MSG("long_term_reference_flag = " << refMarking->long_term_reference_flag); + MSG("adaptive_ref_pic_marking_mode_flag = " << refMarking->adaptive_ref_pic_marking_mode_flag); + if ( refMarking->adaptive_ref_pic_marking_mode_flag ) { + MSG("mmco_count = " << refMarking->mmco_count); + for (j = 0; j < AVC_MAX_REF_PICTURE_NUM; j++) { + MSG_NO_NEWLINE("(" << refMarking->mmco[j].memory_management_control_operation << ", " << refMarking->mmco[j].difference_of_pic_nums_minus1 << ", " << refMarking->mmco[j].long_term_pic_num << ", " << refMarking->mmco[j].long_term_frame_idx << ", " << refMarking->mmco[j].max_long_term_frame_idx_plus1 << ") "); + } + } + + MSG("cabac_init_idc = " << p_slice_header->cabac_init_idc); + MSG("slice_qp_delta = " << p_slice_header->slice_qp_delta); + MSG("sp_for_switch_flag = " << p_slice_header->sp_for_switch_flag); + MSG("slice_qs_delta = " << p_slice_header->slice_qs_delta); + MSG("disable_deblocking_filter_idc = " << p_slice_header->disable_deblocking_filter_idc); + MSG("slice_alpha_c0_offset_div2 = " << p_slice_header->slice_alpha_c0_offset_div2); + MSG("slice_beta_offset_div2 = " << p_slice_header->slice_beta_offset_div2); + MSG("slice_group_change_cycle = " << p_slice_header->slice_group_change_cycle); +} +#endif // DBGINFO \ No newline at end of file diff --git a/src/parser/avc_parser.h b/src/parser/avc_parser.h new file mode 100644 index 0000000000..46622727ec --- /dev/null +++ b/src/parser/avc_parser.h @@ -0,0 +1,153 @@ +/* +Copyright (c) 2023 - 2024 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. +*/ +#pragma once + +#include "avc_defines.h" +#include "roc_video_parser.h" + +class AvcVideoParser : public RocVideoParser { + +public: + /*! \brief AvcVideoParser constructor + */ + AvcVideoParser(); + + /*! \brief AvcVideoParser destructor + */ + virtual ~AvcVideoParser(); + + /*! \brief Function to Initialize the parser + * \param [in] p_params Input of RocdecParserParams with codec type to initialize parser. + * \return rocDecStatus Returns success on completion, else error code for failure + */ + virtual rocDecStatus Initialize(RocdecParserParams *p_params); + + /*! \brief Function to Parse video data: Typically called from application when a demuxed picture is ready to be parsed + * \param [in] p_data Pointer to picture data of type RocdecSourceDataPacket + * @return rocDecStatus Returns success on completion, else error_code for failure + */ + virtual rocDecStatus ParseVideoData(RocdecSourceDataPacket *p_data); + + /*! \brief function to uninitialize AVC parser + * @return rocDecStatus + */ + virtual rocDecStatus UnInitialize(); // derived method + + +protected: + /*! \brief Decoded picture buffer + */ + typedef struct{ + uint32_t dpb_size; // DPB buffer size in number of frames + } DecodedPictureBuffer; + + AvcNalUnitHeader nal_unit_header_; + AvcSeqParameterSet sps_list_[AVC_MAX_SPS_NUM]; + int32_t active_sps_id_; + AvcPicParameterSet pps_list_[AVC_MAX_PPS_NUM]; + int32_t active_pps_id_; + + AvcNalUnitHeader slice_nal_unit_header_; + AvcSliceHeader slice_header_0_; + + int prev_has_mmco_5_; + int curr_has_mmco_5_; + int prev_ref_pic_bottom_field_; + int curr_ref_pic_bottom_field_; + + // DPB + DecodedPictureBuffer dpb_buffer_; + + /*! \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 ParserResult + */ + ParserResult ParsePictureData(const uint8_t *p_stream, uint32_t pic_data_size); + + /*! \brief Function to parse the NAL unit header + * \param [in] header_byte The AVC NAL unit header byte + * \return AvcNalUnitHeader Parsed nal header + */ + AvcNalUnitHeader ParseNalUnitHeader(uint8_t header_byte); + + /*! \brief Function to parse Sequence Parameter Set + * \param [in] p_stream A pointer of uint8_t for the input stream to be parsed + * \param [in] size Size of the input stream + * \return No return value + */ + void ParseSps(uint8_t *p_stream, size_t size); + + /*! \brief Function to parse Picture Parameter Set + * \param [in] p_stream A pointer of uint8_t for the input stream to be parsed + * \param [in] size Size of the input stream + * \return No return value + */ + void ParsePps(uint8_t *p_stream, size_t stream_size_in_byte); + + /*! \brief Function to parse slice header + * \param p_stream The pointer to the input bit stream + * \param [in] stream_size_in_byte The byte size of the stream + * \param [out] p_slice_header The pointer to the slice header strucutre + * \return ParserResult + */ + ParserResult ParseSliceHeader(uint8_t *p_stream, size_t stream_size_in_byte, AvcSliceHeader *p_slice_header); + + /*! \brief Function to parse a scaling list + * \param [in] p_stream A pointer of uint8_t for the input stream to be parsed + * \param [in/out] offset Current bit offset + * \param [out] scaling_list Pointer to the output scaling list + * \param [in] list_size Scaling list size + * \param [out] use_default_scaling_matrix_flag Array of flags that indicate whether to use default values + */ + void GetScalingList(uint8_t *p_stream, size_t &offset, uint32_t *scaling_list, uint32_t list_size, uint32_t *use_default_scaling_matrix_flag); + + /*! \brief Function to parse vidio usability information (VUI) parameters + * \param [in] p_stream The pointer to the input bit stream + * \param [in/out] offset Current bit offset + * \param [out] p_vui_params The pointer to VUI structure + * \return No return value + */ + void GetVuiParameters(uint8_t *p_stream, size_t &offset, AvcVuiSeqParameters *p_vui_params); + + /*! \brief Function to check if there is more data in RBSP + * \param [in] p_stream The pointer to the input bit stream + * \param [in] stream_size_in_byte The byte size of the stream + * \param [in] bit_offset The current bit offset + * \return true/false + */ + bool MoreRbspData(uint8_t *p_stream, size_t stream_size_in_byte, size_t bit_offset); + +#if DBGINFO + /*! \brief Function to log out parsed SPS content for debug. + */ + void PrintSps(AvcSeqParameterSet *p_sps); + + /*! \brief Function to log out parsed PPS content for debug. + */ + void PrintPps(AvcPicParameterSet *p_pps); + + /*! \brief Function to log out parsed slice header content for debug. + */ + void PrintSliceHeader(AvcSliceHeader *p_slice_header); +#endif // DBGINFO +}; \ No newline at end of file diff --git a/src/parser/h264_parser.cpp b/src/parser/h264_parser.cpp deleted file mode 100644 index ae78cee0e5..0000000000 --- a/src/parser/h264_parser.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* -Copyright (c) 2023 - 2024 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 "h264_parser.h" - -/** - * @brief Construct a new HEVCParser object - * - */ -H264VideoParser::H264VideoParser() { - -} - -/** - * @brief Function to initialize any h264 parser related members - * - * @return rocDecStatus - */ -rocDecStatus H264VideoParser::Initialize(RocdecParserParams *pParams) { - RocVideoParser::Initialize(pParams); - //todo:: - return ROCDEC_NOT_IMPLEMENTED; -} - -/** - * @brief Function to Parse video data: Typically called from application when a demuxed picture is ready to be parsed - * - * @param pData: IN: pointer to demuxed data packet - * @return rocDecStatus - */ -rocDecStatus H264VideoParser::ParseVideoData(RocdecSourceDataPacket *pData) { - return ROCDEC_NOT_IMPLEMENTED; -} - -/** - * @brief function to uninitialize h264 parser - * - * @return rocDecStatus - */ -rocDecStatus H264VideoParser::UnInitialize() { - //todo:: - return ROCDEC_NOT_IMPLEMENTED; -} diff --git a/src/parser/h264_parser.h b/src/parser/h264_parser.h deleted file mode 100644 index 30133e7791..0000000000 --- a/src/parser/h264_parser.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright (c) 2023 - 2024 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. -*/ -#pragma once - -#include "roc_video_parser.h" - -class H264VideoParser : public RocVideoParser { - -public: - /** - * @brief Construct a new HEVCParser object - * - */ - H264VideoParser(); - /** - * @brief Derived Function to Initialize the parser - * - * @return rocDecStatus - */ - virtual rocDecStatus Initialize(RocdecParserParams *pParams); - /** - * @brief Function to Parse video data: Typically called from application when a demuxed picture is ready to be parsed - * @brief Derived from base class - * - * @param pData: Pointer to picture data - * @return rocDecStatus: returns success on completion, else error_code for failure - */ - virtual rocDecStatus ParseVideoData(RocdecSourceDataPacket *pData); - /** - * @brief function to uninitialize h264 parser - * - * @return rocDecStatus - */ - virtual rocDecStatus UnInitialize(); // derived method - - -private: - -}; \ No newline at end of file diff --git a/src/parser/hevc_defines.h b/src/parser/hevc_defines.h index 9d955e7aec..01b07c11d9 100644 --- a/src/parser/hevc_defines.h +++ b/src/parser/hevc_defines.h @@ -30,7 +30,6 @@ THE SOFTWARE. #define HEVC_SCALING_LIST_NUM 6 ///< list number for quantization matrix #define HEVC_SCALING_LIST_MAX_INDEX 64 -#define RBSP_BUF_SIZE 1024 // enough to parse any parameter sets or slice headers #define HEVC_MAX_DPB_FRAMES 16 // (A-2) #define HEVC_MAX_NUM_REF_PICS 16 // 7.4.7.1. (num_tile_columns_minus1 + 1) * PicHeightInCtbsY − 1. Max tile columns = 20 (A.4.2). Pic height in 16x16 CTB of 8K = 270. diff --git a/src/parser/hevc_parser.cpp b/src/parser/hevc_parser.cpp index cca1ee24bb..e2ded97de1 100644 --- a/src/parser/hevc_parser.cpp +++ b/src/parser/hevc_parser.cpp @@ -36,12 +36,10 @@ inline T *AllocStruct(const int max_cnt) { } HevcVideoParser::HevcVideoParser() { - pic_count_ = 0; first_pic_after_eos_nal_unit_ = 0; m_active_vps_id_ = -1; m_active_sps_id_ = -1; m_active_pps_id_ = -1; - b_new_picture_ = false; // allocate all fixed size structors here m_vps_ = AllocStruct(MAX_VPS_COUNT); m_sps_ = AllocStruct(MAX_SPS_COUNT); @@ -60,11 +58,7 @@ HevcVideoParser::HevcVideoParser() { } rocDecStatus HevcVideoParser::Initialize(RocdecParserParams *p_params) { - ParserResult status = Init(); - if (status) - return ROCDEC_RUNTIME_ERROR; - RocVideoParser::Initialize(p_params); - return ROCDEC_SUCCESS; + return RocVideoParser::Initialize(p_params); } /** @@ -83,7 +77,7 @@ rocDecStatus HevcVideoParser::ParseVideoData(RocdecSourceDataPacket *p_data) { // Clear DPB output/display buffer number dpb_buffer_.num_output_pics = 0; - bool status = ParseFrameData(p_data->payload, p_data->payload_size); + bool status = ParsePictureData(p_data->payload, p_data->payload_size); if (!status) { ERR(STR("Parser failed!")); return ROCDEC_RUNTIME_ERROR; @@ -154,11 +148,6 @@ HevcVideoParser::~HevcVideoParser() { } } -ParserResult HevcVideoParser::Init() { - b_new_picture_ = false; - return PARSER_OK; -} - int HevcVideoParser::FillSeqCallbackFn(HevcSeqParamSet* sps_data) { video_format_params_.codec = rocDecVideoCodec_HEVC; video_format_params_.frame_rate.numerator = frame_rate_.numerator; @@ -555,11 +544,11 @@ int HevcVideoParser::OutputDecodedPictures() { return PARSER_OK; } -bool HevcVideoParser::ParseFrameData(const uint8_t* p_stream, uint32_t frame_data_size) { +bool HevcVideoParser::ParsePictureData(const uint8_t* p_stream, uint32_t pic_data_size) { int ret = PARSER_OK; - frame_data_buffer_ptr_ = (uint8_t*)p_stream; - frame_data_size_ = frame_data_size; + pic_data_buffer_ptr_ = (uint8_t*)p_stream; + pic_data_size_ = pic_data_size; curr_byte_offset_ = 0; start_code_num_ = 0; curr_start_code_offset_ = 0; @@ -571,7 +560,6 @@ bool HevcVideoParser::ParseFrameData(const uint8_t* p_stream, uint32_t frame_dat do { ret = GetNalUnit(); - if (ret == PARSER_NOT_FOUND) { ERR(STR("Error: no start code found in the frame data.")); return false; @@ -582,26 +570,26 @@ 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]); + nal_unit_header_ = ParseNalUnitHeader(&pic_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); - ParseVps(m_rbsp_buf_, m_rbsp_size_); + memcpy(rbsp_buf_, (pic_data_buffer_ptr_ + curr_start_code_offset_ + 5), ebsp_size); + rbsp_size_ = EbspToRbsp(rbsp_buf_, 0, ebsp_size); + ParseVps(rbsp_buf_, rbsp_size_); break; } case NAL_UNIT_SPS: { - 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); - ParseSps(m_rbsp_buf_, m_rbsp_size_); + memcpy(rbsp_buf_, (pic_data_buffer_ptr_ + curr_start_code_offset_ + 5), ebsp_size); + rbsp_size_ = EbspToRbsp(rbsp_buf_, 0, ebsp_size); + ParseSps(rbsp_buf_, rbsp_size_); break; } case NAL_UNIT_PPS: { - 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); - ParsePps(m_rbsp_buf_, m_rbsp_size_); + memcpy(rbsp_buf_, (pic_data_buffer_ptr_ + curr_start_code_offset_ + 5), ebsp_size); + rbsp_size_ = EbspToRbsp(rbsp_buf_, 0, ebsp_size); + ParsePps(rbsp_buf_, rbsp_size_); break; } @@ -621,20 +609,20 @@ bool HevcVideoParser::ParseFrameData(const uint8_t* p_stream, uint32_t frame_dat case NAL_UNIT_CODED_SLICE_RADL_R: case NAL_UNIT_CODED_SLICE_RASL_N: case NAL_UNIT_CODED_SLICE_RASL_R: { - 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); + memcpy(rbsp_buf_, (pic_data_buffer_ptr_ + curr_start_code_offset_ + 5), ebsp_size); + rbsp_size_ = EbspToRbsp(rbsp_buf_, 0, ebsp_size); // For each picture, only parse the first slice header if (slice_num_ == 0) { // Save slice NAL unit header slice_nal_unit_header_ = nal_unit_header_; // Use the data directly from demuxer without copying - pic_stream_data_ptr_ = frame_data_buffer_ptr_ + curr_start_code_offset_; + pic_stream_data_ptr_ = pic_data_buffer_ptr_ + curr_start_code_offset_; // Picture stream data size is calculated as the diff between the frame end and the first slice offset. // This is to consider the possibility of non-slice NAL units between slices. - pic_stream_data_size_ = frame_data_size - curr_start_code_offset_; + pic_stream_data_size_ = pic_data_size - curr_start_code_offset_; - ParseSliceHeader(m_rbsp_buf_, m_rbsp_size_); + ParseSliceHeader(rbsp_buf_, rbsp_size_); // Start decode process if (IsIrapPic(&slice_nal_unit_header_)) { @@ -694,9 +682,9 @@ bool HevcVideoParser::ParseFrameData(const uint8_t* p_stream, uint32_t frame_dat sei_rbsp_buf_size_ = sei_ebsp_size > INIT_SEI_PAYLOAD_BUF_SIZE ? sei_ebsp_size : INIT_SEI_PAYLOAD_BUF_SIZE; sei_rbsp_buf_ = new uint8_t [sei_rbsp_buf_size_]; } - memcpy(sei_rbsp_buf_, (frame_data_buffer_ptr_ + curr_start_code_offset_ + 5), sei_ebsp_size); - m_rbsp_size_ = EBSPtoRBSP(sei_rbsp_buf_, 0, sei_ebsp_size); - ParseSeiMessage(sei_rbsp_buf_, m_rbsp_size_); + memcpy(sei_rbsp_buf_, (pic_data_buffer_ptr_ + curr_start_code_offset_ + 5), sei_ebsp_size); + rbsp_size_ = EbspToRbsp(sei_rbsp_buf_, 0, sei_ebsp_size); + ParseSeiMessage(sei_rbsp_buf_, rbsp_size_); } break; } @@ -725,47 +713,6 @@ bool HevcVideoParser::ParseFrameData(const uint8_t* p_stream, uint32_t frame_dat return true; } -int HevcVideoParser::GetNalUnit() { - bool start_code_found = false; - - nal_unit_size_ = 0; - curr_start_code_offset_ = next_start_code_offset_; // save the current start code offset - - // Search for the next start code - while (curr_byte_offset_ < frame_data_size_ - 2) { - if (frame_data_buffer_ptr_[curr_byte_offset_] == 0 && frame_data_buffer_ptr_[curr_byte_offset_ + 1] == 0 && frame_data_buffer_ptr_[curr_byte_offset_ + 2] == 0x01) { - curr_start_code_offset_ = next_start_code_offset_; // save the current start code offset - - start_code_found = true; - start_code_num_++; - next_start_code_offset_ = curr_byte_offset_; - // Move the pointer 3 bytes forward - curr_byte_offset_ += 3; - - // For the very first NAL unit, search for the next start code (or reach the end of frame) - if (start_code_num_ == 1) { - start_code_found = false; - curr_start_code_offset_ = next_start_code_offset_; - continue; - } else { - break; - } - } - curr_byte_offset_++; - } - if (start_code_num_ == 0) { - // No NAL unit in the frame data - return PARSER_NOT_FOUND; - } - if (start_code_found) { - nal_unit_size_ = next_start_code_offset_ - curr_start_code_offset_; - return PARSER_OK; - } else { - nal_unit_size_ = frame_data_size_ - curr_start_code_offset_; - return PARSER_EOF; - } -} - 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) { if (profile_present_flag) { ptl->general_profile_space = Parser::ReadBits(nalu, offset, 2); @@ -2393,48 +2340,8 @@ int HevcVideoParser::BumpPicFromDpb() { 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) { - 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; -} - #if DBGINFO -void HevcVideoParser::PrintVps(HevcVideoParser::HevcVideoParamSet *vps_ptr) { +void HevcVideoParser::PrintVps(HevcVideoParamSet *vps_ptr) { MSG("=== hevc_video_parameter_set_t ==="); MSG("vps_video_parameter_set_id = " << vps_ptr->vps_video_parameter_set_id); MSG("vps_base_layer_internal_flag = " << vps_ptr->vps_base_layer_internal_flag); @@ -2485,7 +2392,7 @@ void HevcVideoParser::PrintVps(HevcVideoParser::HevcVideoParamSet *vps_ptr) { MSG(""); } -void HevcVideoParser::PrintSps(HevcVideoParser::HevcSeqParamSet *sps_ptr) { +void HevcVideoParser::PrintSps(HevcSeqParamSet *sps_ptr) { MSG("=== hevc_sequence_parameter_set_t ==="); MSG("sps_video_parameter_set_id = " << sps_ptr->sps_video_parameter_set_id); MSG("sps_max_sub_layers_minus1 = " << sps_ptr->sps_max_sub_layers_minus1); @@ -2597,7 +2504,7 @@ void HevcVideoParser::PrintSps(HevcVideoParser::HevcSeqParamSet *sps_ptr) { MSG(""); } -void HevcVideoParser::PrintPps(HevcVideoParser::HevcPicParamSet *pps_ptr) { +void HevcVideoParser::PrintPps(HevcPicParamSet *pps_ptr) { MSG("=== hevc_picture_parameter_set_t ==="); MSG("pps_pic_parameter_set_id = " << pps_ptr->pps_pic_parameter_set_id); MSG("pps_seq_parameter_set_id = " << pps_ptr->pps_seq_parameter_set_id); @@ -2747,7 +2654,7 @@ void HevcVideoParser::PrintSliceSegHeader(HevcSliceSegHeader *slice_header_ptr) MSG(""); } -void HevcVideoParser::PrintStRps(HevcVideoParser::HevcShortTermRps *rps_ptr) { +void HevcVideoParser::PrintStRps(HevcShortTermRps *rps_ptr) { MSG("==== Short-term reference picture set =====") MSG("inter_ref_pic_set_prediction_flag = " << rps_ptr->inter_ref_pic_set_prediction_flag); MSG("delta_idx_minus1 = " << rps_ptr->delta_idx_minus1); @@ -2810,7 +2717,7 @@ void HevcVideoParser::PrintStRps(HevcVideoParser::HevcShortTermRps *rps_ptr) { MSG(""); } -void HevcVideoParser::PrintLtRefInfo(HevcVideoParser::HevcLongTermRps *lt_info_ptr) { +void HevcVideoParser::PrintLtRefInfo(HevcLongTermRps *lt_info_ptr) { MSG("==== Long-term reference picture info ====="); MSG("num_of_pics = " << lt_info_ptr->num_of_pics); MSG_NO_NEWLINE("pocs[]:"); diff --git a/src/parser/hevc_parser.h b/src/parser/hevc_parser.h index c99a76c17a..202fd494ad 100644 --- a/src/parser/hevc_parser.h +++ b/src/parser/hevc_parser.h @@ -26,11 +26,8 @@ THE SOFTWARE. #include "hevc_defines.h" #include -#include #include -#define ZEROBYTES_SHORTSTARTCODE 2 //indicates the number of zero bytes in the short start-code prefix - //size_id = 0 extern int scaling_list_default_0[1][6][16]; //size_id = 1, 2 @@ -116,18 +113,7 @@ protected: uint32_t output_pic_list[HEVC_MAX_DPB_FRAMES]; // sorted output picuture index to frame_buffer_list[] } 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. - * \param [in] begin_bytepos Start position in the EBSP buffer to convert - * \param [in] end_bytepos End position in the EBSP buffer to convert, generally it's size. - * \return Returns the size of the converted buffer in size_t - */ - size_t EBSPtoRBSP(uint8_t *stream_buffer, size_t begin_bytepos, size_t end_bytepos); - // Data members of HEVC class - uint32_t pic_count_; // decoded picture count for the current bitstream - HevcNalUnitHeader nal_unit_header_; int32_t m_active_vps_id_; int32_t m_active_sps_id_; @@ -140,22 +126,6 @@ protected: HevcNalUnitHeader slice_nal_unit_header_; HevcPicInfo curr_pic_info_; - bool b_new_picture_; - int m_packet_count_; - int m_rbsp_size_; - uint8_t m_rbsp_buf_[RBSP_BUF_SIZE]; // to store parameter set or slice header RBSP - - uint8_t *sei_rbsp_buf_; // buffer to store SEI RBSP. Allocated at run time. - uint32_t sei_rbsp_buf_size_; - std::vector sei_message_list_; - int sei_message_count_; // total SEI playload message count of the current frame. - uint8_t *sei_payload_buf_; // buffer to store SEI playload. Allocated at run time. - uint32_t sei_payload_buf_size_; - uint32_t sei_payload_size_; // total SEI payload size of the current frame - - int slice_num_; - uint8_t* pic_stream_data_ptr_; - int pic_stream_data_size_; int first_pic_after_eos_nal_unit_; // to flag the first picture after EOS int no_rasl_output_flag_; // NoRaslOutputFlag @@ -191,17 +161,6 @@ protected: 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 - int curr_byte_offset_; // current parsing byte offset - - // NAL unit info - int start_code_num_; // number of start codes found so far - int curr_start_code_offset_; - int next_start_code_offset_; - int nal_unit_size_; - /*! \brief Function to parse Video Parameter Set * \param [in] nalu A pointer of uint8_t for the input stream to be parsed * \param [in] size Size of the input stream @@ -358,17 +317,12 @@ protected: */ int BumpPicFromDpb(); - /*! \brief Function to parse the data received from the demuxer. + /*! \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] frame_data_size Size of the input stream + * \param [in] pic_data_size Size of the input stream * \return True is successful, else false */ - bool ParseFrameData(const uint8_t* p_stream, uint32_t frame_data_size); - - /*! \brief Function to get the NAL Unit data - * \return Returns OK if successful, else error code - */ - int GetNalUnit(); + bool ParsePictureData(const uint8_t* p_stream, uint32_t pic_data_size); #if DBGINFO void PrintVps(HevcVideoParamSet *vps_ptr); @@ -380,11 +334,6 @@ protected: #endif // DBGINFO private: - /*! \brief Function to initialize the HEVC parser members - * \return Returns OK in ParserResult if successful, else error code - */ - ParserResult Init(); - // functions to fill structures for callback functions int FillSeqCallbackFn(HevcSeqParamSet* sps_data); void FillSeiMessageCallbackFn(); diff --git a/src/parser/parser_handle.h b/src/parser/parser_handle.h index e33b750426..636524a0b9 100644 --- a/src/parser/parser_handle.h +++ b/src/parser/parser_handle.h @@ -25,7 +25,7 @@ THE SOFTWARE. #include #include "rocparser.h" #include "roc_video_parser.h" -#include "h264_parser.h" +#include "avc_parser.h" #include "hevc_parser.h" class RocParserHandle { @@ -44,7 +44,7 @@ private: void CreateParser(RocdecParserParams *params) { switch(params->CodecType) { case rocDecVideoCodec_H264: - roc_parser_ = std::make_shared(); + roc_parser_ = std::make_shared(); break; case rocDecVideoCodec_HEVC: roc_parser_ = std::make_shared(); diff --git a/src/parser/roc_video_parser.cpp b/src/parser/roc_video_parser.cpp index 4a7cfbcb42..71bb1197df 100644 --- a/src/parser/roc_video_parser.cpp +++ b/src/parser/roc_video_parser.cpp @@ -23,6 +23,7 @@ THE SOFTWARE. #include "roc_video_parser.h" RocVideoParser::RocVideoParser() { + pic_count_ = 0; pic_width_ = 0; pic_height_ = 0; new_sps_activated_ = false; @@ -50,3 +51,84 @@ rocDecStatus RocVideoParser::Initialize(RocdecParserParams *pParams) { return ROCDEC_SUCCESS; } + +ParserResult RocVideoParser::GetNalUnit() { + bool start_code_found = false; + + nal_unit_size_ = 0; + curr_start_code_offset_ = next_start_code_offset_; // save the current start code offset + + // Search for the next start code + while (curr_byte_offset_ < pic_data_size_ - 2) { + if (pic_data_buffer_ptr_[curr_byte_offset_] == 0 && pic_data_buffer_ptr_[curr_byte_offset_ + 1] == 0 && pic_data_buffer_ptr_[curr_byte_offset_ + 2] == 0x01) { + curr_start_code_offset_ = next_start_code_offset_; // save the current start code offset + + start_code_found = true; + start_code_num_++; + next_start_code_offset_ = curr_byte_offset_; + // Move the pointer 3 bytes forward + curr_byte_offset_ += 3; + + // For the very first NAL unit, search for the next start code (or reach the end of frame) + if (start_code_num_ == 1) { + start_code_found = false; + curr_start_code_offset_ = next_start_code_offset_; + continue; + } else { + break; + } + } + curr_byte_offset_++; + } + if (start_code_num_ == 0) { + // No NAL unit in the frame data + return PARSER_NOT_FOUND; + } + if (start_code_found) { + nal_unit_size_ = next_start_code_offset_ - curr_start_code_offset_; + return PARSER_OK; + } else { + nal_unit_size_ = pic_data_size_ - curr_start_code_offset_; + return PARSER_EOF; + } +} + +size_t RocVideoParser::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; +} diff --git a/src/parser/roc_video_parser.h b/src/parser/roc_video_parser.h index f87b3282ae..cb5f4c5c9d 100644 --- a/src/parser/roc_video_parser.h +++ b/src/parser/roc_video_parser.h @@ -23,55 +23,10 @@ THE SOFTWARE. #include #include +#include #include "rocparser.h" #include "../commons.h" -/** - * @brief Base class for video parsing - * - */ -class RocVideoParser { -public: - RocVideoParser(); // default constructor - RocVideoParser(RocdecParserParams *pParams) : parser_params_(*pParams) {}; - virtual ~RocVideoParser() = default ; - virtual void SetParserParams(RocdecParserParams *pParams) { parser_params_ = *pParams; }; - RocdecParserParams *GetParserParams() {return &parser_params_;}; - virtual rocDecStatus Initialize(RocdecParserParams *pParams); - virtual rocDecStatus ParseVideoData(RocdecSourceDataPacket *pData) = 0; // pure virtual: implemented by derived class - virtual rocDecStatus UnInitialize() = 0; // pure virtual: implemented by derived class - -protected: - RocdecParserParams parser_params_ = {}; - /** - * @brief callback function pointers for the parser - * - */ - PFNVIDSEQUENCECALLBACK pfn_sequece_cb_; /**< Called before decoding frames and/or whenever there is a fmt change */ - PFNVIDDECODECALLBACK pfn_decode_picture_cb_; /**< Called when a picture is ready to be decoded (decode order) */ - 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 */ - - uint32_t pic_width_; - uint32_t pic_height_; - bool new_sps_activated_; - - struct { - uint32_t numerator; - uint32_t denominator; - } frame_rate_; - - RocdecVideoFormat video_format_params_; - RocdecSeiMessageInfo sei_message_info_params_; - RocdecPicParams dec_pic_params_; -}; - -enum ParserSeekOrigin { - PARSER_SEEK_BEGIN = 0, - PARSER_SEEK_CURRENT = 1, - PARSER_SEEK_END = 2, -}; - typedef enum ParserResult { PARSER_OK = 0, PARSER_FAIL , @@ -113,6 +68,89 @@ typedef enum ParserResult { PARSER_CODEC_NOT_SUPPORTED ,//codec not supported } ParserResult; +#define ZEROBYTES_SHORTSTARTCODE 2 //indicates the number of zero bytes in the short start-code prefix +#define RBSP_BUF_SIZE 1024 // enough to parse any parameter sets or slice headers + +/** + * @brief Base class for video parsing + * + */ +class RocVideoParser { +public: + RocVideoParser(); // default constructor + RocVideoParser(RocdecParserParams *pParams) : parser_params_(*pParams) {}; + virtual ~RocVideoParser() = default ; + virtual void SetParserParams(RocdecParserParams *pParams) { parser_params_ = *pParams; }; + RocdecParserParams *GetParserParams() {return &parser_params_;}; + virtual rocDecStatus Initialize(RocdecParserParams *pParams); + virtual rocDecStatus ParseVideoData(RocdecSourceDataPacket *pData) = 0; // pure virtual: implemented by derived class + virtual rocDecStatus UnInitialize() = 0; // pure virtual: implemented by derived class + +protected: + RocdecParserParams parser_params_ = {}; + + /*! \brief callback function pointers for the parser + */ + PFNVIDSEQUENCECALLBACK pfn_sequece_cb_; /**< Called before decoding frames and/or whenever there is a fmt change */ + PFNVIDDECODECALLBACK pfn_decode_picture_cb_; /**< Called when a picture is ready to be decoded (decode order) */ + 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 */ + + uint32_t pic_count_; // decoded picture count for the current bitstream + uint32_t pic_width_; + uint32_t pic_height_; + bool new_sps_activated_; + + struct { + uint32_t numerator; + uint32_t denominator; + } frame_rate_; + + RocdecVideoFormat video_format_params_; + RocdecSeiMessageInfo sei_message_info_params_; + RocdecPicParams dec_pic_params_; + + // Picture bit stream info + uint8_t *pic_data_buffer_ptr_; // bit stream buffer pointer of the current frame from the demuxer + int pic_data_size_; // bit stream size of the current frame + int curr_byte_offset_; // current parsing byte offset + + // NAL unit info + int start_code_num_; // number of start codes found so far + int curr_start_code_offset_; + int next_start_code_offset_; + int nal_unit_size_; + + int rbsp_size_; + uint8_t rbsp_buf_[RBSP_BUF_SIZE]; // to store parameter set or slice header RBSP + + int slice_num_; + uint8_t* pic_stream_data_ptr_; + int pic_stream_data_size_; + + uint8_t *sei_rbsp_buf_; // buffer to store SEI RBSP. Allocated at run time. + uint32_t sei_rbsp_buf_size_; + std::vector sei_message_list_; + int sei_message_count_; // total SEI playload message count of the current frame. + uint8_t *sei_payload_buf_; // buffer to store SEI playload. Allocated at run time. + uint32_t sei_payload_buf_size_; + uint32_t sei_payload_size_; // total SEI payload size of the current frame + + /*! \brief Function to get the NAL Unit data + * \return Returns OK if successful, else error code + */ + ParserResult GetNalUnit(); + + /*! \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. + * \param [in] begin_bytepos Start position in the EBSP buffer to convert + * \param [in] end_bytepos End position in the EBSP buffer to convert, generally it's size. + * \return Returns the size of the converted buffer in size_t + */ + size_t EbspToRbsp(uint8_t *stream_buffer, size_t begin_bytepos, size_t end_bytepos); +}; + // helpers namespace Parser { inline char GetLowByte(uint16_t data) { diff --git a/utils/rocvideodecode/roc_video_dec.cpp b/utils/rocvideodecode/roc_video_dec.cpp index 247a077dbf..7c34025cca 100644 --- a/utils/rocvideodecode/roc_video_dec.cpp +++ b/utils/rocvideodecode/roc_video_dec.cpp @@ -1060,7 +1060,7 @@ void RocVideoDecoder::GetDeviceinfo(std::string &device_name, std::string &gcn_a bool RocVideoDecoder::GetOutputSurfaceInfo(OutputSurfaceInfo **surface_info) { if (!disp_width_ || !disp_height_) { - std::cerr << "ERROR: RocVideoDecoderr is not intialized" << std::endl; + std::cerr << "ERROR: RocVideoDecoder is not intialized" << std::endl; return false; } *surface_info = &output_surface_info_;