start work h265
This commit is contained in:
		
							
								
								
									
										669
									
								
								codec/h265parser/parser.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										669
									
								
								codec/h265parser/parser.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,669 @@ | ||||
| package h265parser | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/deepch/vdk/av" | ||||
| 	"github.com/deepch/vdk/utils/bits" | ||||
| 	"github.com/deepch/vdk/utils/bits/pio" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	NAL_UNIT_CODED_SLICE_TRAIL_N    = 0 | ||||
| 	NAL_UNIT_CODED_SLICE_TRAIL_R    = 1 | ||||
| 	NAL_UNIT_CODED_SLICE_TSA_N      = 2 | ||||
| 	NAL_UNIT_CODED_SLICE_TSA_R      = 3 | ||||
| 	NAL_UNIT_CODED_SLICE_STSA_N     = 4 | ||||
| 	NAL_UNIT_CODED_SLICE_STSA_R     = 5 | ||||
| 	NAL_UNIT_CODED_SLICE_RADL_N     = 6 | ||||
| 	NAL_UNIT_CODED_SLICE_RADL_R     = 7 | ||||
| 	NAL_UNIT_CODED_SLICE_RASL_N     = 8 | ||||
| 	NAL_UNIT_CODED_SLICE_RASL_R     = 9 | ||||
| 	NAL_UNIT_RESERVED_VCL_N10       = 10 | ||||
| 	NAL_UNIT_RESERVED_VCL_R11       = 11 | ||||
| 	NAL_UNIT_RESERVED_VCL_N12       = 12 | ||||
| 	NAL_UNIT_RESERVED_VCL_R13       = 13 | ||||
| 	NAL_UNIT_RESERVED_VCL_N14       = 14 | ||||
| 	NAL_UNIT_RESERVED_VCL_R15       = 15 | ||||
| 	NAL_UNIT_CODED_SLICE_BLA_W_LP   = 16 | ||||
| 	NAL_UNIT_CODED_SLICE_BLA_W_RADL = 17 | ||||
| 	NAL_UNIT_CODED_SLICE_BLA_N_LP   = 18 | ||||
| 	NAL_UNIT_CODED_SLICE_IDR_W_RADL = 19 | ||||
| 	NAL_UNIT_CODED_SLICE_IDR_N_LP   = 20 | ||||
| 	NAL_UNIT_CODED_SLICE_CRA        = 21 | ||||
| 	NAL_UNIT_RESERVED_IRAP_VCL22    = 22 | ||||
| 	NAL_UNIT_RESERVED_IRAP_VCL23    = 23 | ||||
| 	NAL_UNIT_RESERVED_VCL24         = 24 | ||||
| 	NAL_UNIT_RESERVED_VCL25         = 25 | ||||
| 	NAL_UNIT_RESERVED_VCL26         = 26 | ||||
| 	NAL_UNIT_RESERVED_VCL27         = 27 | ||||
| 	NAL_UNIT_RESERVED_VCL28         = 28 | ||||
| 	NAL_UNIT_RESERVED_VCL29         = 29 | ||||
| 	NAL_UNIT_RESERVED_VCL30         = 30 | ||||
| 	NAL_UNIT_RESERVED_VCL31         = 31 | ||||
| 	NAL_UNIT_VPS                    = 32 | ||||
| 	NAL_UNIT_SPS                    = 33 | ||||
| 	NAL_UNIT_PPS                    = 34 | ||||
| 	NAL_UNIT_ACCESS_UNIT_DELIMITER  = 35 | ||||
| 	NAL_UNIT_EOS                    = 36 | ||||
| 	NAL_UNIT_EOB                    = 37 | ||||
| 	NAL_UNIT_FILLER_DATA            = 38 | ||||
| 	NAL_UNIT_PREFIX_SEI             = 39 | ||||
| 	NAL_UNIT_SUFFIX_SEI             = 40 | ||||
| 	NAL_UNIT_RESERVED_NVCL41        = 41 | ||||
| 	NAL_UNIT_RESERVED_NVCL42        = 42 | ||||
| 	NAL_UNIT_RESERVED_NVCL43        = 43 | ||||
| 	NAL_UNIT_RESERVED_NVCL44        = 44 | ||||
| 	NAL_UNIT_RESERVED_NVCL45        = 45 | ||||
| 	NAL_UNIT_RESERVED_NVCL46        = 46 | ||||
| 	NAL_UNIT_RESERVED_NVCL47        = 47 | ||||
| 	NAL_UNIT_UNSPECIFIED_48         = 48 | ||||
| 	NAL_UNIT_UNSPECIFIED_49         = 49 | ||||
| 	NAL_UNIT_UNSPECIFIED_50         = 50 | ||||
| 	NAL_UNIT_UNSPECIFIED_51         = 51 | ||||
| 	NAL_UNIT_UNSPECIFIED_52         = 52 | ||||
| 	NAL_UNIT_UNSPECIFIED_53         = 53 | ||||
| 	NAL_UNIT_UNSPECIFIED_54         = 54 | ||||
| 	NAL_UNIT_UNSPECIFIED_55         = 55 | ||||
| 	NAL_UNIT_UNSPECIFIED_56         = 56 | ||||
| 	NAL_UNIT_UNSPECIFIED_57         = 57 | ||||
| 	NAL_UNIT_UNSPECIFIED_58         = 58 | ||||
| 	NAL_UNIT_UNSPECIFIED_59         = 59 | ||||
| 	NAL_UNIT_UNSPECIFIED_60         = 60 | ||||
| 	NAL_UNIT_UNSPECIFIED_61         = 61 | ||||
| 	NAL_UNIT_UNSPECIFIED_62         = 62 | ||||
| 	NAL_UNIT_UNSPECIFIED_63         = 63 | ||||
| 	NAL_UNIT_INVALID                = 64 | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	MAX_VPS_COUNT  = 16 | ||||
| 	MAX_SUB_LAYERS = 7 | ||||
| 	MAX_SPS_COUNT  = 32 | ||||
| ) | ||||
|  | ||||
| func IsDataNALU(b []byte) bool { | ||||
| 	typ := b[0] & 0x1f | ||||
| 	return typ >= 1 && typ <= 5 | ||||
| } | ||||
|  | ||||
| var StartCodeBytes = []byte{0, 0, 1} | ||||
| var AUDBytes = []byte{0, 0, 0, 1, 0x9, 0xf0, 0, 0, 0, 1} // AUD | ||||
|  | ||||
| func CheckNALUsType(b []byte) (typ int) { | ||||
| 	_, typ = SplitNALUs(b) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	NALU_RAW = iota | ||||
| 	NALU_AVCC | ||||
| 	NALU_ANNEXB | ||||
| ) | ||||
|  | ||||
| func SplitNALUs(b []byte) (nalus [][]byte, typ int) { | ||||
| 	if len(b) < 4 { | ||||
| 		return [][]byte{b}, NALU_RAW | ||||
| 	} | ||||
| 	val3 := pio.U24BE(b) | ||||
| 	val4 := pio.U32BE(b) | ||||
| 	if val4 <= uint32(len(b)) { | ||||
| 		_val4 := val4 | ||||
| 		_b := b[4:] | ||||
| 		nalus := [][]byte{} | ||||
| 		for { | ||||
| 			nalus = append(nalus, _b[:_val4]) | ||||
| 			_b = _b[_val4:] | ||||
| 			if len(_b) < 4 { | ||||
| 				break | ||||
| 			} | ||||
| 			_val4 = pio.U32BE(_b) | ||||
| 			_b = _b[4:] | ||||
| 			if _val4 > uint32(len(_b)) { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		if len(_b) == 0 { | ||||
| 			return nalus, NALU_AVCC | ||||
| 		} | ||||
| 	} | ||||
| 	// is Annex B | ||||
| 	if val3 == 1 || val4 == 1 { | ||||
| 		_val3 := val3 | ||||
| 		_val4 := val4 | ||||
| 		start := 0 | ||||
| 		pos := 0 | ||||
| 		for { | ||||
| 			if start != pos { | ||||
| 				nalus = append(nalus, b[start:pos]) | ||||
| 			} | ||||
| 			if _val3 == 1 { | ||||
| 				pos += 3 | ||||
| 			} else if _val4 == 1 { | ||||
| 				pos += 4 | ||||
| 			} | ||||
| 			start = pos | ||||
| 			if start == len(b) { | ||||
| 				break | ||||
| 			} | ||||
| 			_val3 = 0 | ||||
| 			_val4 = 0 | ||||
| 			for pos < len(b) { | ||||
| 				if pos+2 < len(b) && b[pos] == 0 { | ||||
| 					_val3 = pio.U24BE(b[pos:]) | ||||
| 					if _val3 == 0 { | ||||
| 						if pos+3 < len(b) { | ||||
| 							_val4 = uint32(b[pos+3]) | ||||
| 							if _val4 == 1 { | ||||
| 								break | ||||
| 							} | ||||
| 						} | ||||
| 					} else if _val3 == 1 { | ||||
| 						break | ||||
| 					} | ||||
| 					pos++ | ||||
| 				} else { | ||||
| 					pos++ | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		typ = NALU_ANNEXB | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	return [][]byte{b}, NALU_RAW | ||||
| } | ||||
|  | ||||
| type SPSInfo struct { | ||||
| 	ProfileIdc uint | ||||
| 	LevelIdc   uint | ||||
|  | ||||
| 	MbWidth  uint | ||||
| 	MbHeight uint | ||||
|  | ||||
| 	CropLeft   uint | ||||
| 	CropRight  uint | ||||
| 	CropTop    uint | ||||
| 	CropBottom uint | ||||
|  | ||||
| 	Width  uint | ||||
| 	Height uint | ||||
| } | ||||
|  | ||||
| func ParseSPS(data []byte) (self SPSInfo, err error) { | ||||
| 	r := &bits.GolombBitReader{R: bytes.NewReader(data)} | ||||
|  | ||||
| 	if _, err = r.ReadBits(8); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if self.ProfileIdc, err = r.ReadBits(8); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// constraint_set0_flag-constraint_set6_flag,reserved_zero_2bits | ||||
| 	if _, err = r.ReadBits(8); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// level_idc | ||||
| 	if self.LevelIdc, err = r.ReadBits(8); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// seq_parameter_set_id | ||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	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 chroma_format_idc == 3 { | ||||
| 			// residual_colour_transform_flag | ||||
| 			if _, err = r.ReadBit(); err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// bit_depth_luma_minus8 | ||||
| 		if _, err = r.ReadExponentialGolombCode(); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		// bit_depth_chroma_minus8 | ||||
| 		if _, err = r.ReadExponentialGolombCode(); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 		// qpprime_y_zero_transform_bypass_flag | ||||
| 		if _, err = r.ReadBit(); err != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		var seq_scaling_matrix_present_flag uint | ||||
| 		if seq_scaling_matrix_present_flag, err = r.ReadBit(); err != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		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 | ||||
| 					} 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 | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// log2_max_frame_num_minus4 | ||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	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 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// max_num_ref_frames | ||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// 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 | ||||
| } | ||||
|  | ||||
| type CodecData struct { | ||||
| 	Record     []byte | ||||
| 	RecordInfo AVCDecoderConfRecord | ||||
| 	SPSInfo    SPSInfo | ||||
| } | ||||
|  | ||||
| func (self CodecData) Type() av.CodecType { | ||||
| 	return av.H265 | ||||
| } | ||||
|  | ||||
| func (self CodecData) AVCDecoderConfRecordBytes() []byte { | ||||
| 	return self.Record | ||||
| } | ||||
|  | ||||
| func (self CodecData) SPS() []byte { | ||||
| 	return self.RecordInfo.SPS[0] | ||||
| } | ||||
|  | ||||
| func (self CodecData) PPS() []byte { | ||||
| 	return self.RecordInfo.PPS[0] | ||||
| } | ||||
|  | ||||
| func (self CodecData) VPS() []byte { | ||||
| 	return self.RecordInfo.VPS[0] | ||||
| } | ||||
|  | ||||
| func (self CodecData) Width() int { | ||||
| 	return int(self.SPSInfo.Width) | ||||
| } | ||||
|  | ||||
| func (self CodecData) Height() int { | ||||
| 	return int(self.SPSInfo.Height) | ||||
| } | ||||
|  | ||||
| func NewCodecDataFromAVCDecoderConfRecord(record []byte) (self CodecData, err error) { | ||||
| 	self.Record = record | ||||
| 	if _, err = (&self.RecordInfo).Unmarshal(record); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if len(self.RecordInfo.SPS) == 0 { | ||||
| 		err = fmt.Errorf("h265parser: no SPS found in AVCDecoderConfRecord") | ||||
| 		return | ||||
| 	} | ||||
| 	if len(self.RecordInfo.PPS) == 0 { | ||||
| 		err = fmt.Errorf("h265parser: no PPS found in AVCDecoderConfRecord") | ||||
| 		return | ||||
| 	} | ||||
| 	if len(self.RecordInfo.VPS) == 0 { | ||||
| 		err = fmt.Errorf("h265parser: no VPS found in AVCDecoderConfRecord") | ||||
| 		return | ||||
| 	} | ||||
| 	if self.SPSInfo, err = ParseSPS(self.RecordInfo.SPS[0]); err != nil { | ||||
| 		err = fmt.Errorf("h265parser: parse SPS failed(%s)", err) | ||||
| 		return | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func NewCodecDataFromSPSAndPPS(sps, pps, vps []byte) (self CodecData, err error) { | ||||
| 	recordinfo := AVCDecoderConfRecord{} | ||||
| 	recordinfo.AVCProfileIndication = sps[1] | ||||
| 	recordinfo.ProfileCompatibility = sps[2] | ||||
| 	recordinfo.AVCLevelIndication = sps[3] | ||||
| 	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 | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| type AVCDecoderConfRecord struct { | ||||
| 	AVCProfileIndication uint8 | ||||
| 	ProfileCompatibility uint8 | ||||
| 	AVCLevelIndication   uint8 | ||||
| 	LengthSizeMinusOne   uint8 | ||||
| 	SPS                  [][]byte | ||||
| 	PPS                  [][]byte | ||||
| 	VPS                  [][]byte | ||||
| } | ||||
|  | ||||
| var ErrDecconfInvalid = fmt.Errorf("h265parser: AVCDecoderConfRecord invalid") | ||||
|  | ||||
| func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) { | ||||
| 	if len(b) < 7 { | ||||
| 		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 | ||||
| 			return | ||||
| 		} | ||||
| 		spslen := int(pio.U16BE(b[n:])) | ||||
| 		n += 2 | ||||
|  | ||||
| 		if len(b) < n+spslen { | ||||
| 			err = ErrDecconfInvalid | ||||
| 			return | ||||
| 		} | ||||
| 		self.SPS = append(self.SPS, b[n:n+spslen]) | ||||
| 		n += spslen | ||||
| 	} | ||||
|  | ||||
| 	if len(b) < n+1 { | ||||
| 		err = ErrDecconfInvalid | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ppscount := int(b[n]) | ||||
| 	n++ | ||||
|  | ||||
| 	for i := 0; i < ppscount; i++ { | ||||
| 		if len(b) < n+2 { | ||||
| 			err = ErrDecconfInvalid | ||||
| 			return | ||||
| 		} | ||||
| 		ppslen := int(pio.U16BE(b[n:])) | ||||
| 		n += 2 | ||||
|  | ||||
| 		if len(b) < n+ppslen { | ||||
| 			err = ErrDecconfInvalid | ||||
| 			return | ||||
| 		} | ||||
| 		self.PPS = append(self.PPS, b[n:n+ppslen]) | ||||
| 		n += ppslen | ||||
| 	} | ||||
|  | ||||
| 	vpscount := int(b[n]) | ||||
| 	n++ | ||||
|  | ||||
| 	for i := 0; i < vpscount; i++ { | ||||
| 		if len(b) < n+2 { | ||||
| 			err = ErrDecconfInvalid | ||||
| 			return | ||||
| 		} | ||||
| 		vpslen := int(pio.U16BE(b[n:])) | ||||
| 		n += 2 | ||||
|  | ||||
| 		if len(b) < n+vpslen { | ||||
| 			err = ErrDecconfInvalid | ||||
| 			return | ||||
| 		} | ||||
| 		self.VPS = append(self.VPS, b[n:n+vpslen]) | ||||
| 		n += vpslen | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (self AVCDecoderConfRecord) Len() (n int) { | ||||
| 	n = 7 | ||||
| 	for _, sps := range self.SPS { | ||||
| 		n += 2 + len(sps) | ||||
| 	} | ||||
| 	for _, pps := range self.PPS { | ||||
| 		n += 2 + len(pps) | ||||
| 	} | ||||
| 	for _, vps := range self.VPS { | ||||
| 		n += 2 + len(vps) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (self AVCDecoderConfRecord) Marshal(b []byte) (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)) | ||||
| 	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)) | ||||
| 	n++ | ||||
|  | ||||
| 	for _, vps := range self.VPS { | ||||
| 		pio.PutU16BE(b[n:], uint16(len(vps))) | ||||
| 		n += 2 | ||||
| 		copy(b[n:], vps) | ||||
| 		n += len(vps) | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| type SliceType uint | ||||
|  | ||||
| func (self SliceType) String() string { | ||||
| 	switch self { | ||||
| 	case SLICE_P: | ||||
| 		return "P" | ||||
| 	case SLICE_B: | ||||
| 		return "B" | ||||
| 	case SLICE_I: | ||||
| 		return "I" | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	SLICE_P = iota + 1 | ||||
| 	SLICE_B | ||||
| 	SLICE_I | ||||
| ) | ||||
|  | ||||
| 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) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	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 | ||||
| 	} | ||||
|  | ||||
| 	switch u { | ||||
| 	case 0, 3, 5, 8: | ||||
| 		sliceType = SLICE_P | ||||
| 	case 1, 6: | ||||
| 		sliceType = SLICE_B | ||||
| 	case 2, 4, 7, 9: | ||||
| 		sliceType = SLICE_I | ||||
| 	default: | ||||
| 		err = fmt.Errorf("h265parser: slice_type=%d invalid", u) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Andrey Semochkin
					Andrey Semochkin