diff --git a/rtpconn/rtp_test.go b/rtpconn/rtp_test.go new file mode 100644 index 0000000..3cf8099 --- /dev/null +++ b/rtpconn/rtp_test.go @@ -0,0 +1,48 @@ +package rtpconn + +import ( + "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, + }, + } + + 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 := isKeyframe("video/vp8", &packet) + if kf != (i == 0) || !kfKnown { + t.Errorf("isKeyframe(p%v): %v %v", i, kf, kfKnown) + } + } +} diff --git a/rtpconn/rtpreader.go b/rtpconn/rtpreader.go index 4316602..47645ca 100644 --- a/rtpconn/rtpreader.go +++ b/rtpconn/rtpreader.go @@ -13,15 +13,26 @@ import ( "github.com/jech/galene/rtptime" ) -func isVP8Keyframe(packet *rtp.Packet) bool { - var vp8 codecs.VP8Packet - _, err := vp8.Unmarshal(packet.Payload) - if err != nil { - return false - } +// isKeyframe 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 isKeyframe(codec string, packet *rtp.Packet) (bool, bool) { + switch strings.ToLower(codec) { + case "video/vp8": + var vp8 codecs.VP8Packet + _, err := vp8.Unmarshal(packet.Payload) + if err != nil || len(vp8.Payload) < 1 { + return false, false + } - return vp8.S != 0 && vp8.PID == 0 && - len(vp8.Payload) > 0 && (vp8.Payload[0]&0x1) == 0 + if vp8.S != 0 && vp8.PID == 0 && (vp8.Payload[0]&0x1) == 0 { + return true, true + } + return false, true + default: + return false, false + } } func readLoop(conn *rtpUpConnection, track *rtpUpTrack) { @@ -54,10 +65,7 @@ func readLoop(conn *rtpUpConnection, track *rtpUpTrack) { track.jitter.Accumulate(packet.Timestamp) - kf := false - if isvideo && strings.ToLower(codec.MimeType) == "video/vp8" { - kf = isVP8Keyframe(&packet) - } + kf, _ := isKeyframe(codec.MimeType, &packet) first, index := track.cache.Store( packet.SequenceNumber, packet.Timestamp, diff --git a/rtpconn/rtpwriter.go b/rtpconn/rtpwriter.go index 888967d..ad01df1 100644 --- a/rtpconn/rtpwriter.go +++ b/rtpconn/rtpwriter.go @@ -343,13 +343,8 @@ func rtpWriterLoop(writer *rtpWriter, up *rtpUpConnection, track *rtpUpTrack) { } if kfNeeded > kfUnneeded { - kf := false - kfValid := false - switch strings.ToLower(codec.MimeType) { - case "video/vp8": - kf = isVP8Keyframe(&packet) - kfValid = true - } + kf, kfKnown := + isKeyframe(codec.MimeType, &packet) if kf { kfNeeded = kfUnneeded } @@ -370,7 +365,7 @@ func rtpWriterLoop(writer *rtpWriter, up *rtpUpConnection, track *rtpUpTrack) { up.sendPLI(track) } - if !kfValid { + if !kfKnown { // we cannot detect keyframes for // this codec, reset our state kfNeeded = kfUnneeded