h265 video mp4 support
This commit is contained in:
		| @@ -2,6 +2,7 @@ package h265parser | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  |  | ||||||
| 	"github.com/deepch/vdk/av" | 	"github.com/deepch/vdk/av" | ||||||
| @@ -9,6 +10,32 @@ import ( | |||||||
| 	"github.com/deepch/vdk/utils/bits/pio" | 	"github.com/deepch/vdk/utils/bits/pio" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | type SPSInfo struct { | ||||||
|  | 	ProfileIdc                       uint | ||||||
|  | 	LevelIdc                         uint | ||||||
|  | 	MbWidth                          uint | ||||||
|  | 	MbHeight                         uint | ||||||
|  | 	CropLeft                         uint | ||||||
|  | 	CropRight                        uint | ||||||
|  | 	CropTop                          uint | ||||||
|  | 	CropBottom                       uint | ||||||
|  | 	Width                            uint | ||||||
|  | 	Height                           uint | ||||||
|  | 	numTemporalLayers                uint | ||||||
|  | 	temporalIdNested                 uint | ||||||
|  | 	chromaFormat                     uint | ||||||
|  | 	PicWidthInLumaSamples            uint | ||||||
|  | 	PicHeightInLumaSamples           uint | ||||||
|  | 	bitDepthLumaMinus8               uint | ||||||
|  | 	bitDepthChromaMinus8             uint | ||||||
|  | 	generalProfileSpace              uint | ||||||
|  | 	generalTierFlag                  uint | ||||||
|  | 	generalProfileIDC                uint | ||||||
|  | 	generalProfileCompatibilityFlags uint32 | ||||||
|  | 	generalConstraintIndicatorFlags  uint64 | ||||||
|  | 	generalLevelIDC                  uint | ||||||
|  | } | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	NAL_UNIT_CODED_SLICE_TRAIL_N    = 0 | 	NAL_UNIT_CODED_SLICE_TRAIL_N    = 0 | ||||||
| 	NAL_UNIT_CODED_SLICE_TRAIL_R    = 1 | 	NAL_UNIT_CODED_SLICE_TRAIL_R    = 1 | ||||||
| @@ -83,6 +110,11 @@ const ( | |||||||
| 	MAX_SPS_COUNT  = 32 | 	MAX_SPS_COUNT  = 32 | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	ErrorH265IncorectUnitSize = errors.New("Invorect Unit Size") | ||||||
|  | 	ErrorH265IncorectUnitType = errors.New("Incorect Unit Type") | ||||||
|  | ) | ||||||
|  |  | ||||||
| func IsDataNALU(b []byte) bool { | func IsDataNALU(b []byte) bool { | ||||||
| 	typ := b[0] & 0x1f | 	typ := b[0] & 0x1f | ||||||
| 	return typ >= 1 && typ <= 5 | 	return typ >= 1 && typ <= 5 | ||||||
| @@ -128,7 +160,6 @@ func SplitNALUs(b []byte) (nalus [][]byte, typ int) { | |||||||
| 			return nalus, NALU_AVCC | 			return nalus, NALU_AVCC | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	// is Annex B |  | ||||||
| 	if val3 == 1 || val4 == 1 { | 	if val3 == 1 || val4 == 1 { | ||||||
| 		_val3 := val3 | 		_val3 := val3 | ||||||
| 		_val4 := val4 | 		_val4 := val4 | ||||||
| @@ -175,212 +206,216 @@ func SplitNALUs(b []byte) (nalus [][]byte, typ int) { | |||||||
| 	return [][]byte{b}, NALU_RAW | 	return [][]byte{b}, NALU_RAW | ||||||
| } | } | ||||||
|  |  | ||||||
| type SPSInfo struct { | func ParseSPS(sps []byte) (ctx SPSInfo, err error) { | ||||||
| 	ProfileIdc uint | 	if len(sps) < 2 { | ||||||
| 	LevelIdc   uint | 		err = ErrorH265IncorectUnitSize | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	rbsp := nal2rbsp(sps[2:]) | ||||||
|  | 	br := &bits.GolombBitReader{R: bytes.NewReader(rbsp)} | ||||||
|  | 	if _, err = br.ReadBits(4); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	spsMaxSubLayersMinus1, err := br.ReadBits(3) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	MbWidth  uint | 	if spsMaxSubLayersMinus1+1 > ctx.numTemporalLayers { | ||||||
| 	MbHeight uint | 		ctx.numTemporalLayers = spsMaxSubLayersMinus1 + 1 | ||||||
|  | 	} | ||||||
|  | 	if ctx.temporalIdNested, err = br.ReadBit(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if err = parsePTL(br, &ctx, spsMaxSubLayersMinus1); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	var cf uint | ||||||
|  | 	if cf, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	ctx.chromaFormat = uint(cf) | ||||||
|  | 	if ctx.chromaFormat == 3 { | ||||||
|  | 		if _, err = br.ReadBit(); err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if ctx.PicWidthInLumaSamples, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	ctx.Width = uint(ctx.PicWidthInLumaSamples) | ||||||
|  | 	if ctx.PicHeightInLumaSamples, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	ctx.Height = uint(ctx.PicHeightInLumaSamples) | ||||||
|  | 	conformanceWindowFlag, err := br.ReadBit() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if conformanceWindowFlag != 0 { | ||||||
|  | 		if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	CropLeft   uint | 	var bdlm8 uint | ||||||
| 	CropRight  uint | 	if bdlm8, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
| 	CropTop    uint | 		return | ||||||
| 	CropBottom uint | 	} | ||||||
|  | 	ctx.bitDepthChromaMinus8 = uint(bdlm8) | ||||||
|  | 	var bdcm8 uint | ||||||
|  | 	if bdcm8, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	ctx.bitDepthChromaMinus8 = uint(bdcm8) | ||||||
|  |  | ||||||
| 	Width  uint | 	_, err = br.ReadExponentialGolombCode() | ||||||
| 	Height uint | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	spsSubLayerOrderingInfoPresentFlag, err := br.ReadBit() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	var i uint | ||||||
|  | 	if spsSubLayerOrderingInfoPresentFlag != 0 { | ||||||
|  | 		i = 0 | ||||||
|  | 	} else { | ||||||
|  | 		i = spsMaxSubLayersMinus1 | ||||||
|  | 	} | ||||||
|  | 	for ; i <= spsMaxSubLayersMinus1; i++ { | ||||||
|  | 		if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if _, err = br.ReadExponentialGolombCode(); err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func ParseSPS(data []byte) (self SPSInfo, err error) { | func parsePTL(br *bits.GolombBitReader, ctx *SPSInfo, maxSubLayersMinus1 uint) error { | ||||||
| 	r := &bits.GolombBitReader{R: bytes.NewReader(data)} | 	var err error | ||||||
|  | 	var ptl SPSInfo | ||||||
| 	if _, err = r.ReadBits(8); err != nil { | 	if ptl.generalProfileSpace, err = br.ReadBits(2); err != nil { | ||||||
| 		return | 		return err | ||||||
| 	} | 	} | ||||||
|  | 	if ptl.generalTierFlag, err = br.ReadBit(); err != nil { | ||||||
| 	if self.ProfileIdc, err = r.ReadBits(8); err != nil { | 		return err | ||||||
| 		return |  | ||||||
| 	} | 	} | ||||||
|  | 	if ptl.generalProfileIDC, err = br.ReadBits(5); err != nil { | ||||||
| 	// constraint_set0_flag-constraint_set6_flag,reserved_zero_2bits | 		return err | ||||||
| 	if _, err = r.ReadBits(8); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} | 	} | ||||||
|  | 	if ptl.generalProfileCompatibilityFlags, err = br.ReadBits32(32); err != nil { | ||||||
| 	// level_idc | 		return err | ||||||
| 	if self.LevelIdc, err = r.ReadBits(8); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} | 	} | ||||||
|  | 	if ptl.generalConstraintIndicatorFlags, err = br.ReadBits64(48); err != nil { | ||||||
| 	// seq_parameter_set_id | 		return err | ||||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} | 	} | ||||||
|  | 	if ptl.generalLevelIDC, err = br.ReadBits(8); err != nil { | ||||||
| 	if self.ProfileIdc == 100 || self.ProfileIdc == 110 || | 		return err | ||||||
| 		self.ProfileIdc == 122 || self.ProfileIdc == 244 || |  | ||||||
| 		self.ProfileIdc == 44 || self.ProfileIdc == 83 || |  | ||||||
| 		self.ProfileIdc == 86 || self.ProfileIdc == 118 { |  | ||||||
|  |  | ||||||
| 		var chroma_format_idc uint |  | ||||||
| 		if chroma_format_idc, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 			return |  | ||||||
| 	} | 	} | ||||||
|  | 	updatePTL(ctx, &ptl) | ||||||
| 		if chroma_format_idc == 3 { | 	if maxSubLayersMinus1 == 0 { | ||||||
| 			// residual_colour_transform_flag | 		return nil | ||||||
| 			if _, err = r.ReadBit(); err != nil { | 	} | ||||||
| 				return | 	subLayerProfilePresentFlag := make([]uint, maxSubLayersMinus1) | ||||||
|  | 	subLayerLevelPresentFlag := make([]uint, maxSubLayersMinus1) | ||||||
|  | 	for i := uint(0); i < maxSubLayersMinus1; i++ { | ||||||
|  | 		if subLayerProfilePresentFlag[i], err = br.ReadBit(); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		if subLayerLevelPresentFlag[i], err = br.ReadBit(); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if maxSubLayersMinus1 > 0 { | ||||||
|  | 		for i := maxSubLayersMinus1; i < 8; i++ { | ||||||
|  | 			if _, err = br.ReadBits(2); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for i := uint(0); i < maxSubLayersMinus1; i++ { | ||||||
|  | 		if subLayerProfilePresentFlag[i] != 0 { | ||||||
|  | 			if _, err = br.ReadBits32(32); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			if _, err = br.ReadBits32(32); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			if _, err = br.ReadBits32(24); err != nil { | ||||||
|  | 				return err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// bit_depth_luma_minus8 | 		if subLayerLevelPresentFlag[i] != 0 { | ||||||
| 		if _, err = r.ReadExponentialGolombCode(); err != nil { | 			if _, err = br.ReadBits(8); err != nil { | ||||||
| 			return | 				return err | ||||||
| 			} | 			} | ||||||
| 		// bit_depth_chroma_minus8 |  | ||||||
| 		if _, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} | 		} | ||||||
| 		// qpprime_y_zero_transform_bypass_flag |  | ||||||
| 		if _, err = r.ReadBit(); err != nil { |  | ||||||
| 			return |  | ||||||
| 	} | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
| 		var seq_scaling_matrix_present_flag uint | func updatePTL(ctx, ptl *SPSInfo) { | ||||||
| 		if seq_scaling_matrix_present_flag, err = r.ReadBit(); err != nil { | 	ctx.generalProfileSpace = ptl.generalProfileSpace | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if seq_scaling_matrix_present_flag != 0 { | 	if ptl.generalTierFlag > ctx.generalTierFlag { | ||||||
| 			for i := 0; i < 8; i++ { | 		ctx.generalLevelIDC = ptl.generalLevelIDC | ||||||
| 				var seq_scaling_list_present_flag uint |  | ||||||
| 				if seq_scaling_list_present_flag, err = r.ReadBit(); err != nil { | 		ctx.generalTierFlag = ptl.generalTierFlag | ||||||
| 					return |  | ||||||
| 				} |  | ||||||
| 				if seq_scaling_list_present_flag != 0 { |  | ||||||
| 					var sizeOfScalingList uint |  | ||||||
| 					if i < 6 { |  | ||||||
| 						sizeOfScalingList = 16 |  | ||||||
| 	} else { | 	} else { | ||||||
| 						sizeOfScalingList = 64 | 		if ptl.generalLevelIDC > ctx.generalLevelIDC { | ||||||
| 					} | 			ctx.generalLevelIDC = ptl.generalLevelIDC | ||||||
| 					lastScale := uint(8) |  | ||||||
| 					nextScale := uint(8) |  | ||||||
| 					for j := uint(0); j < sizeOfScalingList; j++ { |  | ||||||
| 						if nextScale != 0 { |  | ||||||
| 							var delta_scale uint |  | ||||||
| 							if delta_scale, err = r.ReadSE(); err != nil { |  | ||||||
| 								return |  | ||||||
| 							} |  | ||||||
| 							nextScale = (lastScale + delta_scale + 256) % 256 |  | ||||||
| 						} |  | ||||||
| 						if nextScale != 0 { |  | ||||||
| 							lastScale = nextScale |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// log2_max_frame_num_minus4 | 	if ptl.generalProfileIDC > ctx.generalProfileIDC { | ||||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { | 		ctx.generalProfileIDC = ptl.generalProfileIDC | ||||||
| 		return |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var pic_order_cnt_type uint | 	ctx.generalProfileCompatibilityFlags &= ptl.generalProfileCompatibilityFlags | ||||||
| 	if pic_order_cnt_type, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if pic_order_cnt_type == 0 { |  | ||||||
| 		// log2_max_pic_order_cnt_lsb_minus4 |  | ||||||
| 		if _, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} else if pic_order_cnt_type == 1 { |  | ||||||
| 		// delta_pic_order_always_zero_flag |  | ||||||
| 		if _, err = r.ReadBit(); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		// offset_for_non_ref_pic |  | ||||||
| 		if _, err = r.ReadSE(); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		// offset_for_top_to_bottom_field |  | ||||||
| 		if _, err = r.ReadSE(); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		var num_ref_frames_in_pic_order_cnt_cycle uint |  | ||||||
| 		if num_ref_frames_in_pic_order_cnt_cycle, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		for i := uint(0); i < num_ref_frames_in_pic_order_cnt_cycle; i++ { |  | ||||||
| 			if _, err = r.ReadSE(); err != nil { |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// max_num_ref_frames | 	ctx.generalConstraintIndicatorFlags &= ptl.generalConstraintIndicatorFlags | ||||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { | } | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// gaps_in_frame_num_value_allowed_flag | func nal2rbsp(nal []byte) []byte { | ||||||
| 	if _, err = r.ReadBit(); err != nil { | 	return bytes.Replace(nal, []byte{0x0, 0x0, 0x3}, []byte{0x0, 0x0}, -1) | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if self.MbWidth, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	self.MbWidth++ |  | ||||||
|  |  | ||||||
| 	if self.MbHeight, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	self.MbHeight++ |  | ||||||
|  |  | ||||||
| 	var frame_mbs_only_flag uint |  | ||||||
| 	if frame_mbs_only_flag, err = r.ReadBit(); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if frame_mbs_only_flag == 0 { |  | ||||||
| 		// mb_adaptive_frame_field_flag |  | ||||||
| 		if _, err = r.ReadBit(); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// direct_8x8_inference_flag |  | ||||||
| 	if _, err = r.ReadBit(); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var frame_cropping_flag uint |  | ||||||
| 	if frame_cropping_flag, err = r.ReadBit(); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if frame_cropping_flag != 0 { |  | ||||||
| 		if self.CropLeft, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		if self.CropRight, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		if self.CropTop, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		if self.CropBottom, err = r.ReadExponentialGolombCode(); err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	self.Width = (self.MbWidth * 16) - self.CropLeft*2 - self.CropRight*2 |  | ||||||
| 	self.Height = ((2 - frame_mbs_only_flag) * self.MbHeight * 16) - self.CropTop*2 - self.CropBottom*2 |  | ||||||
|  |  | ||||||
| 	return |  | ||||||
| } | } | ||||||
|  |  | ||||||
| type CodecData struct { | type CodecData struct { | ||||||
| @@ -443,23 +478,20 @@ func NewCodecDataFromAVCDecoderConfRecord(record []byte) (self CodecData, err er | |||||||
|  |  | ||||||
| func NewCodecDataFromVPSAndSPSAndPPS(vps, sps, pps []byte) (self CodecData, err error) { | func NewCodecDataFromVPSAndSPSAndPPS(vps, sps, pps []byte) (self CodecData, err error) { | ||||||
| 	recordinfo := AVCDecoderConfRecord{} | 	recordinfo := AVCDecoderConfRecord{} | ||||||
| 	recordinfo.AVCProfileIndication = sps[1] | 	recordinfo.AVCProfileIndication = sps[3] | ||||||
| 	recordinfo.ProfileCompatibility = sps[2] | 	recordinfo.ProfileCompatibility = sps[4] | ||||||
| 	recordinfo.AVCLevelIndication = sps[3] | 	recordinfo.AVCLevelIndication = sps[5] | ||||||
| 	recordinfo.SPS = [][]byte{sps} | 	recordinfo.SPS = [][]byte{sps} | ||||||
| 	recordinfo.PPS = [][]byte{pps} | 	recordinfo.PPS = [][]byte{pps} | ||||||
| 	recordinfo.VPS = [][]byte{vps} | 	recordinfo.VPS = [][]byte{vps} | ||||||
| 	recordinfo.LengthSizeMinusOne = 3 | 	recordinfo.LengthSizeMinusOne = 3 | ||||||
|  |  | ||||||
| 	buf := make([]byte, recordinfo.Len()) |  | ||||||
| 	recordinfo.Marshal(buf) |  | ||||||
|  |  | ||||||
| 	self.RecordInfo = recordinfo |  | ||||||
| 	self.Record = buf |  | ||||||
|  |  | ||||||
| 	if self.SPSInfo, err = ParseSPS(sps); err != nil { | 	if self.SPSInfo, err = ParseSPS(sps); err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	buf := make([]byte, recordinfo.Len()) | ||||||
|  | 	recordinfo.Marshal(buf, self.SPSInfo) | ||||||
|  | 	self.RecordInfo = recordinfo | ||||||
|  | 	self.Record = buf | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -480,14 +512,12 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) { | |||||||
| 		err = ErrDecconfInvalid | 		err = ErrDecconfInvalid | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	self.AVCProfileIndication = b[1] | 	self.AVCProfileIndication = b[1] | ||||||
| 	self.ProfileCompatibility = b[2] | 	self.ProfileCompatibility = b[2] | ||||||
| 	self.AVCLevelIndication = b[3] | 	self.AVCLevelIndication = b[3] | ||||||
| 	self.LengthSizeMinusOne = b[4] & 0x03 | 	self.LengthSizeMinusOne = b[4] & 0x03 | ||||||
| 	spscount := int(b[5] & 0x1f) | 	spscount := int(b[5] & 0x1f) | ||||||
| 	n += 6 | 	n += 6 | ||||||
|  |  | ||||||
| 	for i := 0; i < spscount; i++ { | 	for i := 0; i < spscount; i++ { | ||||||
| 		if len(b) < n+2 { | 		if len(b) < n+2 { | ||||||
| 			err = ErrDecconfInvalid | 			err = ErrDecconfInvalid | ||||||
| @@ -550,55 +580,63 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (self AVCDecoderConfRecord) Len() (n int) { | func (self AVCDecoderConfRecord) Len() (n int) { | ||||||
| 	n = 7 | 	n = 23 | ||||||
| 	for _, sps := range self.SPS { | 	for _, sps := range self.SPS { | ||||||
| 		n += 2 + len(sps) | 		n += 5 + len(sps) | ||||||
| 	} | 	} | ||||||
| 	for _, pps := range self.PPS { | 	for _, pps := range self.PPS { | ||||||
| 		n += 2 + len(pps) | 		n += 5 + len(pps) | ||||||
| 	} | 	} | ||||||
| 	for _, vps := range self.VPS { | 	for _, vps := range self.VPS { | ||||||
| 		n += 2 + len(vps) | 		n += 5 + len(vps) | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self AVCDecoderConfRecord) Marshal(b []byte) (n int) { | func (self AVCDecoderConfRecord) Marshal(b []byte, si SPSInfo) (n int) { | ||||||
| 	b[0] = 1 | 	b[0] = 1 | ||||||
| 	b[1] = self.AVCProfileIndication | 	b[1] = self.AVCProfileIndication | ||||||
| 	b[2] = self.ProfileCompatibility | 	b[2] = self.ProfileCompatibility | ||||||
| 	b[3] = self.AVCLevelIndication | 	b[3] = self.AVCLevelIndication | ||||||
| 	b[4] = self.LengthSizeMinusOne | 0xfc | 	b[21] = 3 | ||||||
| 	b[5] = uint8(len(self.SPS)) | 0xe0 | 	b[22] = 3 | ||||||
| 	n += 6 | 	n += 23 | ||||||
|  | 	b[n] = (self.VPS[0][0] >> 1) & 0x3f | ||||||
| 	for _, sps := range self.SPS { |  | ||||||
| 		pio.PutU16BE(b[n:], uint16(len(sps))) |  | ||||||
| 		n += 2 |  | ||||||
| 		copy(b[n:], sps) |  | ||||||
| 		n += len(sps) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	b[n] = uint8(len(self.PPS)) |  | ||||||
| 	n++ | 	n++ | ||||||
|  | 	b[n] = byte(len(self.VPS) >> 8) | ||||||
| 	for _, pps := range self.PPS { | 	n++ | ||||||
| 		pio.PutU16BE(b[n:], uint16(len(pps))) | 	b[n] = byte(len(self.VPS)) | ||||||
| 		n += 2 |  | ||||||
| 		copy(b[n:], pps) |  | ||||||
| 		n += len(pps) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	b[n] = uint8(len(self.VPS)) |  | ||||||
| 	n++ | 	n++ | ||||||
|  |  | ||||||
| 	for _, vps := range self.VPS { | 	for _, vps := range self.VPS { | ||||||
| 		pio.PutU16BE(b[n:], uint16(len(vps))) | 		pio.PutU16BE(b[n:], uint16(len(vps))) | ||||||
| 		n += 2 | 		n += 2 | ||||||
| 		copy(b[n:], vps) | 		copy(b[n:], vps) | ||||||
| 		n += len(vps) | 		n += len(vps) | ||||||
| 	} | 	} | ||||||
|  | 	b[n] = (self.SPS[0][0] >> 1) & 0x3f | ||||||
|  | 	n++ | ||||||
|  | 	b[n] = byte(len(self.SPS) >> 8) | ||||||
|  | 	n++ | ||||||
|  | 	b[n] = byte(len(self.SPS)) | ||||||
|  | 	n++ | ||||||
|  | 	for _, sps := range self.SPS { | ||||||
|  | 		pio.PutU16BE(b[n:], uint16(len(sps))) | ||||||
|  | 		n += 2 | ||||||
|  | 		copy(b[n:], sps) | ||||||
|  | 		n += len(sps) | ||||||
|  | 	} | ||||||
|  | 	b[n] = (self.PPS[0][0] >> 1) & 0x3f | ||||||
|  | 	n++ | ||||||
|  | 	b[n] = byte(len(self.PPS) >> 8) | ||||||
|  | 	n++ | ||||||
|  | 	b[n] = byte(len(self.PPS)) | ||||||
|  | 	n++ | ||||||
|  | 	for _, pps := range self.PPS { | ||||||
|  | 		pio.PutU16BE(b[n:], uint16(len(pps))) | ||||||
|  | 		n += 2 | ||||||
|  | 		copy(b[n:], pps) | ||||||
|  | 		n += len(pps) | ||||||
|  | 	} | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -623,17 +661,13 @@ const ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) { | func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) { | ||||||
|  |  | ||||||
| 	if len(packet) <= 1 { | 	if len(packet) <= 1 { | ||||||
| 		err = fmt.Errorf("h265parser: packet too short to parse slice header") | 		err = fmt.Errorf("h265parser: packet too short to parse slice header") | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	nal_unit_type := packet[0] & 0x1f | 	nal_unit_type := packet[0] & 0x1f | ||||||
| 	switch nal_unit_type { | 	switch nal_unit_type { | ||||||
| 	case 1, 2, 5, 19: | 	case 1, 2, 5, 19: | ||||||
| 		// slice_layer_without_partitioning_rbsp |  | ||||||
| 		// slice_data_partition_a_layer_rbsp |  | ||||||
|  |  | ||||||
| 	default: | 	default: | ||||||
| 		err = fmt.Errorf("h265parser: nal_unit_type=%d has no slice header", nal_unit_type) | 		err = fmt.Errorf("h265parser: nal_unit_type=%d has no slice header", nal_unit_type) | ||||||
| @@ -641,13 +675,9 @@ func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	r := &bits.GolombBitReader{R: bytes.NewReader(packet[1:])} | 	r := &bits.GolombBitReader{R: bytes.NewReader(packet[1:])} | ||||||
|  |  | ||||||
| 	// first_mb_in_slice |  | ||||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { | 	if _, err = r.ReadExponentialGolombCode(); err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// slice_type |  | ||||||
| 	var u uint | 	var u uint | ||||||
| 	if u, err = r.ReadExponentialGolombCode(); err != nil { | 	if u, err = r.ReadExponentialGolombCode(); err != nil { | ||||||
| 		return | 		return | ||||||
| @@ -664,6 +694,5 @@ func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) { | |||||||
| 		err = fmt.Errorf("h265parser: slice_type=%d invalid", u) | 		err = fmt.Errorf("h265parser: slice_type=%d invalid", u) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|   | |||||||
| @@ -181,6 +181,7 @@ func (self *Stream) fillTrackAtom() (err error) { | |||||||
| 	} else if self.Type() == av.H265 { | 	} else if self.Type() == av.H265 { | ||||||
| 		codec := self.CodecData.(h265parser.CodecData) | 		codec := self.CodecData.(h265parser.CodecData) | ||||||
| 		width, height := codec.Width(), codec.Height() | 		width, height := codec.Width(), codec.Height() | ||||||
|  |  | ||||||
| 		self.sample.SampleDesc.HV1Desc = &mp4io.HV1Desc{ | 		self.sample.SampleDesc.HV1Desc = &mp4io.HV1Desc{ | ||||||
| 			DataRefIdx:           1, | 			DataRefIdx:           1, | ||||||
| 			HorizontalResolution: 72, | 			HorizontalResolution: 72, | ||||||
| @@ -192,6 +193,7 @@ func (self *Stream) fillTrackAtom() (err error) { | |||||||
| 			ColorTableId:         -1, | 			ColorTableId:         -1, | ||||||
| 			Conf:                 &mp4io.HV1Conf{Data: codec.AVCDecoderConfRecordBytes()}, | 			Conf:                 &mp4io.HV1Conf{Data: codec.AVCDecoderConfRecordBytes()}, | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		self.trackAtom.Media.Handler = &mp4io.HandlerRefer{ | 		self.trackAtom.Media.Handler = &mp4io.HandlerRefer{ | ||||||
| 			SubType: [4]byte{'v', 'i', 'd', 'e'}, | 			SubType: [4]byte{'v', 'i', 'd', 'e'}, | ||||||
| 			Name:    []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'G', 'G', 0, 0, 0}, | 			Name:    []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'G', 'G', 0, 0, 0}, | ||||||
| @@ -200,6 +202,7 @@ func (self *Stream) fillTrackAtom() (err error) { | |||||||
| 			Flags: 0x000001, | 			Flags: 0x000001, | ||||||
| 		} | 		} | ||||||
| 		self.codecString = fmt.Sprintf("hvc1.%02X%02X%02X", codec.RecordInfo.AVCProfileIndication, codec.RecordInfo.ProfileCompatibility, codec.RecordInfo.AVCLevelIndication) | 		self.codecString = fmt.Sprintf("hvc1.%02X%02X%02X", codec.RecordInfo.AVCProfileIndication, codec.RecordInfo.ProfileCompatibility, codec.RecordInfo.AVCLevelIndication) | ||||||
|  |  | ||||||
| 	} else if self.Type() == av.AAC { | 	} else if self.Type() == av.AAC { | ||||||
| 		codec := self.CodecData.(aacparser.CodecData) | 		codec := self.CodecData.(aacparser.CodecData) | ||||||
| 		self.sample.SampleDesc.MP4ADesc = &mp4io.MP4ADesc{ | 		self.sample.SampleDesc.MP4ADesc = &mp4io.MP4ADesc{ | ||||||
| @@ -354,6 +357,7 @@ func (element *Stream) writePacketV3(pkt av.Packet, rawdur time.Duration, maxFra | |||||||
| } | } | ||||||
|  |  | ||||||
| func (element *Stream) writePacketV2(pkt av.Packet, rawdur time.Duration, maxFrames int) (bool, []byte, error) { | func (element *Stream) writePacketV2(pkt av.Packet, rawdur time.Duration, maxFrames int) (bool, []byte, error) { | ||||||
|  | 	//pkt.Data = pkt.Data[4:] | ||||||
| 	trackID := pkt.Idx + 1 | 	trackID := pkt.Idx + 1 | ||||||
| 	if element.sampleIndex == 0 { | 	if element.sampleIndex == 0 { | ||||||
| 		element.moof.Header = &mp4fio.MovieFragHeader{Seqnum: uint32(element.muxer.fragmentIndex + 1)} | 		element.moof.Header = &mp4fio.MovieFragHeader{Seqnum: uint32(element.muxer.fragmentIndex + 1)} | ||||||
|   | |||||||
| @@ -142,26 +142,33 @@ func Dial(options RTSPClientOptions) (*RTSPClient, error) { | |||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 		if i2.AVType == VIDEO { | 		if i2.AVType == VIDEO { | ||||||
| 			if i2.Type == av.H264 && len(i2.SpropParameterSets) > 1 { | 			if i2.Type == av.H264 { | ||||||
|  | 				if len(i2.SpropParameterSets) > 1 { | ||||||
| 					if codecData, err := h264parser.NewCodecDataFromSPSAndPPS(i2.SpropParameterSets[0], i2.SpropParameterSets[1]); err == nil { | 					if codecData, err := h264parser.NewCodecDataFromSPSAndPPS(i2.SpropParameterSets[0], i2.SpropParameterSets[1]); err == nil { | ||||||
| 						client.sps = i2.SpropParameterSets[0] | 						client.sps = i2.SpropParameterSets[0] | ||||||
| 						client.pps = i2.SpropParameterSets[1] | 						client.pps = i2.SpropParameterSets[1] | ||||||
| 						client.CodecData = append(client.CodecData, codecData) | 						client.CodecData = append(client.CodecData, codecData) | ||||||
| 					client.videoIDX = int8(len(client.CodecData) - 1) |  | ||||||
| 					client.videoCodec = av.H264 |  | ||||||
| 					} | 					} | ||||||
| 			} else if i2.Type == av.H265 && len(i2.SpropVPS) > 1 && len(i2.SpropSPS) > 1 && len(i2.SpropPPS) > 1 { | 				} else { | ||||||
|  | 					client.CodecData = append(client.CodecData, h264parser.CodecData{}) | ||||||
|  | 				} | ||||||
|  | 				client.videoCodec = av.H264 | ||||||
|  | 			} else if i2.Type == av.H265 { | ||||||
|  | 				if len(i2.SpropVPS) > 1 && len(i2.SpropSPS) > 1 && len(i2.SpropPPS) > 1 { | ||||||
| 					if codecData, err := h265parser.NewCodecDataFromVPSAndSPSAndPPS(i2.SpropVPS, i2.SpropSPS, i2.SpropPPS); err == nil { | 					if codecData, err := h265parser.NewCodecDataFromVPSAndSPSAndPPS(i2.SpropVPS, i2.SpropSPS, i2.SpropPPS); err == nil { | ||||||
| 						client.vps = i2.SpropVPS | 						client.vps = i2.SpropVPS | ||||||
| 						client.sps = i2.SpropSPS | 						client.sps = i2.SpropSPS | ||||||
| 						client.pps = i2.SpropPPS | 						client.pps = i2.SpropPPS | ||||||
| 						client.CodecData = append(client.CodecData, codecData) | 						client.CodecData = append(client.CodecData, codecData) | ||||||
| 					client.videoIDX = int8(len(client.CodecData) - 1) |  | ||||||
| 					client.videoCodec = av.H265 |  | ||||||
| 					} | 					} | ||||||
|  | 				} else { | ||||||
|  | 					client.CodecData = append(client.CodecData, h265parser.CodecData{}) | ||||||
|  | 				} | ||||||
|  | 				client.videoCodec = av.H265 | ||||||
| 			} else { | 			} else { | ||||||
| 				client.Println("SDP Video Codec Type Not Supported", i2.Type) | 				client.Println("SDP Video Codec Type Not Supported", i2.Type) | ||||||
| 			} | 			} | ||||||
|  | 			client.videoIDX = int8(len(client.CodecData) - 1) | ||||||
| 			client.videoID = ch | 			client.videoID = ch | ||||||
| 		} | 		} | ||||||
| 		if i2.AVType == AUDIO { | 		if i2.AVType == AUDIO { | ||||||
| @@ -552,7 +559,7 @@ func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) { | |||||||
| 						Data:            append(binSize(len(nal)), nal...), | 						Data:            append(binSize(len(nal)), nal...), | ||||||
| 						CompositionTime: time.Duration(1) * time.Millisecond, | 						CompositionTime: time.Duration(1) * time.Millisecond, | ||||||
| 						Idx:             client.videoIDX, | 						Idx:             client.videoIDX, | ||||||
| 						IsKeyFrame:      naluType == h265parser.NAL_UNIT_CODED_SLICE_IDR_W_RADL, | 						IsKeyFrame:      false, | ||||||
| 						Duration:        time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond, | 						Duration:        time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond, | ||||||
| 						Time:            time.Duration(timestamp/90) * time.Millisecond, | 						Time:            time.Duration(timestamp/90) * time.Millisecond, | ||||||
| 					}) | 					}) | ||||||
| @@ -564,22 +571,19 @@ func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) { | |||||||
| 					client.CodecUpdatePPS(nal) | 					client.CodecUpdatePPS(nal) | ||||||
| 				case h265parser.NAL_UNIT_UNSPECIFIED_49: | 				case h265parser.NAL_UNIT_UNSPECIFIED_49: | ||||||
| 					se := nal[2] >> 6 | 					se := nal[2] >> 6 | ||||||
| 					naluType = nal[2] & 0x3f | 					naluType := nal[2] & 0x3f | ||||||
| 					if se == 2 { | 					if se == 2 { | ||||||
| 						client.BufferRtpPacket.Truncate(0) | 						client.BufferRtpPacket.Truncate(0) | ||||||
| 						client.BufferRtpPacket.Reset() | 						client.BufferRtpPacket.Reset() | ||||||
| 						client.BufferRtpPacket.Write([]byte{0, 0, 0, 0, (nal[0] & 0x81) | (naluType << 1), nal[1]}) | 						client.BufferRtpPacket.Write([]byte{(nal[0] & 0x81) | (naluType << 1), nal[1]}) | ||||||
| 						r := make([]byte, 2) | 						r := make([]byte, 2) | ||||||
| 						r[1] = nal[1] | 						r[1] = nal[1] | ||||||
| 						r[0] = (nal[0] & 0x81) | (naluType << 1) | 						r[0] = (nal[0] & 0x81) | (naluType << 1) | ||||||
| 						client.BufferRtpPacket.Write(nal[3:]) | 						client.BufferRtpPacket.Write(nal[3:]) | ||||||
| 					} else if se == 1 { | 					} else if se == 1 { | ||||||
| 						client.BufferRtpPacket.Write(nal[3:]) | 						client.BufferRtpPacket.Write(nal[3:]) | ||||||
| 						binary.BigEndian.PutUint32(client.BufferRtpPacket.Bytes()[:4], uint32(client.BufferRtpPacket.Len())-4) |  | ||||||
| 						buf := make([]byte, client.BufferRtpPacket.Len()) |  | ||||||
| 						copy(buf, client.BufferRtpPacket.Bytes()) |  | ||||||
| 						retmap = append(retmap, &av.Packet{ | 						retmap = append(retmap, &av.Packet{ | ||||||
| 							Data:            append(binSize(len(nal)), nal...), | 							Data:            append(binSize(client.BufferRtpPacket.Len()), client.BufferRtpPacket.Bytes()...), | ||||||
| 							CompositionTime: time.Duration(1) * time.Millisecond, | 							CompositionTime: time.Duration(1) * time.Millisecond, | ||||||
| 							Idx:             client.videoIDX, | 							Idx:             client.videoIDX, | ||||||
| 							IsKeyFrame:      naluType == h265parser.NAL_UNIT_CODED_SLICE_IDR_W_RADL, | 							IsKeyFrame:      naluType == h265parser.NAL_UNIT_CODED_SLICE_IDR_W_RADL, | ||||||
| @@ -590,8 +594,9 @@ func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) { | |||||||
| 						client.BufferRtpPacket.Write(nal[3:]) | 						client.BufferRtpPacket.Write(nal[3:]) | ||||||
| 					} | 					} | ||||||
| 				default: | 				default: | ||||||
| 					//log.Println("???", naluType) | 					client.Println("Unsupported Nal", naluType) | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 			} else if client.videoCodec == av.H264 { | 			} else if client.videoCodec == av.H264 { | ||||||
| 				naluType := nal[0] & 0x1f | 				naluType := nal[0] & 0x1f | ||||||
| 				switch { | 				switch { | ||||||
|   | |||||||
| @@ -195,6 +195,9 @@ func (element *Muxer) WritePacket(pkt av.Packet) (err error) { | |||||||
| 	} | 	} | ||||||
| 	if tmp, ok := element.streams[pkt.Idx]; ok { | 	if tmp, ok := element.streams[pkt.Idx]; ok { | ||||||
| 		element.StreamACK.Reset(10 * time.Second) | 		element.StreamACK.Reset(10 * time.Second) | ||||||
|  | 		if len(pkt.Data) < 5 { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
| 		switch tmp.codec.Type() { | 		switch tmp.codec.Type() { | ||||||
| 		case av.H264: | 		case av.H264: | ||||||
| 			codec := tmp.codec.(h264parser.CodecData) | 			codec := tmp.codec.(h264parser.CodecData) | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -5,4 +5,5 @@ go 1.14 | |||||||
| require ( | require ( | ||||||
| 	github.com/pion/webrtc/v2 v2.2.23 // indirect | 	github.com/pion/webrtc/v2 v2.2.23 // indirect | ||||||
| 	github.com/pion/webrtc/v3 v3.0.1 // indirect | 	github.com/pion/webrtc/v3 v3.0.1 // indirect | ||||||
|  | 	github.com/q191201771/lal v0.19.1 // indirect | ||||||
| ) | ) | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							| @@ -100,6 +100,10 @@ github.com/pion/webrtc/v3 v3.0.1/go.mod h1:ePzv8r2tzj95nJuPsns/7OiS5M8RiGSULdxzI | |||||||
| github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||||||
| github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
|  | github.com/q191201771/lal v0.19.1 h1:Fxh33T+9y7Dp958/SFalzpWlt18LEYYT2z8UZdzhokQ= | ||||||
|  | github.com/q191201771/lal v0.19.1/go.mod h1:HUvNYsaXA7ZwGStxtpnxpH0lN5qzd350glLmdigDg0A= | ||||||
|  | github.com/q191201771/naza v0.17.0 h1:ZuETbHDX8srxxxL4AiDW+HTwEHnbfJvS40R8PUNStpQ= | ||||||
|  | github.com/q191201771/naza v0.17.0/go.mod h1:5LeGupZZFtYP1g/S203n9vXoUNVdlRnPIfM6rExjqt0= | ||||||
| github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= | github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= | ||||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||||
|   | |||||||
| @@ -33,6 +33,30 @@ func (self *GolombBitReader) ReadBits(n int) (res uint, err error) { | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (self *GolombBitReader) ReadBits32(n uint) (r uint32, err error) { | ||||||
|  | 	var t uint | ||||||
|  | 	for i := uint(0); i < n; i++ { | ||||||
|  | 		t, err = self.ReadBit() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		r = (r << 1) | uint32(t) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (self *GolombBitReader) ReadBits64(n uint) (r uint64, err error) { | ||||||
|  | 	var t uint | ||||||
|  | 	for i := uint(0); i < n; i++ { | ||||||
|  | 		t, err = self.ReadBit() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		r = (r << 1) | uint64(t) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
| func (self *GolombBitReader) ReadExponentialGolombCode() (res uint, err error) { | func (self *GolombBitReader) ReadExponentialGolombCode() (res uint, err error) { | ||||||
| 	i := 0 | 	i := 0 | ||||||
| 	for { | 	for { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Andrey Semochkin
					Andrey Semochkin