opus work in progress
This commit is contained in:
		
							
								
								
									
										3
									
								
								av/av.go
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								av/av.go
									
									
									
									
									
								
							| @@ -123,6 +123,7 @@ var ( | |||||||
| 	SPEEX      = MakeAudioCodecType(avCodecTypeMagic + 4) | 	SPEEX      = MakeAudioCodecType(avCodecTypeMagic + 4) | ||||||
| 	NELLYMOSER = MakeAudioCodecType(avCodecTypeMagic + 5) | 	NELLYMOSER = MakeAudioCodecType(avCodecTypeMagic + 5) | ||||||
| 	PCM        = MakeAudioCodecType(avCodecTypeMagic + 6) | 	PCM        = MakeAudioCodecType(avCodecTypeMagic + 6) | ||||||
|  | 	OPUS       = MakeAudioCodecType(avCodecTypeMagic + 7) | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const codecTypeAudioBit = 0x1 | const codecTypeAudioBit = 0x1 | ||||||
| @@ -144,6 +145,8 @@ func (self CodecType) String() string { | |||||||
| 		return "NELLYMOSER" | 		return "NELLYMOSER" | ||||||
| 	case PCM: | 	case PCM: | ||||||
| 		return "PCM" | 		return "PCM" | ||||||
|  | 	case OPUS: | ||||||
|  | 		return "OPUS" | ||||||
| 	} | 	} | ||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,6 +7,32 @@ import ( | |||||||
| 	"github.com/deepch/vdk/codec/fake" | 	"github.com/deepch/vdk/codec/fake" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | type OpusCodecData struct { | ||||||
|  | 	typ            av.CodecType | ||||||
|  | 	SampleRate_    int | ||||||
|  | 	ChannelLayout_ av.ChannelLayout | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (self OpusCodecData) Type() av.CodecType { | ||||||
|  | 	return self.typ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (self OpusCodecData) SampleRate() int { | ||||||
|  | 	return self.SampleRate_ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (self OpusCodecData) ChannelLayout() av.ChannelLayout { | ||||||
|  | 	return self.ChannelLayout_ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (self OpusCodecData) PacketDuration(data []byte) (time.Duration, error) { | ||||||
|  | 	return time.Duration(1000) * time.Second / time.Duration(self.SampleRate_), nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (self OpusCodecData) SampleFormat() av.SampleFormat { | ||||||
|  | 	return av.FLT | ||||||
|  | } | ||||||
|  |  | ||||||
| type PCMUCodecData struct { | type PCMUCodecData struct { | ||||||
| 	typ av.CodecType | 	typ av.CodecType | ||||||
| } | } | ||||||
| @@ -48,15 +74,19 @@ func NewPCMAlawCodecData() av.AudioCodecData { | |||||||
| 		typ: av.PCM_ALAW, | 		typ: av.PCM_ALAW, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | func NewOpusCodecData(sr int, cc av.ChannelLayout) av.AudioCodecData { | ||||||
|  | 	return OpusCodecData{ | ||||||
|  | 		typ:            av.OPUS, | ||||||
|  | 		SampleRate_:    sr, | ||||||
|  | 		ChannelLayout_: cc, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| type SpeexCodecData struct { | type SpeexCodecData struct { | ||||||
| 	fake.CodecData | 	fake.CodecData | ||||||
| } | } | ||||||
|  |  | ||||||
| func (self SpeexCodecData) PacketDuration(data []byte) (time.Duration, error) { | func (self SpeexCodecData) PacketDuration(data []byte) (time.Duration, error) { | ||||||
| 	// libavcodec/libspeexdec.c |  | ||||||
| 	// samples = samplerate/50 |  | ||||||
| 	// duration = 0.02s |  | ||||||
| 	return time.Millisecond * 20, nil | 	return time.Millisecond * 20, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ type Media struct { | |||||||
| 	TimeScale          int | 	TimeScale          int | ||||||
| 	Control            string | 	Control            string | ||||||
| 	Rtpmap             int | 	Rtpmap             int | ||||||
|  | 	ChannelCount       int | ||||||
| 	Config             []byte | 	Config             []byte | ||||||
| 	SpropParameterSets [][]byte | 	SpropParameterSets [][]byte | ||||||
| 	PayloadType        int | 	PayloadType        int | ||||||
| @@ -83,6 +84,13 @@ func Parse(content string) (sess Session, medias []Media) { | |||||||
| 								media.Type = av.AAC | 								media.Type = av.AAC | ||||||
| 							case "L16": | 							case "L16": | ||||||
| 								media.Type = av.PCM | 								media.Type = av.PCM | ||||||
|  | 							case "OPUS": | ||||||
|  | 								media.Type = av.OPUS | ||||||
|  | 								if len(keyval) > 2 { | ||||||
|  | 									if i, err := strconv.Atoi(keyval[2]); err == nil { | ||||||
|  | 										media.ChannelCount = i | ||||||
|  | 									} | ||||||
|  | 								} | ||||||
| 							case "H264": | 							case "H264": | ||||||
| 								media.Type = av.H264 | 								media.Type = av.H264 | ||||||
| 							} | 							} | ||||||
|   | |||||||
| @@ -75,7 +75,8 @@ type RTSPClient struct { | |||||||
| 	sps                 []byte | 	sps                 []byte | ||||||
| 	pps                 []byte | 	pps                 []byte | ||||||
| 	CodecData           []av.CodecData | 	CodecData           []av.CodecData | ||||||
| 	PCMTime             int64 | 	PCMTime             time.Duration | ||||||
|  | 	AudioTimeScale      int64 | ||||||
| } | } | ||||||
|  |  | ||||||
| type RTSPClientOptions struct { | type RTSPClientOptions struct { | ||||||
| @@ -94,11 +95,12 @@ func Dial(options RTSPClientOptions) (*RTSPClient, error) { | |||||||
| 		OutgoingProxyQueue:  make(chan *[]byte, 3000), | 		OutgoingProxyQueue:  make(chan *[]byte, 3000), | ||||||
| 		OutgoingPacketQueue: make(chan *av.Packet, 3000), | 		OutgoingPacketQueue: make(chan *av.Packet, 3000), | ||||||
| 		BufferRtpPacket:     bytes.NewBuffer([]byte{}), | 		BufferRtpPacket:     bytes.NewBuffer([]byte{}), | ||||||
| 		videoID:             0, | 		videoID:             -1, | ||||||
| 		audioID:             2, | 		audioID:             -2, | ||||||
| 		videoIDX:            0, | 		videoIDX:            -1, | ||||||
| 		audioIDX:            1, | 		audioIDX:            -2, | ||||||
| 		options:             options, | 		options:             options, | ||||||
|  | 		AudioTimeScale:      8000, | ||||||
| 	} | 	} | ||||||
| 	client.headers["User-Agent"] = "Lavf58.20.100" | 	client.headers["User-Agent"] = "Lavf58.20.100" | ||||||
| 	err := client.parseURL(html.UnescapeString(client.options.URL)) | 	err := client.parseURL(html.UnescapeString(client.options.URL)) | ||||||
| @@ -154,10 +156,21 @@ func Dial(options RTSPClientOptions) (*RTSPClient, error) { | |||||||
| 				if err == nil { | 				if err == nil { | ||||||
| 					client.Println("Audio AAC bad config") | 					client.Println("Audio AAC bad config") | ||||||
| 				} | 				} | ||||||
|  | 			case av.OPUS: | ||||||
|  | 				var cl av.ChannelLayout | ||||||
|  | 				switch i2.ChannelCount { | ||||||
|  | 				case 1: | ||||||
|  | 					cl = av.CH_MONO | ||||||
|  | 				case 2: | ||||||
|  | 					cl = av.CH_STEREO | ||||||
|  | 				default: | ||||||
|  | 					cl = av.CH_MONO | ||||||
|  | 				} | ||||||
|  | 				CodecData = codec.NewOpusCodecData(i2.TimeScale, cl) | ||||||
| 			case av.PCM_MULAW: | 			case av.PCM_MULAW: | ||||||
| 				CodecData = codec.NewPCMMulawCodecData() | 				CodecData = codec.NewPCMMulawCodecData() | ||||||
| 			case av.PCM_ALAW: | 			case av.PCM_ALAW: | ||||||
| 				CodecData = codec.NewPCMMulawCodecData() | 				CodecData = codec.NewPCMAlawCodecData() | ||||||
| 			case av.PCM: | 			case av.PCM: | ||||||
| 				CodecData = codec.NewPCMCodecData() | 				CodecData = codec.NewPCMCodecData() | ||||||
| 			default: | 			default: | ||||||
| @@ -166,6 +179,9 @@ func Dial(options RTSPClientOptions) (*RTSPClient, error) { | |||||||
| 			if CodecData != nil { | 			if CodecData != nil { | ||||||
| 				client.CodecData = append(client.CodecData, CodecData) | 				client.CodecData = append(client.CodecData, CodecData) | ||||||
| 				client.audioIDX = int8(len(client.CodecData) - 1) | 				client.audioIDX = int8(len(client.CodecData) - 1) | ||||||
|  | 				if i2.TimeScale != 0 { | ||||||
|  | 					client.AudioTimeScale = int64(i2.TimeScale) | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		ch += 2 | 		ch += 2 | ||||||
| @@ -556,14 +572,21 @@ 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 { | ||||||
| 			//client.PCMTime += int64(float32(1000) / (float32(8000) / float32(len(nal)))) | 			//basic | ||||||
|  | 			//time.Duration(float32(timestamp)/float32(float32(client.AudioTimeScale)/float32(1000))) * time.Millisecond | ||||||
|  | 			//pcm | ||||||
|  | 			//client.PCMTime += time.Duration(len(nal)) * time.Second / time.Duration(client.AudioTimeScale) | ||||||
|  | 			//opus | ||||||
|  | 			//client.PCMTime := time.Duration((sampleCount/48000)*1000) * time.Millisecond | ||||||
|  | 			//Need Add Opus And AAC | ||||||
| 			retmap = append(retmap, &av.Packet{ | 			retmap = append(retmap, &av.Packet{ | ||||||
| 				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.audioIDX, | 				Idx:             client.audioIDX, | ||||||
| 				IsKeyFrame:      false, | 				IsKeyFrame:      false, | ||||||
| 				Time:            time.Duration(timestamp/8) * time.Millisecond, | 				Time:            time.Duration(float32(timestamp)/float32(float32(client.AudioTimeScale)/float32(1000))) * time.Millisecond, | ||||||
| 			}) | 			}) | ||||||
|  | 			//log.Println("===>", time.Duration(float32(timestamp)/float32(float32(client.AudioTimeScale)/float32(1000)))*time.Millisecond) | ||||||
| 		} | 		} | ||||||
| 		if len(retmap) > 0 { | 		if len(retmap) > 0 { | ||||||
| 			return retmap, true | 			return retmap, true | ||||||
|   | |||||||
| @@ -14,23 +14,6 @@ import ( | |||||||
| 	"github.com/pion/webrtc/v3/pkg/media" | 	"github.com/pion/webrtc/v3/pkg/media" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	// MimeTypeH264 H264 MIME type. |  | ||||||
| 	MimeTypeH264 = "video/h264" |  | ||||||
| 	// MimeTypeOpus Opus MIME type |  | ||||||
| 	MimeTypeOpus = "audio/opus" |  | ||||||
| 	// MimeTypeVP8 VP8 MIME type |  | ||||||
| 	MimeTypeVP8 = "video/vp8" |  | ||||||
| 	// MimeTypeVP9 VP9 MIME type |  | ||||||
| 	MimeTypeVP9 = "video/vp9" |  | ||||||
| 	// MimeTypeG722 G722 MIME type |  | ||||||
| 	MimeTypeG722 = "audio/G722" |  | ||||||
| 	// MimeTypePCMU PCMU MIME type |  | ||||||
| 	MimeTypePCMU = "audio/PCMU" |  | ||||||
| 	// MimeTypePCMA PCMA MIME type |  | ||||||
| 	MimeTypePCMA = "audio/PCMA" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	ErrorNotFound          = errors.New("WebRTC Stream Not Found") | 	ErrorNotFound          = errors.New("WebRTC Stream Not Found") | ||||||
| 	ErrorCodecNotSupported = errors.New("WebRTC Codec Not Supported") | 	ErrorCodecNotSupported = errors.New("WebRTC Codec Not Supported") | ||||||
| @@ -99,18 +82,22 @@ func (element *Muxer) WriteHeader(streams []av.CodecData, sdp64 string) (string, | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} else if i2.Type().IsAudio() { | 		} else if i2.Type().IsAudio() { | ||||||
| 			AudioCodecString := MimeTypePCMU | 			AudioCodecString := webrtc.MimeTypePCMA | ||||||
| 			switch i2.Type() { | 			switch i2.Type() { | ||||||
| 			case av.PCM_ALAW: | 			case av.PCM_ALAW: | ||||||
| 				AudioCodecString = MimeTypePCMA | 				AudioCodecString = webrtc.MimeTypePCMA | ||||||
| 			case av.PCM_MULAW: | 			case av.PCM_MULAW: | ||||||
| 				AudioCodecString = MimeTypePCMU | 				AudioCodecString = webrtc.MimeTypePCMU | ||||||
|  | 			case av.OPUS: | ||||||
|  | 				AudioCodecString = webrtc.MimeTypeOpus | ||||||
| 			default: | 			default: | ||||||
| 				log.Println(ErrorIgnoreAudioTrack) | 				log.Println(ErrorIgnoreAudioTrack) | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 			track, err = webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{ | 			track, err = webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{ | ||||||
| 				MimeType: AudioCodecString, | 				MimeType:  AudioCodecString, | ||||||
|  | 				Channels:  uint16(i2.(av.AudioCodecData).ChannelLayout().Count()), | ||||||
|  | 				ClockRate: uint32(i2.(av.AudioCodecData).SampleRate()), | ||||||
| 			}, "pion-rtsp-audio", "pion-rtsp-audio") | 			}, "pion-rtsp-audio", "pion-rtsp-audio") | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return "", err | 				return "", err | ||||||
| @@ -162,6 +149,7 @@ func (element *Muxer) WriteHeader(streams []av.CodecData, sdp64 string) (string, | |||||||
| } | } | ||||||
|  |  | ||||||
| func (element *Muxer) WritePacket(pkt av.Packet) (err error) { | func (element *Muxer) WritePacket(pkt av.Packet) (err error) { | ||||||
|  | 	//log.Println("WritePacket", pkt.Time, element.stop, webrtc.ICEConnectionStateConnected, pkt.Idx, element.streams[pkt.Idx]) | ||||||
| 	var WritePacketSuccess bool | 	var WritePacketSuccess bool | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		if !WritePacketSuccess { | 		if !WritePacketSuccess { | ||||||
| @@ -189,6 +177,7 @@ func (element *Muxer) WritePacket(pkt av.Packet) (err error) { | |||||||
| 			} | 			} | ||||||
| 		case av.PCM_MULAW: | 		case av.PCM_MULAW: | ||||||
| 		case av.PCM_ALAW: | 		case av.PCM_ALAW: | ||||||
|  | 		case av.OPUS: | ||||||
| 		default: | 		default: | ||||||
| 			return ErrorCodecNotSupported | 			return ErrorCodecNotSupported | ||||||
| 		} | 		} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Andrey Semochkin
					Andrey Semochkin