From b2ea8e8533a86b026a17a828ba359727cf3bd172 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 11 May 2021 19:59:24 +0200 Subject: [PATCH] Move isKeyframe into its own file. --- rtpconn/codec.go | 112 +++++++++++++++++++++++++++++++++++++++++++ rtpconn/rtpreader.go | 106 ---------------------------------------- 2 files changed, 112 insertions(+), 106 deletions(-) create mode 100644 rtpconn/codec.go diff --git a/rtpconn/codec.go b/rtpconn/codec.go new file mode 100644 index 0000000..f2e0dd9 --- /dev/null +++ b/rtpconn/codec.go @@ -0,0 +1,112 @@ +package rtpconn + +import ( + "strings" + + "github.com/pion/rtp" + "github.com/pion/rtp/codecs" +) + +// 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 + } + + if vp8.S != 0 && vp8.PID == 0 && (vp8.Payload[0]&0x1) == 0 { + return true, true + } + return false, true + case "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 + case "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 == 5, 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 == 5 { + 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 == 5), true + } + return false, false + + default: + return false, false + } +} diff --git a/rtpconn/rtpreader.go b/rtpconn/rtpreader.go index f7e5990..107fdd4 100644 --- a/rtpconn/rtpreader.go +++ b/rtpconn/rtpreader.go @@ -3,120 +3,14 @@ package rtpconn import ( "io" "log" - "strings" "github.com/pion/rtp" - "github.com/pion/rtp/codecs" "github.com/pion/webrtc/v3" "github.com/jech/galene/packetcache" "github.com/jech/galene/rtptime" ) -// 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 - } - - if vp8.S != 0 && vp8.PID == 0 && (vp8.Payload[0]&0x1) == 0 { - return true, true - } - return false, true - case "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 - case "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 == 5, 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 == 5 { - 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 == 5), true - } - return false, false - - default: - return false, false - } -} - func readLoop(conn *rtpUpConnection, track *rtpUpTrack) { writers := rtpWriterPool{conn: conn, track: track} defer func() {