work HEVC in progress next v3
This commit is contained in:
		| @@ -441,7 +441,7 @@ func NewCodecDataFromAVCDecoderConfRecord(record []byte) (self CodecData, err er | |||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewCodecDataFromSPSAndPPS(sps, pps, vps []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[1] | ||||||
| 	recordinfo.ProfileCompatibility = sps[2] | 	recordinfo.ProfileCompatibility = sps[2] | ||||||
| @@ -468,9 +468,9 @@ type AVCDecoderConfRecord struct { | |||||||
| 	ProfileCompatibility uint8 | 	ProfileCompatibility uint8 | ||||||
| 	AVCLevelIndication   uint8 | 	AVCLevelIndication   uint8 | ||||||
| 	LengthSizeMinusOne   uint8 | 	LengthSizeMinusOne   uint8 | ||||||
|  | 	VPS                  [][]byte | ||||||
| 	SPS                  [][]byte | 	SPS                  [][]byte | ||||||
| 	PPS                  [][]byte | 	PPS                  [][]byte | ||||||
| 	VPS                  [][]byte |  | ||||||
| } | } | ||||||
|  |  | ||||||
| var ErrDecconfInvalid = fmt.Errorf("h265parser: AVCDecoderConfRecord invalid") | var ErrDecconfInvalid = fmt.Errorf("h265parser: AVCDecoderConfRecord invalid") | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ import ( | |||||||
| 	"github.com/deepch/vdk/av" | 	"github.com/deepch/vdk/av" | ||||||
| 	"github.com/deepch/vdk/codec/aacparser" | 	"github.com/deepch/vdk/codec/aacparser" | ||||||
| 	"github.com/deepch/vdk/codec/h264parser" | 	"github.com/deepch/vdk/codec/h264parser" | ||||||
|  | 	"github.com/deepch/vdk/codec/h265parser" | ||||||
| 	"github.com/deepch/vdk/format/mp4/mp4io" | 	"github.com/deepch/vdk/format/mp4/mp4io" | ||||||
| 	"github.com/deepch/vdk/format/mp4f/mp4fio" | 	"github.com/deepch/vdk/format/mp4f/mp4fio" | ||||||
| 	"github.com/deepch/vdk/utils/bits/pio" | 	"github.com/deepch/vdk/utils/bits/pio" | ||||||
| @@ -178,7 +179,7 @@ func (self *Stream) fillTrackAtom() (err error) { | |||||||
| 		} | 		} | ||||||
| 		self.codecString = fmt.Sprintf("avc1.%02X%02X%02X", codec.RecordInfo.AVCProfileIndication, codec.RecordInfo.ProfileCompatibility, codec.RecordInfo.AVCLevelIndication) | 		self.codecString = fmt.Sprintf("avc1.%02X%02X%02X", codec.RecordInfo.AVCProfileIndication, codec.RecordInfo.ProfileCompatibility, codec.RecordInfo.AVCLevelIndication) | ||||||
| 	} else if self.Type() == av.H265 { | 	} else if self.Type() == av.H265 { | ||||||
| 		codec := self.CodecData.(h264parser.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, | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import ( | |||||||
| 	"encoding/base64" | 	"encoding/base64" | ||||||
| 	"encoding/hex" | 	"encoding/hex" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"log" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| @@ -23,6 +24,9 @@ type Media struct { | |||||||
| 	ChannelCount       int | 	ChannelCount       int | ||||||
| 	Config             []byte | 	Config             []byte | ||||||
| 	SpropParameterSets [][]byte | 	SpropParameterSets [][]byte | ||||||
|  | 	SpropVPS           []byte | ||||||
|  | 	SpropSPS           []byte | ||||||
|  | 	SpropPPS           []byte | ||||||
| 	PayloadType        int | 	PayloadType        int | ||||||
| 	SizeLength         int | 	SizeLength         int | ||||||
| 	IndexLength        int | 	IndexLength        int | ||||||
| @@ -93,6 +97,10 @@ func Parse(content string) (sess Session, medias []Media) { | |||||||
| 								} | 								} | ||||||
| 							case "H264": | 							case "H264": | ||||||
| 								media.Type = av.H264 | 								media.Type = av.H264 | ||||||
|  | 							case "H265": | ||||||
|  | 								media.Type = av.H265 | ||||||
|  | 							case "HEVC": | ||||||
|  | 								media.Type = av.H265 | ||||||
| 							} | 							} | ||||||
| 							if i, err := strconv.Atoi(keyval[1]); err == nil { | 							if i, err := strconv.Atoi(keyval[1]); err == nil { | ||||||
| 								media.TimeScale = i | 								media.TimeScale = i | ||||||
| @@ -115,6 +123,27 @@ func Parse(content string) (sess Session, medias []Media) { | |||||||
| 										media.SizeLength, _ = strconv.Atoi(val) | 										media.SizeLength, _ = strconv.Atoi(val) | ||||||
| 									case "indexlength": | 									case "indexlength": | ||||||
| 										media.IndexLength, _ = strconv.Atoi(val) | 										media.IndexLength, _ = strconv.Atoi(val) | ||||||
|  | 									case "sprop-vps": | ||||||
|  | 										val, err := base64.StdEncoding.DecodeString(val) | ||||||
|  | 										if err == nil { | ||||||
|  | 											media.SpropVPS = val | ||||||
|  | 										} else { | ||||||
|  | 											log.Println("SDP: decode vps error", err) | ||||||
|  | 										} | ||||||
|  | 									case "sprop-sps": | ||||||
|  | 										val, err := base64.StdEncoding.DecodeString(val) | ||||||
|  | 										if err == nil { | ||||||
|  | 											media.SpropSPS = val | ||||||
|  | 										} else { | ||||||
|  | 											log.Println("SDP: decode sps error", err) | ||||||
|  | 										} | ||||||
|  | 									case "sprop-pps": | ||||||
|  | 										val, err := base64.StdEncoding.DecodeString(val) | ||||||
|  | 										if err == nil { | ||||||
|  | 											media.SpropPPS = val | ||||||
|  | 										} else { | ||||||
|  | 											log.Println("SDP: decode pps error", err) | ||||||
|  | 										} | ||||||
| 									case "sprop-parameter-sets": | 									case "sprop-parameter-sets": | ||||||
| 										fields := strings.Split(val, ",") | 										fields := strings.Split(val, ",") | ||||||
| 										for _, field := range fields { | 										for _, field := range fields { | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ import ( | |||||||
| 	"github.com/deepch/vdk/codec" | 	"github.com/deepch/vdk/codec" | ||||||
| 	"github.com/deepch/vdk/codec/aacparser" | 	"github.com/deepch/vdk/codec/aacparser" | ||||||
| 	"github.com/deepch/vdk/codec/h264parser" | 	"github.com/deepch/vdk/codec/h264parser" | ||||||
|  | 	"github.com/deepch/vdk/codec/h265parser" | ||||||
| 	"github.com/deepch/vdk/format/rtsp/sdp" | 	"github.com/deepch/vdk/format/rtsp/sdp" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -72,12 +73,14 @@ type RTSPClient struct { | |||||||
| 	fuStarted           bool | 	fuStarted           bool | ||||||
| 	options             RTSPClientOptions | 	options             RTSPClientOptions | ||||||
| 	BufferRtpPacket     *bytes.Buffer | 	BufferRtpPacket     *bytes.Buffer | ||||||
|  | 	vps                 []byte | ||||||
| 	sps                 []byte | 	sps                 []byte | ||||||
| 	pps                 []byte | 	pps                 []byte | ||||||
| 	CodecData           []av.CodecData | 	CodecData           []av.CodecData | ||||||
| 	AudioTimeLine       time.Duration | 	AudioTimeLine       time.Duration | ||||||
| 	AudioTimeScale      int64 | 	AudioTimeScale      int64 | ||||||
| 	audioCodec          av.CodecType | 	audioCodec          av.CodecType | ||||||
|  | 	videoCodec          av.CodecType | ||||||
| 	PreAudioTS          int64 | 	PreAudioTS          int64 | ||||||
| 	PreVideoTS          int64 | 	PreVideoTS          int64 | ||||||
| 	PreSequenceNumber   int | 	PreSequenceNumber   int | ||||||
| @@ -145,6 +148,16 @@ func Dial(options RTSPClientOptions) (*RTSPClient, error) { | |||||||
| 					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.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 { | ||||||
|  | 				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 { | 			} else { | ||||||
| 				client.Println("SDP Video Codec Type Not Supported", i2.Type) | 				client.Println("SDP Video Codec Type Not Supported", i2.Type) | ||||||
| @@ -531,70 +544,119 @@ func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) { | |||||||
| 		nalRaw, _ := h264parser.SplitNALUs(content[offset:end]) | 		nalRaw, _ := h264parser.SplitNALUs(content[offset:end]) | ||||||
| 		var retmap []*av.Packet | 		var retmap []*av.Packet | ||||||
| 		for _, nal := range nalRaw { | 		for _, nal := range nalRaw { | ||||||
| 			naluType := nal[0] & 0x1f | 			if client.videoCodec == av.H265 { | ||||||
| 			switch { | 				naluType := (nal[0] >> 1) & 0x3f | ||||||
| 			case naluType >= 1 && naluType <= 5: | 				switch naluType { | ||||||
| 				retmap = append(retmap, &av.Packet{ | 				case h265parser.NAL_UNIT_CODED_SLICE_TRAIL_R: | ||||||
| 					Data:            append(binSize(len(nal)), nal...), | 					retmap = append(retmap, &av.Packet{ | ||||||
| 					CompositionTime: time.Duration(1) * time.Millisecond, | 						Data:            append(binSize(len(nal)), nal...), | ||||||
| 					Idx:             client.videoIDX, | 						CompositionTime: time.Duration(1) * time.Millisecond, | ||||||
| 					IsKeyFrame:      naluType == 5, | 						Idx:             client.videoIDX, | ||||||
| 					Duration:        time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond, | 						IsKeyFrame:      naluType == h265parser.NAL_UNIT_CODED_SLICE_IDR_W_RADL, | ||||||
| 					Time:            time.Duration(timestamp/90) * time.Millisecond, | 						Duration:        time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond, | ||||||
| 				}) | 						Time:            time.Duration(timestamp/90) * time.Millisecond, | ||||||
| 			case naluType == 7: | 					}) | ||||||
| 				client.CodecUpdateSPS(nal) | 				case h265parser.NAL_UNIT_VPS: | ||||||
| 			case naluType == 8: | 					client.CodecUpdateVPS(nal) | ||||||
| 				client.CodecUpdatePPS(nal) | 				case h265parser.NAL_UNIT_SPS: | ||||||
| 			case naluType == 24: | 					client.CodecUpdateSPS(nal) | ||||||
| 				client.Println("24 Type need add next version report https://github.com/deepch/vdk") | 				case h265parser.NAL_UNIT_PPS: | ||||||
| 			case naluType == 28: | 					client.CodecUpdatePPS(nal) | ||||||
| 				fuIndicator := content[offset] | 				case h265parser.NAL_UNIT_UNSPECIFIED_49: | ||||||
| 				fuHeader := content[offset+1] | 					se := nal[2] >> 6 | ||||||
| 				isStart := fuHeader&0x80 != 0 | 					naluType = nal[2] & 0x3f | ||||||
| 				isEnd := fuHeader&0x40 != 0 | 					if se == 2 { | ||||||
| 				if isStart { | 						client.BufferRtpPacket.Truncate(0) | ||||||
| 					client.fuStarted = true | 						client.BufferRtpPacket.Reset() | ||||||
| 					client.BufferRtpPacket.Truncate(0) | 						client.BufferRtpPacket.Write([]byte{0, 0, 0, 0, (nal[0] & 0x81) | (naluType << 1), nal[1]}) | ||||||
| 					client.BufferRtpPacket.Reset() | 						r := make([]byte, 2) | ||||||
| 					client.BufferRtpPacket.Write([]byte{fuIndicator&0xe0 | fuHeader&0x1f}) | 						r[1] = nal[1] | ||||||
| 				} | 						r[0] = (nal[0] & 0x81) | (naluType << 1) | ||||||
| 				if client.fuStarted { | 						client.BufferRtpPacket.Write(nal[3:]) | ||||||
| 					client.BufferRtpPacket.Write(content[offset+2 : end]) | 					} else if se == 1 { | ||||||
| 					if isEnd { | 						client.BufferRtpPacket.Write(nal[3:]) | ||||||
| 						client.fuStarted = false | 						binary.BigEndian.PutUint32(client.BufferRtpPacket.Bytes()[:4], uint32(client.BufferRtpPacket.Len())-4) | ||||||
| 						naluTypef := client.BufferRtpPacket.Bytes()[0] & 0x1f | 						buf := make([]byte, client.BufferRtpPacket.Len()) | ||||||
| 						if naluTypef == 7 { | 						copy(buf, client.BufferRtpPacket.Bytes()) | ||||||
| 							bufered, _ := h264parser.SplitNALUs(append([]byte{0, 0, 0, 1}, client.BufferRtpPacket.Bytes()...)) |  | ||||||
| 							for _, v := range bufered { |  | ||||||
| 								naluTypefs := v[0] & 0x1f |  | ||||||
| 								switch { |  | ||||||
| 								case naluTypefs == 5: |  | ||||||
| 									client.BufferRtpPacket.Reset() |  | ||||||
| 									client.BufferRtpPacket.Write(v) |  | ||||||
| 									naluTypef = 5 |  | ||||||
| 								case naluTypefs == 7: |  | ||||||
| 									client.CodecUpdateSPS(v) |  | ||||||
| 								case naluTypefs == 8: |  | ||||||
| 									client.CodecUpdatePPS(v) |  | ||||||
| 								} |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 						retmap = append(retmap, &av.Packet{ | 						retmap = append(retmap, &av.Packet{ | ||||||
| 							Data:            append(binSize(client.BufferRtpPacket.Len()), client.BufferRtpPacket.Bytes()...), | 							Data:            append(binSize(len(nal)), nal...), | ||||||
| 							CompositionTime: time.Duration(1) * time.Millisecond, | 							CompositionTime: time.Duration(1) * time.Millisecond, | ||||||
| 							Duration:        time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond, |  | ||||||
| 							Idx:             client.videoIDX, | 							Idx:             client.videoIDX, | ||||||
| 							IsKeyFrame:      naluTypef == 5, | 							IsKeyFrame:      naluType == h265parser.NAL_UNIT_CODED_SLICE_IDR_W_RADL, | ||||||
|  | 							Duration:        time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond, | ||||||
| 							Time:            time.Duration(timestamp/90) * time.Millisecond, | 							Time:            time.Duration(timestamp/90) * time.Millisecond, | ||||||
| 						}) | 						}) | ||||||
|  | 					} else { | ||||||
|  | 						client.BufferRtpPacket.Write(nal[3:]) | ||||||
| 					} | 					} | ||||||
|  | 				default: | ||||||
|  | 					//log.Println("???", naluType) | ||||||
|  | 				} | ||||||
|  | 			} else if client.videoCodec == av.H264 { | ||||||
|  | 				naluType := nal[0] & 0x1f | ||||||
|  | 				switch { | ||||||
|  | 				case naluType >= 1 && naluType <= 5: | ||||||
|  | 					retmap = append(retmap, &av.Packet{ | ||||||
|  | 						Data:            append(binSize(len(nal)), nal...), | ||||||
|  | 						CompositionTime: time.Duration(1) * time.Millisecond, | ||||||
|  | 						Idx:             client.videoIDX, | ||||||
|  | 						IsKeyFrame:      naluType == 5, | ||||||
|  | 						Duration:        time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond, | ||||||
|  | 						Time:            time.Duration(timestamp/90) * time.Millisecond, | ||||||
|  | 					}) | ||||||
|  | 				case naluType == 7: | ||||||
|  | 					client.CodecUpdateSPS(nal) | ||||||
|  | 				case naluType == 8: | ||||||
|  | 					client.CodecUpdatePPS(nal) | ||||||
|  | 				case naluType == 24: | ||||||
|  | 					client.Println("24 Type need add next version report https://github.com/deepch/vdk") | ||||||
|  | 				case naluType == 28: | ||||||
|  | 					fuIndicator := content[offset] | ||||||
|  | 					fuHeader := content[offset+1] | ||||||
|  | 					isStart := fuHeader&0x80 != 0 | ||||||
|  | 					isEnd := fuHeader&0x40 != 0 | ||||||
|  | 					if isStart { | ||||||
|  | 						client.fuStarted = true | ||||||
|  | 						client.BufferRtpPacket.Truncate(0) | ||||||
|  | 						client.BufferRtpPacket.Reset() | ||||||
|  | 						client.BufferRtpPacket.Write([]byte{fuIndicator&0xe0 | fuHeader&0x1f}) | ||||||
|  | 					} | ||||||
|  | 					if client.fuStarted { | ||||||
|  | 						client.BufferRtpPacket.Write(content[offset+2 : end]) | ||||||
|  | 						if isEnd { | ||||||
|  | 							client.fuStarted = false | ||||||
|  | 							naluTypef := client.BufferRtpPacket.Bytes()[0] & 0x1f | ||||||
|  | 							if naluTypef == 7 { | ||||||
|  | 								bufered, _ := h264parser.SplitNALUs(append([]byte{0, 0, 0, 1}, client.BufferRtpPacket.Bytes()...)) | ||||||
|  | 								for _, v := range bufered { | ||||||
|  | 									naluTypefs := v[0] & 0x1f | ||||||
|  | 									switch { | ||||||
|  | 									case naluTypefs == 5: | ||||||
|  | 										client.BufferRtpPacket.Reset() | ||||||
|  | 										client.BufferRtpPacket.Write(v) | ||||||
|  | 										naluTypef = 5 | ||||||
|  | 									case naluTypefs == 7: | ||||||
|  | 										client.CodecUpdateSPS(v) | ||||||
|  | 									case naluTypefs == 8: | ||||||
|  | 										client.CodecUpdatePPS(v) | ||||||
|  | 									} | ||||||
|  | 								} | ||||||
|  | 							} | ||||||
|  | 							retmap = append(retmap, &av.Packet{ | ||||||
|  | 								Data:            append(binSize(client.BufferRtpPacket.Len()), client.BufferRtpPacket.Bytes()...), | ||||||
|  | 								CompositionTime: time.Duration(1) * time.Millisecond, | ||||||
|  | 								Duration:        time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond, | ||||||
|  | 								Idx:             client.videoIDX, | ||||||
|  | 								IsKeyFrame:      naluTypef == 5, | ||||||
|  | 								Time:            time.Duration(timestamp/90) * time.Millisecond, | ||||||
|  | 							}) | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				default: | ||||||
|  | 					client.Println("Unsupported NAL Type", naluType) | ||||||
| 				} | 				} | ||||||
| 			default: |  | ||||||
| 				client.Println("Unsupported NAL Type", naluType) |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if len(retmap) > 0 { | 		if len(retmap) > 0 { | ||||||
| 			client.PreVideoTS = timestamp | 			client.PreVideoTS = timestamp | ||||||
| 			return retmap, true | 			return retmap, true | ||||||
| @@ -680,49 +742,109 @@ func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (client *RTSPClient) CodecUpdateSPS(val []byte) { | func (client *RTSPClient) CodecUpdateSPS(val []byte) { | ||||||
| 	if bytes.Compare(val, client.sps) != 0 { | 	if client.videoCodec != av.H264 && client.videoCodec != av.H265 { | ||||||
| 		if len(client.sps) > 0 && len(client.pps) > 0 { | 		return | ||||||
| 			codecData, err := h264parser.NewCodecDataFromSPSAndPPS(val, client.pps) | 	} | ||||||
| 			if err != nil { | 	if bytes.Compare(val, client.sps) == 0 { | ||||||
| 				client.Println("Parse Codec Data Error", err) | 		return | ||||||
| 				return | 	} | ||||||
| 			} | 	client.sps = val | ||||||
| 			if len(client.CodecData) > 0 { | 	if (client.videoCodec == av.H264 && len(client.pps) == 0) || (client.videoCodec == av.H265 && (len(client.vps) == 0 || len(client.pps) == 0)) { | ||||||
| 				for i, i2 := range client.CodecData { | 		return | ||||||
| 					if i2.Type().IsVideo() { | 	} | ||||||
| 						client.CodecData[i] = codecData | 	var codecData av.VideoCodecData | ||||||
| 					} | 	var err error | ||||||
| 				} | 	switch client.videoCodec { | ||||||
| 			} else { | 	case av.H264: | ||||||
| 				client.CodecData = append(client.CodecData, codecData) | 		codecData, err = h264parser.NewCodecDataFromSPSAndPPS(val, client.pps) | ||||||
|  | 		if err != nil { | ||||||
|  | 			client.Println("Parse Codec Data Error", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	case av.H265: | ||||||
|  | 		codecData, err = h265parser.NewCodecDataFromVPSAndSPSAndPPS(client.vps, val, client.pps) | ||||||
|  | 		if err != nil { | ||||||
|  | 			client.Println("Parse Codec Data Error", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if len(client.CodecData) > 0 { | ||||||
|  | 		for i, i2 := range client.CodecData { | ||||||
|  | 			if i2.Type().IsVideo() { | ||||||
|  | 				client.CodecData[i] = codecData | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		client.Signals <- SignalCodecUpdate | 	} else { | ||||||
| 		client.sps = val | 		client.CodecData = append(client.CodecData, codecData) | ||||||
| 	} | 	} | ||||||
|  | 	client.Signals <- SignalCodecUpdate | ||||||
| } | } | ||||||
|  |  | ||||||
| func (client *RTSPClient) CodecUpdatePPS(val []byte) { | func (client *RTSPClient) CodecUpdatePPS(val []byte) { | ||||||
| 	if bytes.Compare(val, client.pps) != 0 { | 	if client.videoCodec != av.H264 && client.videoCodec != av.H265 { | ||||||
| 		if len(client.sps) > 0 && len(client.pps) > 0 { | 		return | ||||||
| 			codecData, err := h264parser.NewCodecDataFromSPSAndPPS(client.sps, val) | 	} | ||||||
| 			if err != nil { | 	if bytes.Compare(val, client.pps) == 0 { | ||||||
| 				client.Println("Parse Codec Data Error", err) | 		return | ||||||
| 				return | 	} | ||||||
| 			} | 	client.pps = val | ||||||
| 			if len(client.CodecData) > 0 { | 	if (client.videoCodec == av.H264 && len(client.sps) == 0) || (client.videoCodec == av.H265 && (len(client.vps) == 0 || len(client.sps) == 0)) { | ||||||
| 				for i, i2 := range client.CodecData { | 		return | ||||||
| 					if i2.Type().IsVideo() { | 	} | ||||||
| 						client.CodecData[i] = codecData | 	var codecData av.VideoCodecData | ||||||
| 					} | 	var err error | ||||||
| 				} | 	switch client.videoCodec { | ||||||
| 			} else { | 	case av.H264: | ||||||
| 				client.CodecData = append(client.CodecData, codecData) | 		codecData, err = h264parser.NewCodecDataFromSPSAndPPS(client.sps, val) | ||||||
|  | 		if err != nil { | ||||||
|  | 			client.Println("Parse Codec Data Error", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	case av.H265: | ||||||
|  | 		codecData, err = h265parser.NewCodecDataFromVPSAndSPSAndPPS(client.vps, client.sps, val) | ||||||
|  | 		if err != nil { | ||||||
|  | 			client.Println("Parse Codec Data Error", err) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if len(client.CodecData) > 0 { | ||||||
|  | 		for i, i2 := range client.CodecData { | ||||||
|  | 			if i2.Type().IsVideo() { | ||||||
|  | 				client.CodecData[i] = codecData | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		client.Signals <- SignalCodecUpdate | 	} else { | ||||||
| 		client.pps = val | 		client.CodecData = append(client.CodecData, codecData) | ||||||
| 	} | 	} | ||||||
|  | 	client.Signals <- SignalCodecUpdate | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (client *RTSPClient) CodecUpdateVPS(val []byte) { | ||||||
|  | 	if client.videoCodec != av.H265 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if bytes.Compare(val, client.vps) == 0 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	client.vps = val | ||||||
|  | 	if len(client.sps) == 0 || len(client.pps) == 0 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	codecData, err := h265parser.NewCodecDataFromVPSAndSPSAndPPS(val, client.sps, client.pps) | ||||||
|  | 	if err != nil { | ||||||
|  | 		client.Println("Parse Codec Data Error", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	if len(client.CodecData) > 0 { | ||||||
|  | 		for i, i2 := range client.CodecData { | ||||||
|  | 			if i2.Type().IsVideo() { | ||||||
|  | 				client.CodecData[i] = codecData | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		client.CodecData = append(client.CodecData, codecData) | ||||||
|  | 	} | ||||||
|  | 	client.Signals <- SignalCodecUpdate | ||||||
| } | } | ||||||
|  |  | ||||||
| //Println mini logging functions | //Println mini logging functions | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Andrey Semochkin
					Andrey Semochkin