mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2025-09-27 04:36:12 +08:00
127 lines
3.0 KiB
Go
127 lines
3.0 KiB
Go
package h265
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"github.com/AlexxIT/go2rtc/pkg/bits"
|
|
)
|
|
|
|
// http://www.itu.int/rec/T-REC-H.265
|
|
|
|
//goland:noinspection GoSnakeCaseUsage
|
|
type SPS struct {
|
|
sps_video_parameter_set_id uint8
|
|
sps_max_sub_layers_minus1 uint8
|
|
sps_temporal_id_nesting_flag byte
|
|
|
|
general_profile_space uint8
|
|
general_tier_flag byte
|
|
general_profile_idc uint8
|
|
general_profile_compatibility_flags uint32
|
|
|
|
general_level_idc uint8
|
|
sub_layer_profile_present_flag []byte
|
|
sub_layer_level_present_flag []byte
|
|
|
|
sps_seq_parameter_set_id uint32
|
|
chroma_format_idc uint32
|
|
separate_colour_plane_flag byte
|
|
|
|
pic_width_in_luma_samples uint32
|
|
pic_height_in_luma_samples uint32
|
|
}
|
|
|
|
func (s *SPS) Width() uint16 {
|
|
return uint16(s.pic_width_in_luma_samples)
|
|
}
|
|
|
|
func (s *SPS) Height() uint16 {
|
|
return uint16(s.pic_height_in_luma_samples)
|
|
}
|
|
|
|
func DecodeSPS(nalu []byte) *SPS {
|
|
rbsp := bytes.ReplaceAll(nalu[2:], []byte{0, 0, 3}, []byte{0, 0})
|
|
|
|
r := bits.NewReader(rbsp)
|
|
s := &SPS{}
|
|
|
|
s.sps_video_parameter_set_id = r.ReadBits8(4)
|
|
s.sps_max_sub_layers_minus1 = r.ReadBits8(3)
|
|
s.sps_temporal_id_nesting_flag = r.ReadBit()
|
|
|
|
if !s.profile_tier_level(r) {
|
|
return nil
|
|
}
|
|
|
|
s.sps_seq_parameter_set_id = r.ReadUEGolomb()
|
|
s.chroma_format_idc = r.ReadUEGolomb()
|
|
if s.chroma_format_idc == 3 {
|
|
s.separate_colour_plane_flag = r.ReadBit()
|
|
}
|
|
|
|
s.pic_width_in_luma_samples = r.ReadUEGolomb()
|
|
s.pic_height_in_luma_samples = r.ReadUEGolomb()
|
|
|
|
//...
|
|
|
|
if r.EOF {
|
|
return nil
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
// profile_tier_level supports ONLY general_profile_idc == 1
|
|
// over variants very complicated...
|
|
//
|
|
//goland:noinspection GoSnakeCaseUsage
|
|
func (s *SPS) profile_tier_level(r *bits.Reader) bool {
|
|
s.general_profile_space = r.ReadBits8(2)
|
|
s.general_tier_flag = r.ReadBit()
|
|
s.general_profile_idc = r.ReadBits8(5)
|
|
|
|
s.general_profile_compatibility_flags = r.ReadBits(32)
|
|
_ = r.ReadBits64(48) // other flags
|
|
|
|
if s.general_profile_idc != 1 {
|
|
return false
|
|
}
|
|
|
|
s.general_level_idc = r.ReadBits8(8)
|
|
|
|
s.sub_layer_profile_present_flag = make([]byte, s.sps_max_sub_layers_minus1)
|
|
s.sub_layer_level_present_flag = make([]byte, s.sps_max_sub_layers_minus1)
|
|
|
|
for i := byte(0); i < s.sps_max_sub_layers_minus1; i++ {
|
|
s.sub_layer_profile_present_flag[i] = r.ReadBit()
|
|
s.sub_layer_level_present_flag[i] = r.ReadBit()
|
|
}
|
|
|
|
if s.sps_max_sub_layers_minus1 > 0 {
|
|
for i := s.sps_max_sub_layers_minus1; i < 8; i++ {
|
|
_ = r.ReadBits8(2) // reserved_zero_2bits
|
|
}
|
|
}
|
|
|
|
for i := byte(0); i < s.sps_max_sub_layers_minus1; i++ {
|
|
if s.sub_layer_profile_present_flag[i] != 0 {
|
|
_ = r.ReadBits8(2) // sub_layer_profile_space
|
|
_ = r.ReadBit() // sub_layer_tier_flag
|
|
sub_layer_profile_idc := r.ReadBits8(5) // sub_layer_profile_idc
|
|
|
|
_ = r.ReadBits(32) // sub_layer_profile_compatibility_flag
|
|
_ = r.ReadBits64(48) // other flags
|
|
|
|
if sub_layer_profile_idc != 1 {
|
|
return false
|
|
}
|
|
}
|
|
|
|
if s.sub_layer_level_present_flag[i] != 0 {
|
|
_ = r.ReadBits8(8)
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|