h265 video mp4 support
This commit is contained in:
		| @@ -2,6 +2,7 @@ package h265parser | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/deepch/vdk/av" | ||||
| @@ -9,6 +10,32 @@ import ( | ||||
| 	"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 ( | ||||
| 	NAL_UNIT_CODED_SLICE_TRAIL_N    = 0 | ||||
| 	NAL_UNIT_CODED_SLICE_TRAIL_R    = 1 | ||||
| @@ -83,6 +110,11 @@ const ( | ||||
| 	MAX_SPS_COUNT  = 32 | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	ErrorH265IncorectUnitSize = errors.New("Invorect Unit Size") | ||||
| 	ErrorH265IncorectUnitType = errors.New("Incorect Unit Type") | ||||
| ) | ||||
|  | ||||
| func IsDataNALU(b []byte) bool { | ||||
| 	typ := b[0] & 0x1f | ||||
| 	return typ >= 1 && typ <= 5 | ||||
| @@ -128,7 +160,6 @@ func SplitNALUs(b []byte) (nalus [][]byte, typ int) { | ||||
| 			return nalus, NALU_AVCC | ||||
| 		} | ||||
| 	} | ||||
| 	// is Annex B | ||||
| 	if val3 == 1 || val4 == 1 { | ||||
| 		_val3 := val3 | ||||
| 		_val4 := val4 | ||||
| @@ -175,212 +206,216 @@ func SplitNALUs(b []byte) (nalus [][]byte, typ int) { | ||||
| 	return [][]byte{b}, NALU_RAW | ||||
| } | ||||
|  | ||||
| type SPSInfo struct { | ||||
| 	ProfileIdc uint | ||||
| 	LevelIdc   uint | ||||
| func ParseSPS(sps []byte) (ctx SPSInfo, err error) { | ||||
| 	if len(sps) < 2 { | ||||
| 		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 | ||||
| 	MbHeight uint | ||||
| 	if spsMaxSubLayersMinus1+1 > ctx.numTemporalLayers { | ||||
| 		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 | ||||
| 	CropRight  uint | ||||
| 	CropTop    uint | ||||
| 	CropBottom uint | ||||
| 	var bdlm8 uint | ||||
| 	if bdlm8, err = br.ReadExponentialGolombCode(); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.bitDepthChromaMinus8 = uint(bdlm8) | ||||
| 	var bdcm8 uint | ||||
| 	if bdcm8, err = br.ReadExponentialGolombCode(); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.bitDepthChromaMinus8 = uint(bdcm8) | ||||
|  | ||||
| 	Width  uint | ||||
| 	Height uint | ||||
| 	_, err = br.ReadExponentialGolombCode() | ||||
| 	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) { | ||||
| 	r := &bits.GolombBitReader{R: bytes.NewReader(data)} | ||||
|  | ||||
| 	if _, err = r.ReadBits(8); err != nil { | ||||
| 		return | ||||
| func parsePTL(br *bits.GolombBitReader, ctx *SPSInfo, maxSubLayersMinus1 uint) error { | ||||
| 	var err error | ||||
| 	var ptl SPSInfo | ||||
| 	if ptl.generalProfileSpace, err = br.ReadBits(2); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if self.ProfileIdc, err = r.ReadBits(8); err != nil { | ||||
| 		return | ||||
| 	if ptl.generalTierFlag, err = br.ReadBit(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// constraint_set0_flag-constraint_set6_flag,reserved_zero_2bits | ||||
| 	if _, err = r.ReadBits(8); err != nil { | ||||
| 		return | ||||
| 	if ptl.generalProfileIDC, err = br.ReadBits(5); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// level_idc | ||||
| 	if self.LevelIdc, err = r.ReadBits(8); err != nil { | ||||
| 		return | ||||
| 	if ptl.generalProfileCompatibilityFlags, err = br.ReadBits32(32); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// seq_parameter_set_id | ||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { | ||||
| 		return | ||||
| 	if ptl.generalConstraintIndicatorFlags, err = br.ReadBits64(48); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if self.ProfileIdc == 100 || self.ProfileIdc == 110 || | ||||
| 		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 | ||||
| 	if ptl.generalLevelIDC, err = br.ReadBits(8); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 		if chroma_format_idc == 3 { | ||||
| 			// residual_colour_transform_flag | ||||
| 			if _, err = r.ReadBit(); err != nil { | ||||
| 				return | ||||
| 	updatePTL(ctx, &ptl) | ||||
| 	if maxSubLayersMinus1 == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	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 _, err = r.ReadExponentialGolombCode(); err != nil { | ||||
| 			return | ||||
| 		if subLayerLevelPresentFlag[i] != 0 { | ||||
| 			if _, err = br.ReadBits(8); err != nil { | ||||
| 				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 | ||||
| 		if seq_scaling_matrix_present_flag, err = r.ReadBit(); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| func updatePTL(ctx, ptl *SPSInfo) { | ||||
| 	ctx.generalProfileSpace = ptl.generalProfileSpace | ||||
|  | ||||
| 		if seq_scaling_matrix_present_flag != 0 { | ||||
| 			for i := 0; i < 8; i++ { | ||||
| 				var seq_scaling_list_present_flag uint | ||||
| 				if seq_scaling_list_present_flag, err = r.ReadBit(); err != nil { | ||||
| 					return | ||||
| 				} | ||||
| 				if seq_scaling_list_present_flag != 0 { | ||||
| 					var sizeOfScalingList uint | ||||
| 					if i < 6 { | ||||
| 						sizeOfScalingList = 16 | ||||
| 	if ptl.generalTierFlag > ctx.generalTierFlag { | ||||
| 		ctx.generalLevelIDC = ptl.generalLevelIDC | ||||
|  | ||||
| 		ctx.generalTierFlag = ptl.generalTierFlag | ||||
| 	} else { | ||||
| 						sizeOfScalingList = 64 | ||||
| 					} | ||||
| 					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 | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		if ptl.generalLevelIDC > ctx.generalLevelIDC { | ||||
| 			ctx.generalLevelIDC = ptl.generalLevelIDC | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// log2_max_frame_num_minus4 | ||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { | ||||
| 		return | ||||
| 	if ptl.generalProfileIDC > ctx.generalProfileIDC { | ||||
| 		ctx.generalProfileIDC = ptl.generalProfileIDC | ||||
| 	} | ||||
|  | ||||
| 	var pic_order_cnt_type uint | ||||
| 	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 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	ctx.generalProfileCompatibilityFlags &= ptl.generalProfileCompatibilityFlags | ||||
|  | ||||
| 	// max_num_ref_frames | ||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.generalConstraintIndicatorFlags &= ptl.generalConstraintIndicatorFlags | ||||
| } | ||||
|  | ||||
| 	// gaps_in_frame_num_value_allowed_flag | ||||
| 	if _, err = r.ReadBit(); err != nil { | ||||
| 		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 | ||||
| func nal2rbsp(nal []byte) []byte { | ||||
| 	return bytes.Replace(nal, []byte{0x0, 0x0, 0x3}, []byte{0x0, 0x0}, -1) | ||||
| } | ||||
|  | ||||
| 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) { | ||||
| 	recordinfo := AVCDecoderConfRecord{} | ||||
| 	recordinfo.AVCProfileIndication = sps[1] | ||||
| 	recordinfo.ProfileCompatibility = sps[2] | ||||
| 	recordinfo.AVCLevelIndication = sps[3] | ||||
| 	recordinfo.AVCProfileIndication = sps[3] | ||||
| 	recordinfo.ProfileCompatibility = sps[4] | ||||
| 	recordinfo.AVCLevelIndication = sps[5] | ||||
| 	recordinfo.SPS = [][]byte{sps} | ||||
| 	recordinfo.PPS = [][]byte{pps} | ||||
| 	recordinfo.VPS = [][]byte{vps} | ||||
| 	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 { | ||||
| 		return | ||||
| 	} | ||||
| 	buf := make([]byte, recordinfo.Len()) | ||||
| 	recordinfo.Marshal(buf, self.SPSInfo) | ||||
| 	self.RecordInfo = recordinfo | ||||
| 	self.Record = buf | ||||
| 	return | ||||
| } | ||||
|  | ||||
| @@ -480,14 +512,12 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) { | ||||
| 		err = ErrDecconfInvalid | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	self.AVCProfileIndication = b[1] | ||||
| 	self.ProfileCompatibility = b[2] | ||||
| 	self.AVCLevelIndication = b[3] | ||||
| 	self.LengthSizeMinusOne = b[4] & 0x03 | ||||
| 	spscount := int(b[5] & 0x1f) | ||||
| 	n += 6 | ||||
|  | ||||
| 	for i := 0; i < spscount; i++ { | ||||
| 		if len(b) < n+2 { | ||||
| 			err = ErrDecconfInvalid | ||||
| @@ -550,55 +580,63 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) { | ||||
| } | ||||
|  | ||||
| func (self AVCDecoderConfRecord) Len() (n int) { | ||||
| 	n = 7 | ||||
| 	n = 23 | ||||
| 	for _, sps := range self.SPS { | ||||
| 		n += 2 + len(sps) | ||||
| 		n += 5 + len(sps) | ||||
| 	} | ||||
| 	for _, pps := range self.PPS { | ||||
| 		n += 2 + len(pps) | ||||
| 		n += 5 + len(pps) | ||||
| 	} | ||||
| 	for _, vps := range self.VPS { | ||||
| 		n += 2 + len(vps) | ||||
| 		n += 5 + len(vps) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (self AVCDecoderConfRecord) Marshal(b []byte) (n int) { | ||||
| func (self AVCDecoderConfRecord) Marshal(b []byte, si SPSInfo) (n int) { | ||||
| 	b[0] = 1 | ||||
| 	b[1] = self.AVCProfileIndication | ||||
| 	b[2] = self.ProfileCompatibility | ||||
| 	b[3] = self.AVCLevelIndication | ||||
| 	b[4] = self.LengthSizeMinusOne | 0xfc | ||||
| 	b[5] = uint8(len(self.SPS)) | 0xe0 | ||||
| 	n += 6 | ||||
|  | ||||
| 	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)) | ||||
| 	b[21] = 3 | ||||
| 	b[22] = 3 | ||||
| 	n += 23 | ||||
| 	b[n] = (self.VPS[0][0] >> 1) & 0x3f | ||||
| 	n++ | ||||
|  | ||||
| 	for _, pps := range self.PPS { | ||||
| 		pio.PutU16BE(b[n:], uint16(len(pps))) | ||||
| 		n += 2 | ||||
| 		copy(b[n:], pps) | ||||
| 		n += len(pps) | ||||
| 	} | ||||
|  | ||||
| 	b[n] = uint8(len(self.VPS)) | ||||
| 	b[n] = byte(len(self.VPS) >> 8) | ||||
| 	n++ | ||||
| 	b[n] = byte(len(self.VPS)) | ||||
| 	n++ | ||||
|  | ||||
| 	for _, vps := range self.VPS { | ||||
| 		pio.PutU16BE(b[n:], uint16(len(vps))) | ||||
| 		n += 2 | ||||
| 		copy(b[n:], 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 | ||||
| } | ||||
|  | ||||
| @@ -623,17 +661,13 @@ const ( | ||||
| ) | ||||
|  | ||||
| func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) { | ||||
|  | ||||
| 	if len(packet) <= 1 { | ||||
| 		err = fmt.Errorf("h265parser: packet too short to parse slice header") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	nal_unit_type := packet[0] & 0x1f | ||||
| 	switch nal_unit_type { | ||||
| 	case 1, 2, 5, 19: | ||||
| 		// slice_layer_without_partitioning_rbsp | ||||
| 		// slice_data_partition_a_layer_rbsp | ||||
|  | ||||
| 	default: | ||||
| 		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:])} | ||||
|  | ||||
| 	// first_mb_in_slice | ||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// slice_type | ||||
| 	var u uint | ||||
| 	if u, err = r.ReadExponentialGolombCode(); err != nil { | ||||
| 		return | ||||
| @@ -664,6 +694,5 @@ func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) { | ||||
| 		err = fmt.Errorf("h265parser: slice_type=%d invalid", u) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|   | ||||
| @@ -181,6 +181,7 @@ func (self *Stream) fillTrackAtom() (err error) { | ||||
| 	} else if self.Type() == av.H265 { | ||||
| 		codec := self.CodecData.(h265parser.CodecData) | ||||
| 		width, height := codec.Width(), codec.Height() | ||||
|  | ||||
| 		self.sample.SampleDesc.HV1Desc = &mp4io.HV1Desc{ | ||||
| 			DataRefIdx:           1, | ||||
| 			HorizontalResolution: 72, | ||||
| @@ -192,6 +193,7 @@ func (self *Stream) fillTrackAtom() (err error) { | ||||
| 			ColorTableId:         -1, | ||||
| 			Conf:                 &mp4io.HV1Conf{Data: codec.AVCDecoderConfRecordBytes()}, | ||||
| 		} | ||||
|  | ||||
| 		self.trackAtom.Media.Handler = &mp4io.HandlerRefer{ | ||||
| 			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}, | ||||
| @@ -200,6 +202,7 @@ func (self *Stream) fillTrackAtom() (err error) { | ||||
| 			Flags: 0x000001, | ||||
| 		} | ||||
| 		self.codecString = fmt.Sprintf("hvc1.%02X%02X%02X", codec.RecordInfo.AVCProfileIndication, codec.RecordInfo.ProfileCompatibility, codec.RecordInfo.AVCLevelIndication) | ||||
|  | ||||
| 	} else if self.Type() == av.AAC { | ||||
| 		codec := self.CodecData.(aacparser.CodecData) | ||||
| 		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) { | ||||
| 	//pkt.Data = pkt.Data[4:] | ||||
| 	trackID := pkt.Idx + 1 | ||||
| 	if element.sampleIndex == 0 { | ||||
| 		element.moof.Header = &mp4fio.MovieFragHeader{Seqnum: uint32(element.muxer.fragmentIndex + 1)} | ||||
|   | ||||
| @@ -142,26 +142,33 @@ func Dial(options RTSPClientOptions) (*RTSPClient, error) { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		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 { | ||||
| 						client.sps = i2.SpropParameterSets[0] | ||||
| 						client.pps = i2.SpropParameterSets[1] | ||||
| 						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 { | ||||
| 						client.vps = i2.SpropVPS | ||||
| 						client.sps = i2.SpropSPS | ||||
| 						client.pps = i2.SpropPPS | ||||
| 						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 { | ||||
| 				client.Println("SDP Video Codec Type Not Supported", i2.Type) | ||||
| 			} | ||||
| 			client.videoIDX = int8(len(client.CodecData) - 1) | ||||
| 			client.videoID = ch | ||||
| 		} | ||||
| 		if i2.AVType == AUDIO { | ||||
| @@ -552,7 +559,7 @@ func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) { | ||||
| 						Data:            append(binSize(len(nal)), nal...), | ||||
| 						CompositionTime: time.Duration(1) * time.Millisecond, | ||||
| 						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, | ||||
| 						Time:            time.Duration(timestamp/90) * time.Millisecond, | ||||
| 					}) | ||||
| @@ -564,22 +571,19 @@ func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) { | ||||
| 					client.CodecUpdatePPS(nal) | ||||
| 				case h265parser.NAL_UNIT_UNSPECIFIED_49: | ||||
| 					se := nal[2] >> 6 | ||||
| 					naluType = nal[2] & 0x3f | ||||
| 					naluType := nal[2] & 0x3f | ||||
| 					if se == 2 { | ||||
| 						client.BufferRtpPacket.Truncate(0) | ||||
| 						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[1] = nal[1] | ||||
| 						r[0] = (nal[0] & 0x81) | (naluType << 1) | ||||
| 						client.BufferRtpPacket.Write(nal[3:]) | ||||
| 					} else if se == 1 { | ||||
| 						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{ | ||||
| 							Data:            append(binSize(len(nal)), nal...), | ||||
| 							Data:            append(binSize(client.BufferRtpPacket.Len()), client.BufferRtpPacket.Bytes()...), | ||||
| 							CompositionTime: time.Duration(1) * time.Millisecond, | ||||
| 							Idx:             client.videoIDX, | ||||
| 							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:]) | ||||
| 					} | ||||
| 				default: | ||||
| 					//log.Println("???", naluType) | ||||
| 					client.Println("Unsupported Nal", naluType) | ||||
| 				} | ||||
|  | ||||
| 			} else if client.videoCodec == av.H264 { | ||||
| 				naluType := nal[0] & 0x1f | ||||
| 				switch { | ||||
|   | ||||
| @@ -195,6 +195,9 @@ func (element *Muxer) WritePacket(pkt av.Packet) (err error) { | ||||
| 	} | ||||
| 	if tmp, ok := element.streams[pkt.Idx]; ok { | ||||
| 		element.StreamACK.Reset(10 * time.Second) | ||||
| 		if len(pkt.Data) < 5 { | ||||
| 			return nil | ||||
| 		} | ||||
| 		switch tmp.codec.Type() { | ||||
| 		case av.H264: | ||||
| 			codec := tmp.codec.(h264parser.CodecData) | ||||
|   | ||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -5,4 +5,5 @@ go 1.14 | ||||
| require ( | ||||
| 	github.com/pion/webrtc/v2 v2.2.23 // 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/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| 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 | ||||
| } | ||||
|  | ||||
| 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) { | ||||
| 	i := 0 | ||||
| 	for { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Andrey Semochkin
					Andrey Semochkin