Commit 89780b86 authored by Juliusz Chroboczek's avatar Juliusz Chroboczek

Move packet parsing code into its own package.

parent 81782751
package rtpconn package codecs
import ( import (
"errors" "errors"
...@@ -8,11 +8,14 @@ import ( ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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
} }
......
package rtpconn package codecs
import ( import (
"testing" "testing"
...@@ -16,13 +16,13 @@ var vp8 = []byte{ ...@@ -16,13 +16,13 @@ var vp8 = []byte{
func TestPacketFlags(t *testing.T) { func TestPacketFlags(t *testing.T) {
buf := append([]byte{}, vp8...) buf := append([]byte{}, vp8...)
flags, err := getPacketFlags("video/vp8", buf) flags, err := PacketFlags("video/vp8", buf)
if flags.seqno != 42 || !flags.start || flags.pid != 57 || if flags.Seqno != 42 || !flags.Start || flags.Pid != 57 ||
flags.sid != 0 || flags.tid != 0 || flags.Sid != 0 || flags.Tid != 0 ||
flags.tidupsync || flags.discardable || err != nil { flags.TidUpSync || flags.Discardable || err != nil {
t.Errorf("Got %v, %v, %v, %v, %v, %v (%v)", t.Errorf("Got %v, %v, %v, %v, %v, %v (%v)",
flags.seqno, flags.start, flags.pid, flags.sid, flags.Seqno, flags.Start, flags.Pid, flags.Sid,
flags.tidupsync, flags.discardable, err, flags.TidUpSync, flags.Discardable, err,
) )
} }
} }
...@@ -30,17 +30,17 @@ func TestPacketFlags(t *testing.T) { ...@@ -30,17 +30,17 @@ func TestPacketFlags(t *testing.T) {
func TestRewrite(t *testing.T) { func TestRewrite(t *testing.T) {
for i := uint16(0); i < 0x7fff; i++ { for i := uint16(0); i < 0x7fff; i++ {
buf := append([]byte{}, vp8...) buf := append([]byte{}, vp8...)
err := rewritePacket("video/vp8", buf, i, i) err := RewritePacket("video/vp8", buf, i, i)
if err != nil { if err != nil {
t.Errorf("rewrite: %v", err) t.Errorf("rewrite: %v", err)
continue continue
} }
flags, err := getPacketFlags("video/vp8", buf) flags, err := PacketFlags("video/vp8", buf)
if err != nil || flags.seqno != i || if err != nil || flags.Seqno != i ||
flags.pid != (57 + i) & 0x7FFF { flags.Pid != (57+i)&0x7FFF {
t.Errorf("Expected %v %v, got %v %v (%v)", t.Errorf("Expected %v %v, got %v %v (%v)",
i, (57 + i) & 0x7FFF, i, (57+i)&0x7FFF,
flags.seqno, flags.pid, err) flags.Seqno, flags.Pid, err)
} }
} }
} }
...@@ -14,6 +14,7 @@ import ( ...@@ -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{ ...@@ -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) { ...@@ -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 ( ...@@ -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) { ...@@ -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
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment