mirror of
https://github.com/livekit/livekit.git
synced 2026-03-30 15:35:41 +00:00
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:
@@ -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
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user