mirror of
https://github.com/jech/galene.git
synced 2024-11-26 02:25:58 +01:00
Move packet parsing code into its own package.
This commit is contained in:
parent
8178275164
commit
89780b866b
5 changed files with 101 additions and 99 deletions
|
@ -1,4 +1,4 @@
|
||||||
package rtpconn
|
package codecs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -8,11 +8,14 @@ import (
|
||||||
"github.com/pion/rtp/codecs"
|
"github.com/pion/rtp/codecs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// isKeyframe determines if packet is the start of a keyframe.
|
var errTruncated = errors.New("truncated packet")
|
||||||
|
var errUnsupportedCodec = errors.New("unsupported codec")
|
||||||
|
|
||||||
|
// Keyframe determines if packet is the start of a keyframe.
|
||||||
// It returns (true, true) if that is the case, (false, true) if that is
|
// 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
|
// definitely not the case, and (false, false) if the information cannot
|
||||||
// be determined.
|
// be determined.
|
||||||
func isKeyframe(codec string, packet *rtp.Packet) (bool, bool) {
|
func Keyframe(codec string, packet *rtp.Packet) (bool, bool) {
|
||||||
if strings.EqualFold(codec, "video/vp8") {
|
if strings.EqualFold(codec, "video/vp8") {
|
||||||
var vp8 codecs.VP8Packet
|
var vp8 codecs.VP8Packet
|
||||||
_, err := vp8.Unmarshal(packet.Payload)
|
_, err := vp8.Unmarshal(packet.Payload)
|
||||||
|
@ -179,29 +182,26 @@ func isKeyframe(codec string, packet *rtp.Packet) (bool, bool) {
|
||||||
return false, false
|
return false, false
|
||||||
}
|
}
|
||||||
|
|
||||||
var errTruncated = errors.New("truncated packet")
|
type Flags struct {
|
||||||
var errUnsupportedCodec = errors.New("unsupported codec")
|
Seqno uint16
|
||||||
|
Start bool
|
||||||
type packetFlags struct {
|
Pid uint16 // only if it needs rewriting
|
||||||
seqno uint16
|
Tid uint8
|
||||||
start bool
|
Sid uint8
|
||||||
pid uint16 // only if it needs rewriting
|
TidUpSync bool
|
||||||
tid uint8
|
SidSync bool
|
||||||
sid uint8
|
SidNonReference bool
|
||||||
tidupsync bool
|
Discardable bool
|
||||||
sidsync bool
|
|
||||||
sidnonreference bool
|
|
||||||
discardable bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPacketFlags(codec string, buf []byte) (packetFlags, error) {
|
func PacketFlags(codec string, buf []byte) (Flags, error) {
|
||||||
if len(buf) < 12 {
|
if len(buf) < 12 {
|
||||||
return packetFlags{}, errTruncated
|
return Flags{}, errTruncated
|
||||||
}
|
}
|
||||||
|
|
||||||
var flags packetFlags
|
var flags Flags
|
||||||
|
|
||||||
flags.seqno = (uint16(buf[2]) << 8) | uint16(buf[3])
|
flags.Seqno = (uint16(buf[2]) << 8) | uint16(buf[3])
|
||||||
|
|
||||||
if strings.EqualFold(codec, "video/vp8") {
|
if strings.EqualFold(codec, "video/vp8") {
|
||||||
var packet rtp.Packet
|
var packet rtp.Packet
|
||||||
|
@ -215,11 +215,11 @@ func getPacketFlags(codec string, buf []byte) (packetFlags, error) {
|
||||||
return flags, err
|
return flags, err
|
||||||
}
|
}
|
||||||
|
|
||||||
flags.start = vp8.S == 1 && vp8.PID == 0
|
flags.Start = vp8.S == 1 && vp8.PID == 0
|
||||||
flags.pid = vp8.PictureID
|
flags.Pid = vp8.PictureID
|
||||||
flags.tid = vp8.TID
|
flags.Tid = vp8.TID
|
||||||
flags.tidupsync = vp8.Y == 1
|
flags.TidUpSync = vp8.Y == 1
|
||||||
flags.discardable = vp8.N == 1
|
flags.Discardable = vp8.N == 1
|
||||||
return flags, nil
|
return flags, nil
|
||||||
} else if strings.EqualFold(codec, "video/vp9") {
|
} else if strings.EqualFold(codec, "video/vp9") {
|
||||||
var packet rtp.Packet
|
var packet rtp.Packet
|
||||||
|
@ -232,19 +232,19 @@ func getPacketFlags(codec string, buf []byte) (packetFlags, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return flags, err
|
return flags, err
|
||||||
}
|
}
|
||||||
flags.start = vp9.B
|
flags.Start = vp9.B
|
||||||
flags.tid = vp9.TID
|
flags.Tid = vp9.TID
|
||||||
flags.sid = vp9.SID
|
flags.Sid = vp9.SID
|
||||||
flags.tidupsync = vp9.U
|
flags.TidUpSync = vp9.U
|
||||||
flags.sidsync = vp9.P
|
flags.SidSync = vp9.P
|
||||||
// not yet in pion/rtp
|
// not yet in pion/rtp
|
||||||
flags.sidnonreference = (packet.Payload[0] & 0x01) != 0
|
flags.SidNonReference = (packet.Payload[0] & 0x01) != 0
|
||||||
return flags, nil
|
return flags, nil
|
||||||
}
|
}
|
||||||
return flags, nil
|
return flags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func rewritePacket(codec string, data []byte, seqno uint16, delta uint16) error {
|
func RewritePacket(codec string, data []byte, seqno uint16, delta uint16) error {
|
||||||
if len(data) < 12 {
|
if len(data) < 12 {
|
||||||
return errTruncated
|
return errTruncated
|
||||||
}
|
}
|
46
codecs/codecs_test.go
Normal file
46
codecs/codecs_test.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package codecs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var vp8 = []byte{
|
||||||
|
0x80, 0, 0, 42,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
|
||||||
|
0x90, 0x80, 0x80, 57,
|
||||||
|
|
||||||
|
0, 0, 0, 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPacketFlags(t *testing.T) {
|
||||||
|
buf := append([]byte{}, 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 TestRewrite(t *testing.T) {
|
||||||
|
for i := uint16(0); i < 0x7fff; i++ {
|
||||||
|
buf := append([]byte{}, vp8...)
|
||||||
|
err := RewritePacket("video/vp8", buf, 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 {
|
||||||
|
t.Errorf("Expected %v %v, got %v %v (%v)",
|
||||||
|
i, (57+i)&0x7FFF,
|
||||||
|
flags.Seqno, flags.Pid, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,46 +0,0 @@
|
||||||
package rtpconn
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var vp8 = []byte{
|
|
||||||
0x80, 0, 0, 42,
|
|
||||||
0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0,
|
|
||||||
|
|
||||||
0x90, 0x80, 0x80, 57,
|
|
||||||
|
|
||||||
0, 0, 0, 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPacketFlags(t *testing.T) {
|
|
||||||
buf := append([]byte{}, vp8...)
|
|
||||||
flags, err := getPacketFlags("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 TestRewrite(t *testing.T) {
|
|
||||||
for i := uint16(0); i < 0x7fff; i++ {
|
|
||||||
buf := append([]byte{}, vp8...)
|
|
||||||
err := rewritePacket("video/vp8", buf, i, i)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("rewrite: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
flags, err := getPacketFlags("video/vp8", buf)
|
|
||||||
if err != nil || flags.seqno != i ||
|
|
||||||
flags.pid != (57 + i) & 0x7FFF {
|
|
||||||
t.Errorf("Expected %v %v, got %v %v (%v)",
|
|
||||||
i, (57 + i) & 0x7FFF,
|
|
||||||
flags.seqno, flags.pid, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/pion/sdp/v3"
|
"github.com/pion/sdp/v3"
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
|
|
||||||
|
"github.com/jech/galene/codecs"
|
||||||
"github.com/jech/galene/conn"
|
"github.com/jech/galene/conn"
|
||||||
"github.com/jech/galene/estimator"
|
"github.com/jech/galene/estimator"
|
||||||
"github.com/jech/galene/group"
|
"github.com/jech/galene/group"
|
||||||
|
@ -213,59 +214,59 @@ var packetBufPool = sync.Pool{
|
||||||
func (down *rtpDownTrack) Write(buf []byte) (int, error) {
|
func (down *rtpDownTrack) Write(buf []byte) (int, error) {
|
||||||
codec := down.remote.Codec().MimeType
|
codec := down.remote.Codec().MimeType
|
||||||
|
|
||||||
flags, err := getPacketFlags(codec, buf)
|
flags, err := codecs.PacketFlags(codec, buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
layer := down.getLayerInfo()
|
layer := down.getLayerInfo()
|
||||||
|
|
||||||
if flags.tid > layer.maxTid || flags.sid > layer.maxSid {
|
if flags.Tid > layer.maxTid || flags.Sid > layer.maxSid {
|
||||||
if flags.tid > layer.maxTid {
|
if flags.Tid > layer.maxTid {
|
||||||
if layer.tid == layer.maxTid {
|
if layer.tid == layer.maxTid {
|
||||||
layer.wantedTid = flags.tid
|
layer.wantedTid = flags.Tid
|
||||||
layer.tid = flags.tid
|
layer.tid = flags.Tid
|
||||||
}
|
}
|
||||||
layer.maxTid = flags.tid
|
layer.maxTid = flags.Tid
|
||||||
}
|
}
|
||||||
if flags.sid > layer.maxSid {
|
if flags.Sid > layer.maxSid {
|
||||||
if layer.sid == layer.maxSid {
|
if layer.sid == layer.maxSid {
|
||||||
layer.wantedSid = flags.sid
|
layer.wantedSid = flags.Sid
|
||||||
layer.sid = flags.sid
|
layer.sid = flags.Sid
|
||||||
}
|
}
|
||||||
layer.maxSid = flags.sid
|
layer.maxSid = flags.Sid
|
||||||
}
|
}
|
||||||
down.setLayerInfo(layer)
|
down.setLayerInfo(layer)
|
||||||
down.adjustLayer()
|
down.adjustLayer()
|
||||||
}
|
}
|
||||||
if flags.start && (layer.tid != layer.wantedTid) {
|
if flags.Start && (layer.tid != layer.wantedTid) {
|
||||||
if layer.wantedTid < layer.tid || flags.tidupsync {
|
if layer.wantedTid < layer.tid || flags.TidUpSync {
|
||||||
layer.tid = layer.wantedTid
|
layer.tid = layer.wantedTid
|
||||||
down.setLayerInfo(layer)
|
down.setLayerInfo(layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.start && (layer.sid != layer.wantedSid) {
|
if flags.Start && (layer.sid != layer.wantedSid) {
|
||||||
if flags.sidsync {
|
if flags.SidSync {
|
||||||
layer.sid = layer.wantedTid
|
layer.sid = layer.wantedTid
|
||||||
down.setLayerInfo(layer)
|
down.setLayerInfo(layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.tid > layer.tid || flags.sid > layer.sid ||
|
if flags.Tid > layer.tid || flags.Sid > layer.sid ||
|
||||||
(flags.sid < layer.sid && flags.sidnonreference) {
|
(flags.Sid < layer.sid && flags.SidNonReference) {
|
||||||
ok := down.packetmap.Drop(flags.seqno, flags.pid)
|
ok := down.packetmap.Drop(flags.Seqno, flags.Pid)
|
||||||
if ok {
|
if ok {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ok, newseqno, piddelta := down.packetmap.Map(flags.seqno, flags.pid)
|
ok, newseqno, piddelta := down.packetmap.Map(flags.Seqno, flags.Pid)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if newseqno == flags.seqno && piddelta == 0 {
|
if newseqno == flags.Seqno && piddelta == 0 {
|
||||||
return down.write(buf)
|
return down.write(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +275,7 @@ func (down *rtpDownTrack) Write(buf []byte) (int, error) {
|
||||||
buf2 := ibuf2.([]byte)
|
buf2 := ibuf2.([]byte)
|
||||||
|
|
||||||
n := copy(buf2, buf)
|
n := copy(buf2, buf)
|
||||||
err = rewritePacket(codec, buf2[:n], newseqno, piddelta)
|
err = codecs.RewritePacket(codec, buf2[:n], newseqno, piddelta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
|
|
||||||
|
"github.com/jech/galene/codecs"
|
||||||
"github.com/jech/galene/packetcache"
|
"github.com/jech/galene/packetcache"
|
||||||
"github.com/jech/galene/rtptime"
|
"github.com/jech/galene/rtptime"
|
||||||
)
|
)
|
||||||
|
@ -74,7 +75,7 @@ func readLoop(track *rtpUpTrack) {
|
||||||
|
|
||||||
track.jitter.Accumulate(packet.Timestamp)
|
track.jitter.Accumulate(packet.Timestamp)
|
||||||
|
|
||||||
kf, kfKnown := isKeyframe(codec.MimeType, &packet)
|
kf, kfKnown := codecs.Keyframe(codec.MimeType, &packet)
|
||||||
if kf || !kfKnown {
|
if kf || !kfKnown {
|
||||||
kfNeeded = false
|
kfNeeded = false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue