Checkpoint audio-only Skald fork work

This commit is contained in:
Storm Dragon
2026-05-18 13:06:57 -04:00
parent a8ada950d5
commit 965347cad4
48 changed files with 1080 additions and 3651 deletions
+6 -322
View File
@@ -2,312 +2,30 @@ package codecs
import (
"errors"
"strings"
"github.com/pion/rtp"
"github.com/pion/rtp/codecs"
)
var errTruncated = errors.New("truncated packet")
// Keyframe determines if packet is the start of a keyframe.
// It returns (true, true) if that is the case, (false, true) if that is
// definitely not the case, and (false, false) if the information cannot
// be determined.
func Keyframe(codec string, packet *rtp.Packet) (bool, bool) {
if strings.EqualFold(codec, "video/vp8") {
var vp8 codecs.VP8Packet
_, err := vp8.Unmarshal(packet.Payload)
if err != nil || len(vp8.Payload) < 1 {
return false, false
}
if vp8.S != 0 && vp8.PID == 0 && (vp8.Payload[0]&0x1) == 0 {
return true, true
}
return false, true
} else if strings.EqualFold(codec, "video/vp9") {
var vp9 codecs.VP9Packet
_, err := vp9.Unmarshal(packet.Payload)
if err != nil || len(vp9.Payload) < 1 {
return false, false
}
if !vp9.B {
return false, true
}
if (vp9.Payload[0] & 0xc0) != 0x80 {
return false, false
}
profile := (vp9.Payload[0] >> 4) & 0x3
if profile != 3 {
return (vp9.Payload[0] & 0xC) == 0, true
}
return (vp9.Payload[0] & 0x6) == 0, true
} else if strings.EqualFold(codec, "video/av1") {
if len(packet.Payload) < 2 {
return false, true
}
// Z=0, N=1
if (packet.Payload[0] & 0x88) != 0x08 {
return false, true
}
w := (packet.Payload[0] & 0x30) >> 4
getObu := func(data []byte, last bool) ([]byte, int, bool) {
if last {
return data, len(data), false
}
offset := 0
length := 0
for {
if len(data) <= offset {
return nil, offset, offset > 0
}
if offset >= 4 {
return nil, offset, true
}
l := data[offset]
length |= int(l&0x7f) << (offset * 7)
offset++
if (l & 0x80) == 0 {
break
}
}
if len(data) < offset+length {
return data[offset:], len(data), true
}
return data[offset : offset+length],
offset + length, false
}
offset := 1
i := 0
for {
obu, length, truncated :=
getObu(packet.Payload[offset:], int(w) == i+1)
if len(obu) < 1 {
return false, false
}
tpe := (obu[0] & 0x38) >> 3
switch i {
case 0:
// OBU_SEQUENCE_HEADER
if tpe != 1 {
return false, true
}
default:
// OBU_FRAME_HEADER or OBU_FRAME
if tpe == 3 || tpe == 6 {
if len(obu) < 2 {
return false, false
}
// show_existing_frame == 0
if (obu[1] & 0x80) != 0 {
return false, true
}
// frame_type == KEY_FRAME
return (obu[1] & 0x60) == 0, true
}
}
if truncated || i >= int(w) {
// the first frame header is in a second
// packet, give up.
return false, false
}
offset += length
i++
}
} else if strings.EqualFold(codec, "video/h264") {
if len(packet.Payload) < 1 {
return false, false
}
nalu := packet.Payload[0] & 0x1F
if nalu == 0 {
// reserved
return false, false
} else if nalu <= 23 {
// simple NALU
return nalu == 7, true
} else if nalu == 24 || nalu == 25 || nalu == 26 || nalu == 27 {
// STAP-A, STAP-B, MTAP16 or MTAP24
i := 1
if nalu == 25 || nalu == 26 || nalu == 27 {
// skip DON
i += 2
}
for i < len(packet.Payload) {
if i+2 > len(packet.Payload) {
return false, false
}
length := uint16(packet.Payload[i])<<8 |
uint16(packet.Payload[i+1])
i += 2
if i+int(length) > len(packet.Payload) {
return false, false
}
offset := 0
if nalu == 26 {
offset = 3
} else if nalu == 27 {
offset = 4
}
if offset >= int(length) {
return false, false
}
n := packet.Payload[i+offset] & 0x1F
if n == 7 {
return true, true
} else if n >= 24 {
// is this legal?
return false, false
}
i += int(length)
}
if i == len(packet.Payload) {
return false, true
}
return false, false
} else if nalu == 28 || nalu == 29 {
// FU-A or FU-B
if len(packet.Payload) < 2 {
return false, false
}
if (packet.Payload[1] & 0x80) == 0 {
// not a starting fragment
return false, true
}
return (packet.Payload[1]&0x1F == 7), true
}
return false, false
}
return false, false
}
func KeyframeDimensions(codec string, packet *rtp.Packet) (uint32, uint32) {
if strings.EqualFold(codec, "video/vp8") {
var vp8 codecs.VP8Packet
_, err := vp8.Unmarshal(packet.Payload)
if err != nil {
return 0, 0
}
if len(vp8.Payload) < 10 {
return 0, 0
}
raw := uint32(vp8.Payload[6]) | uint32(vp8.Payload[7])<<8 |
uint32(vp8.Payload[8])<<16 | uint32(vp8.Payload[9])<<24
width := raw & 0x3FFF
height := (raw >> 16) & 0x3FFF
return width, height
} else if strings.EqualFold(codec, "video/vp9") {
if packet == nil {
return 0, 0
}
var vp9 codecs.VP9Packet
_, err := vp9.Unmarshal(packet.Payload)
if err != nil {
return 0, 0
}
if !vp9.V {
return 0, 0
}
w := uint32(0)
h := uint32(0)
for i := range vp9.Width {
if i >= len(vp9.Height) {
break
}
if w < uint32(vp9.Width[i]) {
w = uint32(vp9.Width[i])
}
if h < uint32(vp9.Height[i]) {
h = uint32(vp9.Height[i])
}
}
return w, h
} else {
return 0, 0
}
}
// Flags holds parsed RTP header flags.
type Flags struct {
Seqno uint16
Marker bool
Start bool
End bool
Keyframe bool
Pid uint16 // only returned for VP8
Tid uint8
Sid uint8
TidUpSync bool
SidUpSync bool
SidNonReference bool
Discardable bool
Seqno uint16
Pid uint16
Marker bool
}
// PacketFlags extracts basic RTP header flags from a raw packet buffer.
func PacketFlags(codec string, buf []byte) (Flags, error) {
if len(buf) < 4 {
return Flags{}, errTruncated
}
var flags Flags
flags.Seqno = (uint16(buf[2]) << 8) | uint16(buf[3])
flags.Marker = (buf[1] & 0x80) != 0
if strings.EqualFold(codec, "video/vp8") {
var packet rtp.Packet
err := packet.Unmarshal(buf)
if err != nil {
return flags, err
}
var vp8 codecs.VP8Packet
_, err = vp8.Unmarshal(packet.Payload)
if err != nil {
return flags, err
}
flags.Start = vp8.S != 0 && vp8.PID == 0
flags.End = packet.Marker
flags.Keyframe = vp8.S != 0 && vp8.PID == 0 &&
len(vp8.Payload) > 0 && (vp8.Payload[0]&0x1) == 0
flags.Pid = vp8.PictureID
flags.Tid = vp8.TID
flags.TidUpSync = flags.Keyframe || vp8.Y == 1
flags.SidUpSync = flags.Keyframe
flags.Discardable = vp8.N == 1
return flags, nil
} else if strings.EqualFold(codec, "video/vp9") {
var packet rtp.Packet
err := packet.Unmarshal(buf)
if err != nil {
return flags, err
}
var vp9 codecs.VP9Packet
_, err = vp9.Unmarshal(packet.Payload)
if err != nil {
return flags, err
}
flags.Start = vp9.B
flags.End = vp9.E
if vp9.B && len(vp9.Payload) > 0 &&
(vp9.Payload[0]&0xc0) == 0x80 {
profile := (vp9.Payload[0] >> 4) & 0x3
if profile != 3 {
flags.Keyframe = (vp9.Payload[0] & 0xC) == 0
} else {
flags.Keyframe = (vp9.Payload[0] & 0x6) == 0
}
}
flags.Tid = vp9.TID
flags.Sid = vp9.SID
flags.TidUpSync = flags.Keyframe || vp9.U
flags.SidUpSync = flags.Keyframe || !vp9.P
flags.SidNonReference = (packet.Payload[0] & 0x01) != 0
return flags, nil
}
return flags, nil
}
// RewritePacket rewrites the sequence number and marker bit in a raw RTP packet.
func RewritePacket(codec string, data []byte, setMarker bool, seqno uint16, delta uint16) error {
if len(data) < 12 {
return errTruncated
@@ -337,39 +55,5 @@ func RewritePacket(codec string, data []byte, setMarker bool, seqno uint16, delt
}
}
// only rewrite PID for VP8.
if strings.EqualFold(codec, "video/vp8") {
x := (data[offset] & 0x80) != 0
if !x {
return nil
}
offset++
if len(data) <= offset {
return errTruncated
}
i := (data[offset] & 0x80) != 0
if !i {
return nil
}
offset++
if len(data) <= offset {
return errTruncated
}
m := (data[offset] & 0x80) != 0
if m {
if len(data) <= offset+1 {
return errTruncated
}
pid := (uint16(data[offset]&0x7F) << 8) |
uint16(data[offset+1])
pid = (pid + delta) & 0x7FFF
data[offset] = 0x80 | byte((pid>>8)&0x7F)
data[offset+1] = byte(pid & 0xFF)
} else {
data[offset] = (data[offset] + uint8(delta)) & 0x7F
}
return nil
}
return nil
}
+22 -234
View File
@@ -1,249 +1,37 @@
package codecs
import (
"bytes"
"testing"
"github.com/pion/rtp"
)
func TestVP8Keyframe(t *testing.T) {
ps := [][]byte{
{
0x80, 0xe0, 0x71, 0x3e, 0x5d, 0x6f, 0x3c, 0xc5,
0x75, 0xc, 0x80, 0x96, 0x90, 0x80, 0xb0, 0x4c,
0x90, 0x2, 0x0, 0x9d, 0x1, 0x2a, 0x10, 0x0, 0x10,
0x0, 0x39, 0x3, 0x0, 0x0, 0x1c, 0x22, 0x16, 0x16,
0x22, 0x66, 0x12, 0x20, 0x4, 0x90, 0x40, 0x4e,
0x9e, 0x8d, 0xe9, 0x40, 0xfe, 0xff, 0xab, 0x59,
0x72, 0x30, 0xd1, 0xaf, 0xe4, 0x6a, 0x11, 0x3,
0xfd, 0x15, 0xe9, 0x2, 0x2e, 0xdf, 0xd9, 0xd1,
0xb8, 0x0, 0x0,
},
{
0x80, 0x6f, 0x61, 0x8f, 0xd5, 0x36, 0xdc, 0x15,
0x1b, 0x4a, 0xb5, 0x29, 0x78, 0x9, 0xa1, 0x93,
0xa0, 0x5b, 0xd8, 0xf1, 0xde, 0x87, 0x23, 0x5a,
0xb9, 0x19, 0x97, 0xb7, 0xbd, 0xbf, 0xf7, 0x6e,
0xad, 0x82, 0xc4, 0x70, 0x1c, 0xc9, 0x3a, 0xb4,
0x1f, 0x13, 0x45, 0xb5, 0xf1, 0x0, 0xa5, 0xa5,
0xa9, 0xd0, 0xa5, 0xdf, 0x67, 0x88, 0x26, 0x30,
0x32,
},
func TestPacketFlags(t *testing.T) {
buf := []byte{0x80, 0x80, 0x01, 0x02, 0x03, 0x04}
flags, err := PacketFlags("audio/opus", buf)
if err != nil {
t.Fatalf("PacketFlags: %v", err)
}
var packet rtp.Packet
for i, p := range ps {
err := packet.Unmarshal(p)
if err != nil {
t.Errorf("Unmarshal(p%v): %v", i, err)
}
kf, kfKnown := Keyframe("video/vp8", &packet)
if kf != (i == 0) || !kfKnown {
t.Errorf("Keyframe(p%v): %v %v", i, kf, kfKnown)
}
if flags.Seqno != 0x0102 {
t.Errorf("seqno %v", flags.Seqno)
}
if !flags.Marker {
t.Errorf("marker")
}
}
func TestVP9Keyframe(t *testing.T) {
ps := [][]byte{
{
0x80, 0xe2, 0x6c, 0xb9, 0xcd, 0xa2, 0x77, 0x5c,
0xea, 0xf0, 0x14, 0xe9, 0x8f, 0xbd, 0x90, 0x18,
0x0, 0x10, 0x0, 0x10, 0x1, 0x4, 0x1, 0x82, 0x49,
0x83, 0x42, 0x0, 0x0, 0xf0, 0x0, 0xf4, 0x2, 0x38,
0x24, 0x1c, 0x18, 0x10, 0x0, 0x0, 0x20, 0x40, 0x0,
0x22, 0x9b, 0xff, 0xff, 0xd7, 0xe6, 0xc0, 0xa,
0xf2, 0x32, 0xd4, 0xdd, 0xa3, 0x69, 0xc6, 0xca,
0xd1, 0x50, 0xeb, 0x1c, 0x1, 0x50, 0x91, 0xf6,
0x64, 0xc7, 0x35, 0xe9, 0x0, 0xfe, 0x76, 0xb2,
0xb, 0x4d, 0xd7, 0x35, 0x23, 0xf3, 0x9f, 0x7f,
0x86, 0x37, 0xb9, 0x65, 0x3a, 0xf9, 0x66, 0xa0,
0x6a, 0xb2, 0x9b, 0xb3, 0x36, 0x5b, 0x47, 0xf2,
0x26, 0x5c, 0xe2, 0x23, 0x4f, 0xff, 0xff, 0xff,
0xfe, 0xc3, 0x49, 0x6b, 0x14, 0x58, 0x4d, 0xdc,
0xd8, 0xf5, 0x76, 0x81, 0x2e, 0xb3, 0x7f, 0xff,
0xfe, 0x18, 0xc8, 0xf8, 0x1b, 0xf6, 0xee, 0xc3,
0xc, 0x6f, 0x23, 0x34, 0x80,
},
{
0x80, 0xe2, 0x4a, 0xb5, 0x1a, 0x33, 0x3f, 0x7b,
0x9c, 0xda, 0x7b, 0xd0, 0x8d, 0xec, 0x14, 0x86,
0x0, 0x40, 0x92, 0x88, 0x2c, 0x50, 0x83, 0x30,
0x10, 0x1c, 0x6, 0x3, 0x0, 0x82, 0x99, 0x15, 0xc8,
0x0, 0x0, 0x0, 0x0, 0x18, 0x70, 0x0, 0x0, 0x4c,
0x4, 0xa0,
},
func TestRewritePacket(t *testing.T) {
buf := []byte{
0x80, 0x00, 0x01, 0x02,
0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a,
}
var packet rtp.Packet
for i, p := range ps {
err := packet.Unmarshal(p)
if err != nil {
t.Errorf("Unmarshal(p%v): %v", i, err)
}
kf, kfKnown := Keyframe("video/vp9", &packet)
if kf != (i == 0) || !kfKnown {
t.Errorf("Keyframe(p%v): %v %v", i, kf, kfKnown)
}
err := RewritePacket("audio/opus", buf, true, 0x0506, 0)
if err != nil {
t.Fatalf("RewritePacket: %v", err)
}
}
func TestH264Keyframe(t *testing.T) {
ps := [][]byte{
{
0x80, 0xe6, 0xf, 0xae, 0xfa, 0x86, 0x3b, 0x49,
0x59, 0xbd, 0x79, 0xe7, 0x78, 0x0, 0xc, 0x67,
0x42, 0xc0, 0xc, 0x8c, 0x8d, 0x4e, 0x40, 0x3c,
0x22, 0x11, 0xa8, 0x0, 0x4, 0x68, 0xce, 0x3c,
0x80, 0x0, 0x1a, 0x65, 0xb8, 0x0, 0x4, 0x0, 0x0,
0x9, 0xe3, 0x31, 0x40, 0x0, 0x46, 0x76, 0x38, 0x0,
0x8, 0x2, 0x47, 0x0, 0x2, 0x7f, 0x3f, 0x77, 0x6f,
0x67, 0x80,
},
{
0x80, 0xe6, 0xf, 0xaf, 0xfa, 0x86, 0x46, 0x89,
0x59, 0xbd, 0x79, 0xe7, 0x61, 0xe0, 0x0, 0x40,
0x0, 0xbe, 0x40, 0x9e, 0xa0,
},
if buf[1] != 0x80 {
t.Errorf("marker not set")
}
var packet rtp.Packet
for i, p := range ps {
err := packet.Unmarshal(p)
if err != nil {
t.Errorf("Unmarshal(p%v): %v", i, err)
}
kf, kfKnown := Keyframe("video/h264", &packet)
if kf != (i == 0) || !kfKnown {
t.Errorf("Keyframe(p%v): %v %v", i, kf, kfKnown)
}
}
}
var vp8 = []byte{
0x80, 0, 0, 42,
0, 0, 0, 0,
0, 0, 0, 0,
0x90, 0x80, 0x80, 57,
0, 0, 0, 0,
}
var emptyVP8 = []byte{
0x80, 0, 0, 42,
0, 0, 0, 0,
0, 0, 0, 0,
0x00,
}
func TestPacketFlagsVP8(t *testing.T) {
buf := bytes.Clone(vp8)
flags, err := PacketFlags("video/vp8", buf)
if flags.Seqno != 42 || !flags.Start || flags.Pid != 57 ||
flags.Sid != 0 || flags.Tid != 0 ||
!flags.TidUpSync || flags.Discardable || err != nil {
t.Errorf("Got %v, %v, %v, %v, %v, %v (%v)",
flags.Seqno, flags.Start, flags.Pid, flags.Sid,
flags.TidUpSync, flags.Discardable, err,
)
}
}
func TestEmptyPacketFlagsVP8(t *testing.T) {
buf := bytes.Clone(emptyVP8)
flags, err := PacketFlags("video/vp8", buf)
if flags.Seqno != 42 || flags.Start ||
flags.Sid != 0 || flags.Tid != 0 ||
flags.TidUpSync || flags.Discardable || err != nil {
t.Errorf("Got %v, %v, %v, %v, %v, %v (%v)",
flags.Seqno, flags.Start, flags.Pid, flags.Sid,
flags.TidUpSync, flags.Discardable, err,
)
}
}
func TestRewriteVP8(t *testing.T) {
for i := uint16(0); i < 0x7fff; i++ {
buf := bytes.Clone(vp8)
err := RewritePacket("video/vp8", buf, true, i, i)
if err != nil {
t.Errorf("rewrite: %v", err)
continue
}
flags, err := PacketFlags("video/vp8", buf)
if err != nil || flags.Seqno != i ||
flags.Pid != (57+i)&0x7FFF || !flags.Marker {
t.Errorf("Expected %v %v, got %v %v (%v)",
i, (57+i)&0x7FFF,
flags.Seqno, flags.Pid, err)
}
}
}
func TestRewriteEmptyVP8(t *testing.T) {
for i := uint16(0); i < 0x7fff; i++ {
buf := bytes.Clone(emptyVP8)
err := RewritePacket("video/vp8", buf, true, i, i)
if err != nil {
t.Errorf("rewrite: %v", err)
continue
}
flags, err := PacketFlags("video/vp8", buf)
if err != nil || flags.Seqno != i ||
!flags.Marker {
t.Errorf("Expected %v %v, got %v %v (%v)",
i, (57+i)&0x7FFF,
flags.Seqno, flags.Pid, err)
}
}
}
var vp9 = []byte{
0x80, 0, 0, 42,
0, 0, 0, 0,
0, 0, 0, 0,
0x88, 0x80, 57, 0,
}
func TestPacketFlagsVP9(t *testing.T) {
buf := bytes.Clone(vp9)
flags, err := PacketFlags("video/vp9", buf)
if flags.Seqno != 42 || !flags.Start || flags.Pid != 0 ||
flags.Sid != 0 || flags.Tid != 0 ||
flags.TidUpSync || flags.Discardable || err != nil {
t.Errorf("Got %v, %v, %v, %v, %v, %v (%v)",
flags.Seqno, flags.Start, flags.Pid, flags.Sid,
flags.TidUpSync, flags.Discardable, err,
)
}
}
func TestRewriteVP9(t *testing.T) {
for i := uint16(0); i < 0x7fff; i++ {
buf := bytes.Clone(vp9)
err := RewritePacket("video/vp9", buf, true, i, i)
if err != nil {
t.Errorf("rewrite: %v", err)
continue
}
flags, err := PacketFlags("video/vp9", buf)
if err != nil || flags.Seqno != i ||
flags.Pid != 0 || !flags.Marker {
t.Errorf("Expected %v %v, got %v %v (%v)",
i, 0,
flags.Seqno, flags.Pid, err)
}
if buf[2] != 0x05 || buf[3] != 0x06 {
t.Errorf("seqno %v %v", buf[2], buf[3])
}
}