Files
ANSCORE/MediaClient/rtp/h265_util.cpp

412 lines
12 KiB
C++

/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "sys_inc.h"
#include "bs.h"
#include "util.h"
#include "h265.h"
#include "h265_util.h"
/**************************************************************************************/
int h265_extract_rbsp(const uint8 *src, int length, uint8 *dst)
{
int i, si, di;
for (i = 0; i + 1 < length; i += 2)
{
if (src[i])
{
continue;
}
if (i > 0 && src[i - 1] == 0)
{
i--;
}
if (i + 2 < length && src[i + 1] == 0 && src[i + 2] <= 3)
{
if (src[i + 2] != 3 && src[i + 2] != 0)
{
/* startcode, so we must be past the end */
length = i;
}
break;
}
}
if (i >= length - 1)
{
// no escaped 0
memcpy(dst, src, length);
return length;
}
memcpy(dst, src, i);
si = di = i;
while (si + 2 < length)
{
// remove escapes (very rare 1:2^22)
if (src[si + 2] > 3)
{
dst[di++] = src[si++];
dst[di++] = src[si++];
}
else if (src[si] == 0 && src[si + 1] == 0 && src[si + 2] != 0)
{
if (src[si + 2] == 3)
{
// escape
dst[di++] = 0;
dst[di++] = 0;
si += 3;
continue;
}
else // next start code
{
return si;
}
}
dst[di++] = src[si++];
}
while (si < length)
{
dst[di++] = src[si++];
}
return si;
}
void h265_parser_init(h265_t * h)
{
memset(h, 0, sizeof(h265_t));
}
int h265_parser_parse(h265_t * h, uint8 * p_data, int len)
{
uint32 i;
bs_t s;
uint8 bufs[512];
if (len > (int)sizeof(bufs))
{
return -1;
}
len = h265_extract_rbsp(p_data, len, bufs);
bs_init(&s, bufs, len);
bs_read(&s, 4); // sps_video_parameter_set_id u(4)
h->sps_max_sub_layers_minus1 = bs_read(&s, 3); // sps_max_sub_layers_minus1 u(3)
if (h->sps_max_sub_layers_minus1 > 6)
{
log_print(HT_LOG_ERR, "%s, sps_max_sub_layers_minus1[%d]>6!!!\r\n",
__FUNCTION__, h->sps_max_sub_layers_minus1);
return -1;
}
bs_read(&s, 1); // sps_temporal_id_nesting_flag u(1)
// profile_tier_level( maxNumSubLayersMinus1 )
{
bs_read(&s, 2); // general_profile_space u(2)
bs_read(&s, 1); // general_tier_flag u(1)
h->general_profile_idc = bs_read(&s, 5); // general_profile_idc u(5)
bs_read(&s, 32); // general_profile_compatibility_flag[ j ] u(5)
bs_read(&s, 1); // general_progressive_source_flag u(1)
bs_read(&s, 1); // general_interlaced_source_flag u(1)
bs_read(&s, 1); // general_non_packed_constraint_flag u(1)
bs_read(&s, 1); // general_frame_only_constraint_flag u(1)
bs_skip(&s, 44); // general_reserved_zero_44bits u(44)
h->general_level_idc = bs_read(&s, 8); // general_level_idc u(8)
uint8 sub_layer_profile_present_flag[6] = {0};
uint8 sub_layer_level_present_flag[6] = {0};
for (i = 0; i < h->sps_max_sub_layers_minus1; i++)
{
sub_layer_profile_present_flag[i]= bs_read(&s, 1);
sub_layer_level_present_flag[i]= bs_read(&s, 1);
}
if (h->sps_max_sub_layers_minus1 > 0)
{
for (i = h->sps_max_sub_layers_minus1; i < 8; i++)
{
bs_read(&s, 2);
}
}
for (i = 0; i < h->sps_max_sub_layers_minus1; i++)
{
if (sub_layer_profile_present_flag[i])
{
bs_read(&s, 2); // sub_layer_profile_space[i]
bs_read(&s, 1); // sub_layer_tier_flag[i]
bs_read(&s, 5); // sub_layer_profile_idc[i]
bs_read(&s, 32); // sub_layer_profile_compatibility_flag[i][32]
bs_read(&s, 1); // sub_layer_progressive_source_flag[i]
bs_read(&s, 1); // sub_layer_interlaced_source_flag[i]
bs_read(&s, 1); // sub_layer_non_packed_constraint_flag[i]
bs_read(&s, 1); // sub_layer_frame_only_constraint_flag[i]
bs_read(&s, 44); // sub_layer_reserved_zero_44bits[i]
}
if (sub_layer_level_present_flag[i])
{
bs_read(&s, 8); // sub_layer_level_idc[i]
}
}
}
h->sps_seq_parameter_set_id = bs_read_ue(&s); // sps_seq_parameter_set_id ue(v)
h->chroma_format_idc = bs_read_ue(&s); // chroma_format_idc ue(v)
if (h->chroma_format_idc > 3)
{
log_print(HT_LOG_ERR, "%s, chroma_format_idc[%d]!!!\r\n",
__FUNCTION__, h->chroma_format_idc);
return -1;
}
if (h->chroma_format_idc == 3)
{
h->separate_colour_plane_flag = bs_read(&s, 1); // separate_colour_plane_flag
}
h->pic_width_in_luma_samples = bs_read_ue(&s); // pic_width_in_luma_samples ue(v)
h->pic_height_in_luma_samples = bs_read_ue(&s); // pic_height_in_luma_samples ue(v)
h->conformance_window_flag = bs_read(&s, 1 ); // conformance_window_flag u(1)
if (h->conformance_window_flag)
{
h->conf_win_left_offset = bs_read_ue(&s); // conf_win_left_offset ue(v)
h->conf_win_right_offset = bs_read_ue(&s); // conf_win_right_offset ue(v)
h->conf_win_top_offset = bs_read_ue(&s); // conf_win_top_offset ue(v)
h->conf_win_bottom_offset = bs_read_ue(&s); // conf_win_bottom_offset ue(v)
}
h->bit_depth_luma_minus8 = bs_read_ue(&s); // bit_depth_luma_minus8 ue(v)
h->bit_depth_chroma_minus8 = bs_read_ue(&s); // bit_depth_chroma_minus8 ue(v)
return 0;
}
void hvcc_init(HEVCDecoderConfigurationRecord * hvcc)
{
memset(hvcc, 0, sizeof(HEVCDecoderConfigurationRecord));
hvcc->lengthSizeMinusOne = 3; // 4 bytes
/*
* The following fields have all their valid bits set by default,
* the ProfileTierLevel parsing code will unset them when needed.
*/
hvcc->general_profile_compatibility_flags = 0xffffffff;
hvcc->general_constraint_indicator_flags = 0xffffffffffff;
/*
* Initialize this field with an invalid value which can be used to detect
* whether we didn't see any VUI (in which case it should be reset to zero).
*/
hvcc->min_spatial_segmentation_idc = MAX_SPATIAL_SEGMENTATION + 1;
}
int hvcc_parse_vps(HEVCDecoderConfigurationRecord * hvcc, uint8 * p_data, int len)
{
uint32 vps_max_sub_layers_minus1;
uint8 bufs[512];
bs_t s;
if (len > (int)sizeof(bufs))
{
return -1;
}
len = h265_extract_rbsp(p_data, len, bufs);
bs_init(&s, bufs, len);
/*
* vps_video_parameter_set_id u(4)
* vps_reserved_three_2bits u(2)
* vps_max_layers_minus1 u(6)
*/
bs_skip(&s, 12);
vps_max_sub_layers_minus1 = bs_read(&s, 3);
/*
* numTemporalLayers greater than 1 indicates that the stream to which this
* configuration record applies is temporally scalable and the contained
* number of temporal layers (also referred to as temporal sub-layer or
* sub-layer in ISO/IEC 23008-2) is equal to numTemporalLayers. Value 1
* indicates that the stream is not temporally scalable. Value 0 indicates
* that it is unknown whether the stream is temporally scalable.
*/
hvcc->numTemporalLayers = MAX(hvcc->numTemporalLayers, vps_max_sub_layers_minus1 + 1);
/*
* vps_temporal_id_nesting_flag u(1)
* vps_reserved_0xffff_16bits u(16)
*/
bs_skip(&s, 17);
uint8 profile_space;
uint8 tier_flag;
uint8 profile_idc;
uint32 profile_compatibility_flags;
uint64 constraint_indicator_flags;
uint8 level_idc;
profile_space = bs_read(&s, 2);
tier_flag = bs_read(&s, 1);
profile_idc = bs_read(&s, 5);
profile_compatibility_flags = bs_read(&s, 32);
constraint_indicator_flags = (uint64)bs_read(&s, 16) << 32;
constraint_indicator_flags |= bs_read(&s, 32);
level_idc = bs_read(&s, 8);
hvcc->general_profile_space = profile_space;
/*
* The level indication general_level_idc must indicate a level of
* capability equal to or greater than the highest level indicated for the
* highest tier in all the parameter sets.
*/
if (hvcc->general_tier_flag < tier_flag)
hvcc->general_level_idc = level_idc;
else
hvcc->general_level_idc = MAX(hvcc->general_level_idc, level_idc);
/*
* The tier indication general_tier_flag must indicate a tier equal to or
* greater than the highest tier indicated in all the parameter sets.
*/
hvcc->general_tier_flag = MAX(hvcc->general_tier_flag, tier_flag);
/*
* The profile indication general_profile_idc must indicate a profile to
* which the stream associated with this configuration record conforms.
*
* If the sequence parameter sets are marked with different profiles, then
* the stream may need examination to determine which profile, if any, the
* entire stream conforms to. If the entire stream is not examined, or the
* examination reveals that there is no profile to which the entire stream
* conforms, then the entire stream must be split into two or more
* sub-streams with separate configuration records in which these rules can
* be met.
*
* Note: set the profile to the highest value for the sake of simplicity.
*/
hvcc->general_profile_idc = MAX(hvcc->general_profile_idc, profile_idc);
/*
* Each bit in general_profile_compatibility_flags may only be set if all
* the parameter sets set that bit.
*/
hvcc->general_profile_compatibility_flags &= profile_compatibility_flags;
/*
* Each bit in general_constraint_indicator_flags may only be set if all
* the parameter sets set that bit.
*/
hvcc->general_constraint_indicator_flags &= constraint_indicator_flags;
/* nothing useful for hvcC past this point */
return 0;
}
int hvcc_parse_pps(HEVCDecoderConfigurationRecord * hvcc, uint8 * p_data, int len)
{
uint8 tiles_enabled_flag, entropy_coding_sync_enabled_flag;
uint8 bufs[512];
bs_t s;
if (len > (int)sizeof(bufs))
{
return -1;
}
len = h265_extract_rbsp(p_data, len, bufs);
bs_init(&s, bufs, len);
bs_read_ue(&s); // pps_pic_parameter_set_id
bs_read_ue(&s); // pps_seq_parameter_set_id
/*
* dependent_slice_segments_enabled_flag u(1)
* output_flag_present_flag u(1)
* num_extra_slice_header_bits u(3)
* sign_data_hiding_enabled_flag u(1)
* cabac_init_present_flag u(1)
*/
bs_skip(&s, 7);
bs_read_ue(&s); // num_ref_idx_l0_default_active_minus1
bs_read_ue(&s); // num_ref_idx_l1_default_active_minus1
bs_read_se(&s); // init_qp_minus26
/*
* constrained_intra_pred_flag u(1)
* transform_skip_enabled_flag u(1)
*/
bs_skip(&s, 2);
if (bs_read(&s, 1)) // cu_qp_delta_enabled_flag
bs_read_ue(&s); // diff_cu_qp_delta_depth
bs_read_se(&s); // pps_cb_qp_offset
bs_read_se(&s); // pps_cr_qp_offset
/*
* pps_slice_chroma_qp_offsets_present_flag u(1)
* weighted_pred_flag u(1)
* weighted_bipred_flag u(1)
* transquant_bypass_enabled_flag u(1)
*/
bs_skip(&s, 4);
tiles_enabled_flag = bs_read(&s, 1);
entropy_coding_sync_enabled_flag = bs_read(&s, 1);
if (entropy_coding_sync_enabled_flag && tiles_enabled_flag)
hvcc->parallelismType = 0; // mixed-type parallel decoding
else if (entropy_coding_sync_enabled_flag)
hvcc->parallelismType = 3; // wavefront-based parallel decoding
else if (tiles_enabled_flag)
hvcc->parallelismType = 2; // tile-based parallel decoding
else
hvcc->parallelismType = 1; // slice-based parallel decoding
/* nothing useful for hvcC past this point */
return 0;
}