Use VP9 Key frame detection from Galene. (#1973)

* Use VP9 Key frame detection from Galene.

With ffmpeg generated VP9 file with single layer
and publishing via Go SDK, the key picture determination
outlined at https://datatracker.ietf.org/doc/html/draft-ietf-payload-vp9-16#page-13
under the F bit explanation does not work. It declares kay frame for
pretty much all frames. Unclear if ffmpeg generated bitstream has issues
or if that procedure in the above document does not work for single
layer case.

Using the bit stream explained here
https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf
(pages 28, 62, 63) implemented in Galene.
That is more expensive as it has to parse more, but works in all cases.

* Add AV1-TODo

* add some TODOs
This commit is contained in:
Raja Subramanian
2023-08-17 22:33:11 +05:30
committed by GitHub
parent 480edff4ac
commit 129b1df8e6
3 changed files with 22 additions and 41 deletions

View File

@@ -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
}
// -------------------------------------

View File

@@ -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
}
}

View File

@@ -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 {