mirror of
https://github.com/comma-hacks/webrtc.git
synced 2025-09-27 04:26:31 +08:00
~300ms, fast camera switching
This commit is contained in:
19
main.go
19
main.go
@@ -9,6 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var visionTrack *VisionIpcTrack
|
var visionTrack *VisionIpcTrack
|
||||||
|
var peerConnection *webrtc.PeerConnection
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
signal := signaling.Create("go-webrtc-body")
|
signal := signaling.Create("go-webrtc-body")
|
||||||
@@ -20,20 +21,32 @@ func main() {
|
|||||||
log.Println("Waiting to pair.")
|
log.Println("Waiting to pair.")
|
||||||
<-signal.PairWaitChannel
|
<-signal.PairWaitChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
signal.OnPeerConnectionCreated = func(pc *webrtc.PeerConnection) {
|
signal.OnPeerConnectionCreated = func(pc *webrtc.PeerConnection) {
|
||||||
ReplaceTrack("road", pc)
|
peerConnection = pc
|
||||||
|
InitStream(pc)
|
||||||
|
}
|
||||||
|
signal.OnMessage = func(msg signaling.Message) {
|
||||||
|
switch msg.PayloadType {
|
||||||
|
case "request_track":
|
||||||
|
{
|
||||||
|
visionTrack.ChangeCamera()
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Printf("unimplemented message type: %s\n", msg.PayloadType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReplaceTrack(prefix string, peerConnection *webrtc.PeerConnection) {
|
func InitStream(peerConnection *webrtc.PeerConnection) {
|
||||||
var err error
|
var err error
|
||||||
if visionTrack != nil {
|
if visionTrack != nil {
|
||||||
visionTrack.Stop()
|
visionTrack.Stop()
|
||||||
}
|
}
|
||||||
visionTrack, err = NewVisionIpcTrack(prefix + "EncodeData")
|
visionTrack, err = NewVisionIpcTrack()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(fmt.Errorf("main: creating track failed: %w", err))
|
log.Fatal(fmt.Errorf("main: creating track failed: %w", err))
|
||||||
}
|
}
|
||||||
|
Submodule signaling updated: eb061314f5...d47c556754
@@ -15,6 +15,12 @@ import (
|
|||||||
|
|
||||||
const V4L2_BUF_FLAG_KEYFRAME = uint32(8)
|
const V4L2_BUF_FLAG_KEYFRAME = uint32(8)
|
||||||
|
|
||||||
|
var cams = []string{
|
||||||
|
"roadEncodeData",
|
||||||
|
"wideRoadEncodeData",
|
||||||
|
"driverEncodeData",
|
||||||
|
}
|
||||||
|
|
||||||
type VisionIpcTrackTranscodeStream struct {
|
type VisionIpcTrackTranscodeStream struct {
|
||||||
decCodecID astiav.CodecID
|
decCodecID astiav.CodecID
|
||||||
decCodec *astiav.Codec
|
decCodec *astiav.Codec
|
||||||
@@ -30,6 +36,7 @@ type VisionIpcTrackTranscodeStream struct {
|
|||||||
type VisionIpcTrack struct {
|
type VisionIpcTrack struct {
|
||||||
name string
|
name string
|
||||||
stream *VisionIpcTrackTranscodeStream
|
stream *VisionIpcTrackTranscodeStream
|
||||||
|
camIdx int
|
||||||
context *zmq.Context
|
context *zmq.Context
|
||||||
subscriber *zmq.Socket
|
subscriber *zmq.Socket
|
||||||
lastIdx int64
|
lastIdx int64
|
||||||
@@ -48,6 +55,8 @@ type VisionIpcTrack struct {
|
|||||||
logMonoTime uint64
|
logMonoTime uint64
|
||||||
timestampEof uint64
|
timestampEof uint64
|
||||||
dataSize int
|
dataSize int
|
||||||
|
|
||||||
|
counter int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Frame struct {
|
type Frame struct {
|
||||||
@@ -57,7 +66,7 @@ type Frame struct {
|
|||||||
|
|
||||||
var Open = false
|
var Open = false
|
||||||
|
|
||||||
func NewVisionIpcTrack(name string) (track *VisionIpcTrack, err error) {
|
func NewVisionIpcTrack() (track *VisionIpcTrack, err error) {
|
||||||
// Create a new context
|
// Create a new context
|
||||||
context, err := zmq.NewContext()
|
context, err := zmq.NewContext()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -65,15 +74,6 @@ func NewVisionIpcTrack(name string) (track *VisionIpcTrack, err error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect to the socket
|
|
||||||
subscriber, err := context.NewSocket(zmq.SUB)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(fmt.Errorf("vision_ipc_track: new zmq socket failed: %w", err))
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
subscriber.SetSubscribe("")
|
|
||||||
subscriber.Connect(GetServiceURI(name))
|
|
||||||
|
|
||||||
// Create stream
|
// Create stream
|
||||||
s := &VisionIpcTrackTranscodeStream{}
|
s := &VisionIpcTrackTranscodeStream{}
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ func NewVisionIpcTrack(name string) (track *VisionIpcTrack, err error) {
|
|||||||
s.encCodecContext.SetHeight(s.decCodecContext.Height())
|
s.encCodecContext.SetHeight(s.decCodecContext.Height())
|
||||||
s.encCodecContext.SetFramerate(s.decCodecContext.Framerate())
|
s.encCodecContext.SetFramerate(s.decCodecContext.Framerate())
|
||||||
s.encCodecContext.SetPixelFormat(s.decCodecContext.PixelFormat())
|
s.encCodecContext.SetPixelFormat(s.decCodecContext.PixelFormat())
|
||||||
s.encCodecContext.SetBitRate(500_000)
|
s.encCodecContext.SetBitRate(1_500_000)
|
||||||
// s.encCodecContext.SetGopSize(0)
|
// s.encCodecContext.SetGopSize(0)
|
||||||
s.encCodecContext.SetSampleAspectRatio(s.decCodecContext.SampleAspectRatio())
|
s.encCodecContext.SetSampleAspectRatio(s.decCodecContext.SampleAspectRatio())
|
||||||
s.encCodecContext.SetTimeBase(s.decCodecContext.TimeBase())
|
s.encCodecContext.SetTimeBase(s.decCodecContext.TimeBase())
|
||||||
@@ -166,10 +166,9 @@ func NewVisionIpcTrack(name string) (track *VisionIpcTrack, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &VisionIpcTrack{
|
return &VisionIpcTrack{
|
||||||
name: name,
|
camIdx: 0,
|
||||||
stream: s,
|
stream: s,
|
||||||
context: context,
|
context: context,
|
||||||
subscriber: subscriber,
|
|
||||||
lastIdx: -1,
|
lastIdx: -1,
|
||||||
seenIframe: false,
|
seenIframe: false,
|
||||||
networkLatency: 0.0,
|
networkLatency: 0.0,
|
||||||
@@ -185,6 +184,8 @@ func NewVisionIpcTrack(name string) (track *VisionIpcTrack, err error) {
|
|||||||
logMonoTime: 0,
|
logMonoTime: 0,
|
||||||
timestampEof: 0,
|
timestampEof: 0,
|
||||||
dataSize: 0,
|
dataSize: 0,
|
||||||
|
|
||||||
|
counter: 0,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,7 +223,6 @@ func (v *VisionIpcTrack) Stop() {
|
|||||||
v.stream.decPkt.Free()
|
v.stream.decPkt.Free()
|
||||||
v.stream.encCodecContext.Free()
|
v.stream.encCodecContext.Free()
|
||||||
v.stream.decCodecContext.Free()
|
v.stream.decCodecContext.Free()
|
||||||
v.subscriber.Close()
|
|
||||||
v.context.Term()
|
v.context.Term()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,19 +231,18 @@ func (v *VisionIpcTrack) Start() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// adapter := NewAdapter()
|
v.Subscribe()
|
||||||
|
defer v.subscriber.Close()
|
||||||
|
|
||||||
// h264, h264Err := h264reader.NewReader(adapter)
|
v.counter = 0
|
||||||
// if h264Err != nil {
|
|
||||||
// panic(h264Err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
counter := 0
|
|
||||||
|
|
||||||
duration := 50 * time.Millisecond
|
duration := 50 * time.Millisecond
|
||||||
|
|
||||||
Open = true
|
Open = true
|
||||||
for Open {
|
for Open {
|
||||||
|
// if v.subscriber == nil {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
msgs := DrainSock(v.subscriber, false)
|
msgs := DrainSock(v.subscriber, false)
|
||||||
v.msgCount = len(msgs)
|
v.msgCount = len(msgs)
|
||||||
if v.msgCount > 0 {
|
if v.msgCount > 0 {
|
||||||
@@ -253,7 +252,7 @@ func (v *VisionIpcTrack) Start() {
|
|||||||
v.stream.decPkt.Unref()
|
v.stream.decPkt.Unref()
|
||||||
v.stream.decFrame.Unref()
|
v.stream.decFrame.Unref()
|
||||||
|
|
||||||
pts := int64(counter * 50) // 50ms per frame
|
pts := int64(v.counter * 50) // 50ms per frame
|
||||||
|
|
||||||
evt, err := cereal.ReadRootEvent(msg)
|
evt, err := cereal.ReadRootEvent(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -261,7 +260,15 @@ func (v *VisionIpcTrack) Start() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
encodeData, err := evt.RoadEncodeData()
|
var encodeData cereal.EncodeData
|
||||||
|
switch evt.Which() {
|
||||||
|
case cereal.Event_Which_roadEncodeData:
|
||||||
|
encodeData, err = evt.RoadEncodeData()
|
||||||
|
case cereal.Event_Which_wideRoadEncodeData:
|
||||||
|
encodeData, err = evt.WideRoadEncodeData()
|
||||||
|
case cereal.Event_Which_driverEncodeData:
|
||||||
|
encodeData, err = evt.DriverEncodeData()
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(fmt.Errorf("cereal read road encode data failed: %w", err))
|
log.Println(fmt.Errorf("cereal read road encode data failed: %w", err))
|
||||||
continue
|
continue
|
||||||
@@ -353,6 +360,16 @@ func (v *VisionIpcTrack) Start() {
|
|||||||
v.pcLatency = ((float64(time.Now().UnixNano()) / 1e6) - float64(v.timeQ[0]))
|
v.pcLatency = ((float64(time.Now().UnixNano()) / 1e6) - float64(v.timeQ[0]))
|
||||||
v.timeQ = v.timeQ[1:]
|
v.timeQ = v.timeQ[1:]
|
||||||
|
|
||||||
|
// this didn't work
|
||||||
|
// // if counter is 0, we changed camera source, so encode a keyframe!
|
||||||
|
// if v.counter == 0 {
|
||||||
|
// // v.stream.encPkt.SetFlags(v.stream.encPkt.Flags().Add(astiav.PacketFlagKey))
|
||||||
|
// // av_opt_set(codec_ctx->priv_data, "x264opts", "keyint=1", 0);
|
||||||
|
// // v.stream.encCodecContext.SetOpt("keyint")
|
||||||
|
// // v.stream.encCodecContext.SetGopSize(1)
|
||||||
|
// v.stream.encCodecContext.SetOpt("x264opts", "keyint", 1)
|
||||||
|
// }
|
||||||
|
|
||||||
// Send frame
|
// Send frame
|
||||||
if err = v.stream.encCodecContext.SendFrame(v.stream.decFrame); err != nil {
|
if err = v.stream.encCodecContext.SendFrame(v.stream.decFrame); err != nil {
|
||||||
log.Println(fmt.Errorf("vision_ipc_track encoder: sending frame failed: %w", err))
|
log.Println(fmt.Errorf("vision_ipc_track encoder: sending frame failed: %w", err))
|
||||||
@@ -368,6 +385,16 @@ func (v *VisionIpcTrack) Start() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this didn't work
|
||||||
|
// // if counter is 0, we changed camera source, so encode a keyframe!
|
||||||
|
// if v.counter == 0 {
|
||||||
|
// // v.stream.encPkt.SetFlags(v.stream.encPkt.Flags().Add(astiav.PacketFlagKey))
|
||||||
|
// // av_opt_set(codec_ctx->priv_data, "x264opts", "keyint=1", 0);
|
||||||
|
// // v.stream.encCodecContext.SetOpt("keyint")
|
||||||
|
// // v.stream.encCodecContext.SetGopSize(0)
|
||||||
|
// v.stream.encCodecContext.SetOpt("x264opts", "keyint", 0)
|
||||||
|
// }
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(fmt.Errorf("vision_ipc_track: encode error: %w", err))
|
log.Println(fmt.Errorf("vision_ipc_track: encode error: %w", err))
|
||||||
continue
|
continue
|
||||||
@@ -378,7 +405,7 @@ func (v *VisionIpcTrack) Start() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
counter++
|
v.counter++
|
||||||
|
|
||||||
v.PrintStats()
|
v.PrintStats()
|
||||||
}
|
}
|
||||||
@@ -401,3 +428,35 @@ func (v *VisionIpcTrack) PrintStats() {
|
|||||||
v.name,
|
v.name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *VisionIpcTrack) ChangeCamera() {
|
||||||
|
v.camIdx = (v.camIdx + 1) % len(cams)
|
||||||
|
v.Subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *VisionIpcTrack) NewSocket() (socket *zmq.Socket, err error) {
|
||||||
|
socket, err = v.context.NewSocket(zmq.SUB)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
v.name = cams[v.camIdx]
|
||||||
|
err = socket.Connect(GetServiceURI(v.name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return socket, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *VisionIpcTrack) Subscribe() {
|
||||||
|
oldSub := v.subscriber
|
||||||
|
subscriber, err := v.NewSocket()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(fmt.Errorf("zmq subscribe failed: %w", err))
|
||||||
|
}
|
||||||
|
subscriber.SetSubscribe("")
|
||||||
|
v.counter = 0
|
||||||
|
v.subscriber = subscriber
|
||||||
|
if oldSub != nil {
|
||||||
|
oldSub.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user