diff --git a/pkg/sfu/buffer/helpers.go b/pkg/sfu/buffer/helpers.go index f52464b4c..274b73e47 100644 --- a/pkg/sfu/buffer/helpers.go +++ b/pkg/sfu/buffer/helpers.go @@ -19,6 +19,7 @@ import ( "errors" "github.com/livekit/protocol/logger" + "github.com/pion/rtp/codecs" ) var ( @@ -310,55 +311,28 @@ func IsH264KeyFrame(payload []byte) bool { // ------------------------------------- +// IsVP9KeyFrame detects if vp9 payload is a keyframe +// taken from https://github.com/jech/galene/blob/master/codecs/codecs.go +// all credits belongs to Juliusz Chroboczek @jech and the awesome Galene SFU func IsVP9KeyFrame(payload []byte) bool { - payloadLen := len(payload) - if payloadLen < 1 { + var vp9 codecs.VP9Packet + _, err := vp9.Unmarshal(payload) + if err != nil || len(vp9.Payload) < 1 { + return false + } + if !vp9.B { return false } - idx := 0 - I := payload[idx]&0x80 > 0 - P := payload[idx]&0x40 > 0 - L := payload[idx]&0x20 > 0 - F := payload[idx]&0x10 > 0 - B := payload[idx]&0x08 > 0 - - if F && !I { + if (vp9.Payload[0] & 0xc0) != 0x80 { return false } - // Check for PictureID - if I { - idx++ - if payloadLen < idx+1 { - return false - } - // Check if m is 1, then Picture ID is 15 bits - if payload[idx]&0x80 > 0 { - idx++ - if payloadLen < idx+1 { - return false - } - } + profile := (vp9.Payload[0] >> 4) & 0x3 + if profile != 3 { + return (vp9.Payload[0] & 0xC) == 0 } - - // Check if TL0PICIDX is present - sid := -1 - if L { - idx++ - if payloadLen < idx+1 { - return false - } - - tid := (payload[idx] >> 5) & 0x7 - if !P && tid != 0 { - return false - } - - sid = int((payload[idx] >> 1) & 0x7) - } - - return !P && (!L || (L && sid == 0)) && B + return (vp9.Payload[0] & 0x6) == 0 } // ------------------------------------- diff --git a/pkg/sfu/forwarder.go b/pkg/sfu/forwarder.go index 696c19817..85d580f18 100644 --- a/pkg/sfu/forwarder.go +++ b/pkg/sfu/forwarder.go @@ -309,6 +309,7 @@ func (f *Forwarder) DetermineCodec(codec webrtc.RTPCodecCapability, extensions [ f.vls = videolayerselector.NewVP9(f.logger) } } + // SVC-TODO: Support for VP9 simulcast. When DD is not available, have to pick selector based on VP9 SVC or Simulcast case "video/av1": // DD-TODO : we only enable dd layer selector for av1/vp9 now, in the future we can enable it for vp8 too if f.vls != nil { @@ -316,6 +317,7 @@ func (f *Forwarder) DetermineCodec(codec webrtc.RTPCodecCapability, extensions [ } else { f.vls = videolayerselector.NewDependencyDescriptor(f.logger) } + // SVC-TODO: Support for AV1 Simulcast or just single spatial layer - won't have DD in that case } } diff --git a/pkg/sfu/receiver.go b/pkg/sfu/receiver.go index 69d3d1265..8aa5dcac3 100644 --- a/pkg/sfu/receiver.go +++ b/pkg/sfu/receiver.go @@ -131,6 +131,10 @@ type WebRTCReceiver struct { redPktWriter func(pkt *buffer.ExtPacket, spatialLayer int32) } +// SVC-TODO: Have to use more conditions to differentiate between +// SVC-TODO: SVC and non-SVC (could be single layer or simulcast). +// SVC-TODO: May only need to differentiate between simulcast and non-simulcast +// SVC-TODO: i. e. may be possible to treat single layer as SVC to get proper/intended functionality. func IsSvcCodec(mime string) bool { switch strings.ToLower(mime) { case "video/av1": @@ -231,6 +235,7 @@ func NewWebRTCReceiver( }) w.connectionStats.Start(w.trackInfo) + // SVC-TODO: Handle DD for non-SVC cases??? if w.isSVC { for _, ext := range receiver.GetParameters().HeaderExtensions { if ext.URI == dd.ExtensionURI {