123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- package h264
- import (
- "fmt"
- "github.com/AlexxIT/go2rtc/pkg/bits"
- )
- // http://www.itu.int/rec/T-REC-H.264
- // https://webrtc.googlesource.com/src/+/refs/heads/main/common_video/h264/sps_parser.cc
- //goland:noinspection GoSnakeCaseUsage
- type SPS struct {
- profile_idc uint8
- profile_iop uint8
- level_idc uint8
- seq_parameter_set_id uint32
- chroma_format_idc uint32
- separate_colour_plane_flag byte
- bit_depth_luma_minus8 uint32
- bit_depth_chroma_minus8 uint32
- qpprime_y_zero_transform_bypass_flag byte
- seq_scaling_matrix_present_flag byte
- log2_max_frame_num_minus4 uint32
- pic_order_cnt_type uint32
- log2_max_pic_order_cnt_lsb_minus4 uint32
- delta_pic_order_always_zero_flag byte
- offset_for_non_ref_pic int32
- offset_for_top_to_bottom_field int32
- num_ref_frames_in_pic_order_cnt_cycle uint32
- num_ref_frames uint32
- gaps_in_frame_num_value_allowed_flag byte
- pic_width_in_mbs_minus_1 uint32
- pic_height_in_map_units_minus_1 uint32
- frame_mbs_only_flag byte
- mb_adaptive_frame_field_flag byte
- direct_8x8_inference_flag byte
- frame_cropping_flag byte
- frame_crop_left_offset uint32
- frame_crop_right_offset uint32
- frame_crop_top_offset uint32
- frame_crop_bottom_offset uint32
- vui_parameters_present_flag byte
- aspect_ratio_info_present_flag byte
- aspect_ratio_idc byte
- sar_width uint16
- sar_height uint16
- overscan_info_present_flag byte
- overscan_appropriate_flag byte
- video_signal_type_present_flag byte
- video_format uint8
- video_full_range_flag byte
- colour_description_present_flag byte
- colour_description uint32
- chroma_loc_info_present_flag byte
- chroma_sample_loc_type_top_field uint32
- chroma_sample_loc_type_bottom_field uint32
- timing_info_present_flag byte
- num_units_in_tick uint32
- time_scale uint32
- fixed_frame_rate_flag byte
- }
- func (s *SPS) Width() uint16 {
- width := 16 * (s.pic_width_in_mbs_minus_1 + 1)
- crop := 2 * (s.frame_crop_left_offset + s.frame_crop_right_offset)
- return uint16(width - crop)
- }
- func (s *SPS) Height() uint16 {
- height := 16 * (s.pic_height_in_map_units_minus_1 + 1)
- crop := 2 * (s.frame_crop_top_offset + s.frame_crop_bottom_offset)
- if s.frame_mbs_only_flag == 0 {
- height *= 2
- }
- return uint16(height - crop)
- }
- func DecodeSPS(sps []byte) *SPS {
- r := bits.NewReader(sps)
- hdr := r.ReadByte()
- if hdr&0x1F != NALUTypeSPS {
- return nil
- }
- s := &SPS{
- profile_idc: r.ReadByte(),
- profile_iop: r.ReadByte(),
- level_idc: r.ReadByte(),
- seq_parameter_set_id: r.ReadUEGolomb(),
- }
- switch s.profile_idc {
- case 100, 110, 122, 244, 44, 83, 86, 118, 128, 138, 139, 134, 135:
- n := byte(8)
- s.chroma_format_idc = r.ReadUEGolomb()
- if s.chroma_format_idc == 3 {
- s.separate_colour_plane_flag = r.ReadBit()
- n = 12
- }
- s.bit_depth_luma_minus8 = r.ReadUEGolomb()
- s.bit_depth_chroma_minus8 = r.ReadUEGolomb()
- s.qpprime_y_zero_transform_bypass_flag = r.ReadBit()
- s.seq_scaling_matrix_present_flag = r.ReadBit()
- if s.seq_scaling_matrix_present_flag != 0 {
- for i := byte(0); i < n; i++ {
- //goland:noinspection GoSnakeCaseUsage
- seq_scaling_list_present_flag := r.ReadBit()
- if seq_scaling_list_present_flag != 0 {
- if i < 6 {
- s.scaling_list(r, 16)
- } else {
- s.scaling_list(r, 64)
- }
- }
- }
- }
- }
- s.log2_max_frame_num_minus4 = r.ReadUEGolomb()
- s.pic_order_cnt_type = r.ReadUEGolomb()
- switch s.pic_order_cnt_type {
- case 0:
- s.log2_max_pic_order_cnt_lsb_minus4 = r.ReadUEGolomb()
- case 1:
- s.delta_pic_order_always_zero_flag = r.ReadBit()
- s.offset_for_non_ref_pic = r.ReadSEGolomb()
- s.offset_for_top_to_bottom_field = r.ReadSEGolomb()
- s.num_ref_frames_in_pic_order_cnt_cycle = r.ReadUEGolomb()
- for i := uint32(0); i < s.num_ref_frames_in_pic_order_cnt_cycle; i++ {
- _ = r.ReadSEGolomb() // offset_for_ref_frame[i]
- }
- }
- s.num_ref_frames = r.ReadUEGolomb()
- s.gaps_in_frame_num_value_allowed_flag = r.ReadBit()
- s.pic_width_in_mbs_minus_1 = r.ReadUEGolomb()
- s.pic_height_in_map_units_minus_1 = r.ReadUEGolomb()
- s.frame_mbs_only_flag = r.ReadBit()
- if s.frame_mbs_only_flag == 0 {
- s.mb_adaptive_frame_field_flag = r.ReadBit()
- }
- s.direct_8x8_inference_flag = r.ReadBit()
- s.frame_cropping_flag = r.ReadBit()
- if s.frame_cropping_flag != 0 {
- s.frame_crop_left_offset = r.ReadUEGolomb()
- s.frame_crop_right_offset = r.ReadUEGolomb()
- s.frame_crop_top_offset = r.ReadUEGolomb()
- s.frame_crop_bottom_offset = r.ReadUEGolomb()
- }
- s.vui_parameters_present_flag = r.ReadBit()
- if s.vui_parameters_present_flag != 0 {
- s.aspect_ratio_info_present_flag = r.ReadBit()
- if s.aspect_ratio_info_present_flag != 0 {
- s.aspect_ratio_idc = r.ReadByte()
- if s.aspect_ratio_idc == 255 {
- s.sar_width = r.ReadUint16()
- s.sar_height = r.ReadUint16()
- }
- }
- s.overscan_info_present_flag = r.ReadBit()
- if s.overscan_info_present_flag != 0 {
- s.overscan_appropriate_flag = r.ReadBit()
- }
- s.video_signal_type_present_flag = r.ReadBit()
- if s.video_signal_type_present_flag != 0 {
- s.video_format = r.ReadBits8(3)
- s.video_full_range_flag = r.ReadBit()
- s.colour_description_present_flag = r.ReadBit()
- if s.colour_description_present_flag != 0 {
- s.colour_description = r.ReadUint24()
- }
- }
- s.chroma_loc_info_present_flag = r.ReadBit()
- if s.chroma_loc_info_present_flag != 0 {
- s.chroma_sample_loc_type_top_field = r.ReadUEGolomb()
- s.chroma_sample_loc_type_bottom_field = r.ReadUEGolomb()
- }
- s.timing_info_present_flag = r.ReadBit()
- if s.timing_info_present_flag != 0 {
- s.num_units_in_tick = r.ReadUint32()
- s.time_scale = r.ReadUint32()
- s.fixed_frame_rate_flag = r.ReadBit()
- }
- //...
- }
- if r.EOF {
- return nil
- }
- return s
- }
- //goland:noinspection GoSnakeCaseUsage
- func (s *SPS) scaling_list(r *bits.Reader, sizeOfScalingList int) {
- lastScale := int32(8)
- nextScale := int32(8)
- for j := 0; j < sizeOfScalingList; j++ {
- if nextScale != 0 {
- delta_scale := r.ReadSEGolomb()
- nextScale = (lastScale + delta_scale + 256) % 256
- }
- if nextScale != 0 {
- lastScale = nextScale
- }
- }
- }
- func (s *SPS) Profile() string {
- switch s.profile_idc {
- case 0x42:
- return "Baseline"
- case 0x4D:
- return "Main"
- case 0x58:
- return "Extended"
- case 0x64:
- return "High"
- }
- return fmt.Sprintf("0x%02X", s.profile_idc)
- }
- func (s *SPS) PixFmt() string {
- if s.bit_depth_luma_minus8 == 0 {
- switch s.chroma_format_idc {
- case 1:
- if s.video_full_range_flag == 1 {
- return "yuvj420p"
- }
- return "yuv420p"
- case 2:
- return "yuv422p"
- case 3:
- return "yuv444p"
- }
- }
- return ""
- }
- func (s *SPS) String() string {
- return fmt.Sprintf(
- "%s %d.%d, %s, %dx%d",
- s.Profile(), s.level_idc/10, s.level_idc%10, s.PixFmt(), s.Width(), s.Height(),
- )
- }
- // FixPixFmt - change yuvj420p to yuv420p in SPS
- // same as "-c:v copy -bsf:v h264_metadata=video_full_range_flag=0"
- func FixPixFmt(sps []byte) {
- r := bits.NewReader(sps)
- _ = r.ReadByte()
- profile := r.ReadByte()
- _ = r.ReadByte()
- _ = r.ReadByte()
- _ = r.ReadUEGolomb()
- switch profile {
- case 100, 110, 122, 244, 44, 83, 86, 118, 128, 138, 139, 134, 135:
- n := byte(8)
- if r.ReadUEGolomb() == 3 {
- _ = r.ReadBit()
- n = 12
- }
- _ = r.ReadUEGolomb()
- _ = r.ReadUEGolomb()
- _ = r.ReadBit()
- if r.ReadBit() != 0 {
- for i := byte(0); i < n; i++ {
- if r.ReadBit() != 0 {
- return // skip
- }
- }
- }
- }
- _ = r.ReadUEGolomb()
- switch r.ReadUEGolomb() {
- case 0:
- _ = r.ReadUEGolomb()
- case 1:
- _ = r.ReadBit()
- _ = r.ReadSEGolomb()
- _ = r.ReadSEGolomb()
- n := r.ReadUEGolomb()
- for i := uint32(0); i < n; i++ {
- _ = r.ReadSEGolomb()
- }
- }
- _ = r.ReadUEGolomb()
- _ = r.ReadBit()
- _ = r.ReadUEGolomb()
- _ = r.ReadUEGolomb()
- if r.ReadBit() == 0 {
- _ = r.ReadBit()
- }
- _ = r.ReadBit()
- if r.ReadBit() != 0 {
- _ = r.ReadUEGolomb()
- _ = r.ReadUEGolomb()
- _ = r.ReadUEGolomb()
- _ = r.ReadUEGolomb()
- }
- if r.ReadBit() != 0 {
- if r.ReadBit() != 0 {
- if r.ReadByte() == 255 {
- _ = r.ReadUint16()
- _ = r.ReadUint16()
- }
- }
- if r.ReadBit() != 0 {
- _ = r.ReadBit()
- }
- if r.ReadBit() != 0 {
- _ = r.ReadBits8(3)
- if r.ReadBit() == 1 {
- pos, bit := r.Pos()
- sps[pos] &= ^byte(1 << bit)
- }
- }
- }
- }
|