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.
[ROCm/rocdecode commit: 395a1249c1]
This commit is contained in:
@@ -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 <stdint.h>
|
||||
|
||||
#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;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 <tt>RocdecParserParams</tt> with codec type to initialize parser.
|
||||
* \return <tt>rocDecStatus</tt> 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 <tt>RocdecSourceDataPacket</tt>
|
||||
* @return <tt>rocDecStatus</tt> 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 <tt>uint8_t</tt> for the input stream to be parsed
|
||||
* \param [in] pic_data_size Size of the input stream
|
||||
* \return <tt>ParserResult</tt>
|
||||
*/
|
||||
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 <tt>AvcNalUnitHeader</tt> Parsed nal header
|
||||
*/
|
||||
AvcNalUnitHeader ParseNalUnitHeader(uint8_t header_byte);
|
||||
|
||||
/*! \brief Function to parse Sequence Parameter Set
|
||||
* \param [in] p_stream A pointer of <tt>uint8_t</tt> 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 <tt>uint8_t</tt> 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 <tt>ParserResult</tt>
|
||||
*/
|
||||
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 <tt>uint8_t</tt> 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
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
};
|
||||
@@ -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.
|
||||
|
||||
@@ -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<HevcVideoParamSet>(MAX_VPS_COUNT);
|
||||
m_sps_ = AllocStruct<HevcSeqParamSet>(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<size_t>(-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[]:");
|
||||
|
||||
@@ -26,11 +26,8 @@ THE SOFTWARE.
|
||||
#include "hevc_defines.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#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 <tt>uint8_t</tt> 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 <tt>size_t</tt>
|
||||
*/
|
||||
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<RocdecSeiMessage> 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 <tt>uint8_t</tt> 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 <tt>uint8_t</tt> 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 <tt>ParserResult</tt> if successful, else error code
|
||||
*/
|
||||
ParserResult Init();
|
||||
|
||||
// functions to fill structures for callback functions
|
||||
int FillSeqCallbackFn(HevcSeqParamSet* sps_data);
|
||||
void FillSeiMessageCallbackFn();
|
||||
|
||||
@@ -25,7 +25,7 @@ THE SOFTWARE.
|
||||
#include <string>
|
||||
#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<H264VideoParser>();
|
||||
roc_parser_ = std::make_shared<AvcVideoParser>();
|
||||
break;
|
||||
case rocDecVideoCodec_HEVC:
|
||||
roc_parser_ = std::make_shared<HevcVideoParser>();
|
||||
|
||||
@@ -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<size_t>(-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;
|
||||
}
|
||||
|
||||
@@ -23,55 +23,10 @@ THE SOFTWARE.
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#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<RocdecSeiMessage> 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 <tt>uint8_t</tt> 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 <tt>size_t</tt>
|
||||
*/
|
||||
size_t EbspToRbsp(uint8_t *stream_buffer, size_t begin_bytepos, size_t end_bytepos);
|
||||
};
|
||||
|
||||
// helpers
|
||||
namespace Parser {
|
||||
inline char GetLowByte(uint16_t data) {
|
||||
|
||||
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user