mirror of
https://github.com/wader/fq.git
synced 2024-12-26 23:15:04 +03:00
333 lines
12 KiB
Go
333 lines
12 KiB
Go
package mpeg
|
|
|
|
// https://www.itu.int/rec/T-REC-H.265
|
|
|
|
import (
|
|
"github.com/wader/fq/format"
|
|
"github.com/wader/fq/pkg/decode"
|
|
"github.com/wader/fq/pkg/interp"
|
|
)
|
|
|
|
func init() {
|
|
interp.RegisterFormat(decode.Format{
|
|
Name: format.HEVC_SPS,
|
|
Description: "H.265/HEVC Sequence Parameter Set",
|
|
DecodeFn: hevcSPSDecode,
|
|
})
|
|
}
|
|
|
|
func profileLayerDecode(d *decode.D, prefix string, profilePresent bool, levelPresent bool, isSublayer bool) {
|
|
if profilePresent {
|
|
d.FieldU2(prefix + "profile_space")
|
|
d.FieldU1(prefix + "tier_flag")
|
|
generalProfileIdc := d.FieldU5(prefix + "profile_idc")
|
|
var generalProfileCompatibilityFlags [32]bool
|
|
d.FieldArray(prefix+"profile_compatibility_flags", func(d *decode.D) {
|
|
for j := 0; j < 32; j++ {
|
|
generalProfileCompatibilityFlags[j] = d.FieldBool(prefix + "profile_compatibility_flag")
|
|
}
|
|
})
|
|
d.FieldBool(prefix + "progressive_source_flag")
|
|
d.FieldBool(prefix + "interlaced_source_flag")
|
|
d.FieldBool(prefix + "non_packed_constraint_flag")
|
|
d.FieldBool(prefix + "frame_only_constraint_flag")
|
|
if generalProfileIdc == 4 || generalProfileCompatibilityFlags[4] ||
|
|
generalProfileIdc == 5 || generalProfileCompatibilityFlags[5] ||
|
|
generalProfileIdc == 6 || generalProfileCompatibilityFlags[6] ||
|
|
generalProfileIdc == 7 || generalProfileCompatibilityFlags[7] ||
|
|
generalProfileIdc == 8 || generalProfileCompatibilityFlags[8] ||
|
|
generalProfileIdc == 9 || generalProfileCompatibilityFlags[9] ||
|
|
generalProfileIdc == 10 || generalProfileCompatibilityFlags[10] {
|
|
d.FieldBool(prefix + "max_12bit_constraint_flag")
|
|
d.FieldBool(prefix + "max_10bit_constraint_flag")
|
|
d.FieldBool(prefix + "max_8bit_constraint_flag")
|
|
d.FieldBool(prefix + "max_422chroma_constraint_flag")
|
|
d.FieldBool(prefix + "max_420chroma_constraint_flag")
|
|
d.FieldBool(prefix + "max_monochrome_constraint_flag")
|
|
d.FieldBool(prefix + "intra_constraint_flag")
|
|
d.FieldBool(prefix + "one_picture_only_constraint_flag")
|
|
d.FieldBool(prefix + "lower_bit_rate_constraint_flag")
|
|
if generalProfileIdc == 5 || generalProfileCompatibilityFlags[5] ||
|
|
(!isSublayer &&
|
|
(generalProfileIdc == 9 || generalProfileCompatibilityFlags[9] ||
|
|
generalProfileIdc == 10 || generalProfileCompatibilityFlags[10])) {
|
|
d.FieldBool(prefix + "max_14bit_constraint_flag")
|
|
d.FieldU33(prefix + "reserved_zero_33bits")
|
|
} else {
|
|
d.FieldU34(prefix + "reserved_zero_34bits")
|
|
}
|
|
} else {
|
|
d.FieldU43(prefix + "reserved_zero_43bits")
|
|
}
|
|
if (generalProfileIdc >= 1 && generalProfileIdc <= 5) ||
|
|
generalProfileIdc == 9 ||
|
|
generalProfileCompatibilityFlags[1] || generalProfileCompatibilityFlags[2] ||
|
|
generalProfileCompatibilityFlags[3] || generalProfileCompatibilityFlags[4] ||
|
|
generalProfileCompatibilityFlags[5] || generalProfileCompatibilityFlags[9] {
|
|
d.FieldBool(prefix + "inbld_flag")
|
|
} else {
|
|
d.FieldBool(prefix + "reserved_zero_bit")
|
|
}
|
|
}
|
|
if levelPresent {
|
|
d.FieldU8(prefix + "level_idc")
|
|
}
|
|
}
|
|
|
|
// H.265 page 41
|
|
func profileTierLevelDecode(d *decode.D, profilePresentFlag bool, maxNumSubLayersMinus1 uint64) {
|
|
profileLayerDecode(d, "general_", profilePresentFlag, true, false)
|
|
subLayerProfilePresentFlags := make([]bool, maxNumSubLayersMinus1)
|
|
subLayerLevelPresentFlags := make([]bool, maxNumSubLayersMinus1)
|
|
d.FieldArray("sub_layer_presents", func(d *decode.D) {
|
|
for i := uint64(0); i < maxNumSubLayersMinus1; i++ {
|
|
d.FieldStruct("sub_layer_present", func(d *decode.D) {
|
|
subLayerProfilePresentFlags[i] = d.FieldBool("sub_layer_profile_present_flag")
|
|
subLayerLevelPresentFlags[i] = d.FieldBool("sub_layer_level_present_flag")
|
|
})
|
|
}
|
|
})
|
|
if maxNumSubLayersMinus1 > 0 {
|
|
for i := maxNumSubLayersMinus1; i < 8; i++ {
|
|
d.FieldArray("reserved_zero_2bits", func(d *decode.D) {
|
|
d.FieldU33("reserved_zero_2bits")
|
|
})
|
|
}
|
|
}
|
|
d.FieldArray("sub_layers", func(d *decode.D) {
|
|
for i := uint64(0); i < maxNumSubLayersMinus1; i++ {
|
|
d.FieldStruct("sub_layer", func(d *decode.D) {
|
|
profileLayerDecode(d, "", subLayerProfilePresentFlags[i], subLayerProfilePresentFlags[i], true)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func hevcSubLayerHrdParameters(d *decode.D, subPicHrdParamsPresentFlag bool, cpbCntMinus1 int) {
|
|
for i := 0; i <= cpbCntMinus1; i++ {
|
|
d.FieldStruct("parameters", func(d *decode.D) {
|
|
d.FieldUFn("bit_rate_value_minus1", uEV)
|
|
d.FieldUFn("cpb_size_value_minus1", uEV)
|
|
if subPicHrdParamsPresentFlag {
|
|
d.FieldUFn("cpb_size_du_value_minus1", uEV)
|
|
d.FieldUFn("bit_rate_du_value_minus1", uEV)
|
|
}
|
|
d.FieldBool("cbr_flag")
|
|
})
|
|
}
|
|
}
|
|
|
|
func hevcHrdParameters(d *decode.D, commonInfPresentFlag bool, maxNumSubLayersMinus1 uint64) {
|
|
var nalHrdParametersPresentFlag bool
|
|
var vclHrdParametersPresentFlag bool
|
|
var subPicHrdParamsPresentFlag bool
|
|
if commonInfPresentFlag {
|
|
nalHrdParametersPresentFlag = d.FieldBool("nal_hrd_parameters_present_flag")
|
|
vclHrdParametersPresentFlag = d.FieldBool("vcl_hrd_parameters_present_flag")
|
|
if nalHrdParametersPresentFlag && vclHrdParametersPresentFlag {
|
|
subPicHrdParamsPresentFlag = d.FieldBool("sub_pic_hrd_params_present_flag")
|
|
if subPicHrdParamsPresentFlag {
|
|
d.FieldU8("tick_divisor_minus2")
|
|
d.FieldU5("sar_wdu_cpb_removal_delay_increment_length_minus1idth")
|
|
d.FieldBool("sub_pic_cpb_params_in_pic_timing_sei_flag")
|
|
d.FieldU5("dpb_output_delay_du_length_minus1")
|
|
}
|
|
d.FieldU8("tick_divisor_minus2")
|
|
d.FieldU8("tick_divisor_minus2")
|
|
if subPicHrdParamsPresentFlag {
|
|
d.FieldU4("cpb_size_du_scale")
|
|
}
|
|
d.FieldU5("initial_cpb_removal_delay_length_minus1")
|
|
d.FieldU5("au_cpb_removal_delay_length_minus1")
|
|
d.FieldU5("dpb_output_delay_length_minus1")
|
|
}
|
|
}
|
|
d.FieldArray("sub_layers", func(d *decode.D) {
|
|
for i := uint64(0); i < maxNumSubLayersMinus1; i++ {
|
|
d.FieldStruct("sub_layer", func(d *decode.D) {
|
|
fixedPicRateGeneralFlag := d.FieldBool("fixed_pic_rate_general_flag")
|
|
var fixedPicRateWithinCvsFlag bool
|
|
if !fixedPicRateGeneralFlag {
|
|
fixedPicRateWithinCvsFlag = d.FieldBool("fixed_pic_rate_within_cvs_flag")
|
|
}
|
|
var lowDelayHrdFlag bool
|
|
if fixedPicRateWithinCvsFlag {
|
|
d.FieldUFn("elemental_duration_in_tc_minus1", uEV)
|
|
} else {
|
|
lowDelayHrdFlag = d.FieldBool("low_delay_hrd_flag")
|
|
}
|
|
var cpbCntMinus1 int
|
|
if !lowDelayHrdFlag {
|
|
cpbCntMinus1 = int(d.FieldUFn("cpb_cnt_minus1", uEV))
|
|
}
|
|
if nalHrdParametersPresentFlag {
|
|
hevcSubLayerHrdParameters(d, subPicHrdParamsPresentFlag, cpbCntMinus1)
|
|
}
|
|
if vclHrdParametersPresentFlag {
|
|
hevcSubLayerHrdParameters(d, subPicHrdParamsPresentFlag, cpbCntMinus1)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func hevcVuiParameters(d *decode.D, spsMaxSubLayersMinus1 uint64) {
|
|
aspectRatioInfoPresentFlag := d.FieldBool("aspect_ratio_info_present_flag")
|
|
if aspectRatioInfoPresentFlag {
|
|
aspectRatioIdc := d.FieldU8("aspect_ratio_idc", avcAspectRatioIdcMap)
|
|
const extendedSAR = 255
|
|
if aspectRatioIdc == extendedSAR {
|
|
d.FieldU16("sar_width")
|
|
d.FieldU16("sar_height")
|
|
}
|
|
}
|
|
overscanInfoPresentFlag := d.FieldBool("overscan_info_present_flag")
|
|
if overscanInfoPresentFlag {
|
|
d.FieldBool("overscan_appropriate_flag")
|
|
}
|
|
videoSignalTypePresentFlag := d.FieldBool("video_signal_type_present_flag")
|
|
if videoSignalTypePresentFlag {
|
|
d.FieldU3("video_format", avcVideoFormatMap)
|
|
d.FieldBool("video_full_range_flag")
|
|
colourDescriptionPresentFlag := d.FieldBool("colour_description_present_flag")
|
|
if colourDescriptionPresentFlag {
|
|
d.FieldU8("colour_primaries", format.ISO_23091_2_ColourPrimariesMap)
|
|
d.FieldU8("transfer_characteristics", format.ISO_23091_2_TransferCharacteristicMap)
|
|
d.FieldU8("matrix_coefficients", format.ISO_23091_2_MatrixCoefficients)
|
|
}
|
|
}
|
|
chromaLocInfoPresentFlag := d.FieldBool("chroma_loc_info_present_flag")
|
|
if chromaLocInfoPresentFlag {
|
|
d.FieldUFn("chroma_sample_loc_type_top_field", uEV)
|
|
d.FieldUFn("chroma_sample_loc_type_bottom_field", uEV)
|
|
}
|
|
|
|
d.FieldBool("neutral_chroma_indication_flag")
|
|
d.FieldBool("field_seq_flag")
|
|
d.FieldBool("frame_field_info_present_flag")
|
|
defaultDisplayWindowFlag := d.FieldBool("default_display_window_flag")
|
|
if defaultDisplayWindowFlag {
|
|
d.FieldUFn("def_disp_win_left_offset", uEV)
|
|
d.FieldUFn("def_disp_win_right_offset", uEV)
|
|
d.FieldUFn("def_disp_win_top_offset", uEV)
|
|
d.FieldUFn("def_disp_win_bottom_offset", uEV)
|
|
}
|
|
|
|
vuiTimingInfoPresentFlag := d.FieldBool("vui_timing_info_present_flag")
|
|
if vuiTimingInfoPresentFlag {
|
|
d.FieldU32("vui_num_units_in_tick")
|
|
d.FieldU32("vui_time_scale")
|
|
vuiPocProportionalToTimingFlag := d.FieldBool("vui_poc_proportional_to_timing_flag")
|
|
if vuiPocProportionalToTimingFlag {
|
|
d.FieldUFn("vui_num_ticks_poc_diff_one_minus1", uEV)
|
|
}
|
|
vuiHrdParametersPresentFlag := d.FieldBool("vui_hrd_parameters_present_flag")
|
|
if vuiHrdParametersPresentFlag {
|
|
hevcHrdParameters(d, true, spsMaxSubLayersMinus1)
|
|
}
|
|
}
|
|
|
|
bitstreamRestrictionFlag := d.FieldBool("bitstream_restriction_flag")
|
|
if bitstreamRestrictionFlag {
|
|
d.FieldBool("tiles_fixed_structure_flag")
|
|
d.FieldBool("motion_vectors_over_pic_boundaries_flag")
|
|
d.FieldBool("restricted_ref_pic_lists_flag")
|
|
d.FieldUFn("min_spatial_segmentation_idc", uEV)
|
|
d.FieldUFn("max_bytes_per_pic_denom", uEV)
|
|
d.FieldUFn("max_bits_per_min_cu_denom", uEV)
|
|
d.FieldUFn("log2_max_mv_length_horizontal", uEV)
|
|
d.FieldUFn("log2_max_mv_length_vertical", uEV)
|
|
}
|
|
}
|
|
|
|
// H.265 page 34
|
|
func hevcSPSDecode(d *decode.D, _ any) any {
|
|
d.FieldU4("sps_video_parameter_set_id")
|
|
spsMaxSubLayersMinus1 := d.FieldU3("sps_max_sub_layers_minus1")
|
|
d.FieldBool("sps_temporal_id_nesting_flag")
|
|
profileTierLevelDecode(d, true, spsMaxSubLayersMinus1)
|
|
d.FieldUFn("sps_seq_parameter_set_id", uEV)
|
|
chromaFormatIdc := d.FieldUFn("chroma_format_idc", uEV, chromaFormatMap)
|
|
if chromaFormatIdc == 3 {
|
|
d.FieldBool("separate_colour_plane_flag")
|
|
}
|
|
d.FieldUFn("pic_width_in_luma_samples", uEV)
|
|
d.FieldUFn("pic_height_in_luma_samples", uEV)
|
|
conformanceWindowFlag := d.FieldBool("conformance_window_flag")
|
|
if conformanceWindowFlag {
|
|
d.FieldUFn("conf_win_left_offset", uEV)
|
|
d.FieldUFn("conf_win_right_offset", uEV)
|
|
d.FieldUFn("conf_win_top_offset", uEV)
|
|
d.FieldUFn("conf_win_bottom_offset", uEV)
|
|
}
|
|
d.FieldUFn("bit_depth_luma_minus8", uEV)
|
|
d.FieldUFn("bit_depth_chroma_minus8", uEV)
|
|
d.FieldUFn("log2_max_pic_order_cnt_lsb_minus4", uEV)
|
|
spsSubLayerOrderingInfoPresentFlag := d.FieldBool("sps_sub_layer_ordering_info_present_flag")
|
|
d.FieldArray("sps_sub_layer_ordering_infos", func(d *decode.D) {
|
|
i := spsMaxSubLayersMinus1
|
|
if spsSubLayerOrderingInfoPresentFlag {
|
|
i = 0
|
|
}
|
|
for ; i <= spsMaxSubLayersMinus1; i++ {
|
|
d.FieldStruct("sps_sub_layer_ordering_info", func(d *decode.D) {
|
|
d.FieldUFn("sps_max_dec_pic_buffering_minus1", uEV)
|
|
d.FieldUFn("sps_max_num_reorder_pics", uEV)
|
|
d.FieldUFn("sps_max_latency_increase_plus1", uEV)
|
|
})
|
|
}
|
|
})
|
|
d.FieldUFn("log2_min_luma_coding_block_size_minus3", uEV)
|
|
d.FieldUFn("log2_diff_max_min_luma_coding_block_size", uEV)
|
|
d.FieldUFn("log2_min_luma_transform_block_size_minus2", uEV)
|
|
d.FieldUFn("log2_diff_max_min_luma_transform_block_size", uEV)
|
|
d.FieldUFn("max_transform_hierarchy_depth_inter", uEV)
|
|
d.FieldUFn("max_transform_hierarchy_depth_intra", uEV)
|
|
scalingListEnabledFlag := d.FieldBool("scaling_list_enabled_flag")
|
|
if scalingListEnabledFlag {
|
|
spsScalingListDataPresentFlag := d.FieldBool("sps_scaling_list_data_present_flag")
|
|
if spsScalingListDataPresentFlag {
|
|
// TODO: scaling_list_data
|
|
return nil
|
|
}
|
|
}
|
|
d.FieldBool("amp_enabled_flag")
|
|
d.FieldBool("sample_adaptive_offset_enabled_flag")
|
|
pcmEnabledFlag := d.FieldBool("pcm_enabled_flag")
|
|
if pcmEnabledFlag {
|
|
d.FieldU4("pcm_sample_bit_depth_luma_minus1")
|
|
d.FieldU4("pcm_sample_bit_depth_chroma_minus1")
|
|
d.FieldUFn("log2_min_pcm_luma_coding_block_size_minus3", uEV)
|
|
d.FieldUFn("log2_diff_max_min_pcm_luma_coding_block_size", uEV)
|
|
d.FieldBool("pcm_loop_filter_disabled_flag")
|
|
}
|
|
numShortTermRefPicSets := d.FieldUFn("num_short_term_ref_pic_sets", uEV)
|
|
if numShortTermRefPicSets > 0 {
|
|
// TODO
|
|
return nil
|
|
}
|
|
longTermRefPicsPresentFlag := d.FieldBool("long_term_ref_pics_present_flag")
|
|
if longTermRefPicsPresentFlag {
|
|
// TODO
|
|
return nil
|
|
}
|
|
d.FieldBool("sps_temporal_mvp_enabled_flag")
|
|
d.FieldBool("strong_intra_smoothing_enabled_flag")
|
|
vuiParametersPresentFlag := d.FieldBool("vui_parameters_present_flag")
|
|
if vuiParametersPresentFlag {
|
|
d.FieldStruct("vui_parameters", func(d *decode.D) { hevcVuiParameters(d, spsMaxSubLayersMinus1) })
|
|
}
|
|
spsExtensionPresentFlag := d.FieldBool("sps_extension_present_flag")
|
|
if spsExtensionPresentFlag {
|
|
d.FieldU1("sps_range_extension_flag")
|
|
d.FieldU1("sps_multilayer_extension_flag")
|
|
d.FieldU1("sps_3d_extension_flag")
|
|
d.FieldU1("sps_scc_extension_flag")
|
|
d.FieldU4("sps_extension_4bits")
|
|
}
|
|
|
|
// TODO
|
|
|
|
return nil
|
|
}
|