// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>// SPDX-License-Identifier: MITpackage codecsimport ()// Use global random generator to properly seed by crypto grade random.var globalMathRandomGenerator = randutil.NewMathRandomGenerator() // nolint:gochecknoglobals// VP9Payloader payloads VP9 packets.typeVP9Payloaderstruct {// whether to use flexible mode or non-flexible mode. FlexibleMode bool// InitialPictureIDFn is a function that returns random initial picture ID. InitialPictureIDFn func() uint16 pictureID uint16 initialized bool}const ( maxSpatialLayers = 5 maxVP9RefPics = 3)// Payload fragments an VP9 packet across one or more byte arrays.func ( *VP9Payloader) ( uint16, []byte) [][]byte {if !.initialized {if .InitialPictureIDFn == nil { .InitialPictureIDFn = func() uint16 {returnuint16(globalMathRandomGenerator.Intn(0x7FFF)) // nolint: gosec } } .pictureID = .InitialPictureIDFn() & 0x7FFF .initialized = true }var [][]byteif .FlexibleMode { = .payloadFlexible(, ) } else { = .payloadNonFlexible(, ) } .pictureID++if .pictureID >= 0x8000 { .pictureID = 0 }return}func ( *VP9Payloader) ( uint16, []byte) [][]byte {/* * Flexible mode (F=1) * 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * |I|P|L|F|B|E|V|Z| (REQUIRED) * +-+-+-+-+-+-+-+-+ * I: |M| PICTURE ID | (REQUIRED) * +-+-+-+-+-+-+-+-+ * M: | EXTENDED PID | (RECOMMENDED) * +-+-+-+-+-+-+-+-+ * L: | TID |U| SID |D| (CONDITIONALLY RECOMMENDED) * +-+-+-+-+-+-+-+-+ -\ * P,F: | P_DIFF |N| (CONDITIONALLY REQUIRED) - up to 3 times * +-+-+-+-+-+-+-+-+ -/ * V: | SS | * | .. | * +-+-+-+-+-+-+-+-+ */ := 3 := int() - := len() := 0var [][]byteifminInt(, ) <= 0 {return [][]byte{} }for > 0 { := minInt(, ) := make([]byte, +) [0] = 0x90// F=1, I=1if == 0 { [0] |= 0x08// B=1 }if == { [0] |= 0x04// E=1 } [1] = byte(.pictureID>>8) | 0x80 [2] = byte(.pictureID)copy([:], [:+]) = append(, ) -= += }return}func ( *VP9Payloader) ( uint16, []byte) [][]byte { //nolint:cyclop/* * Non-flexible mode (F=0) * 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * |I|P|L|F|B|E|V|Z| (REQUIRED) * +-+-+-+-+-+-+-+-+ * I: |M| PICTURE ID | (RECOMMENDED) * +-+-+-+-+-+-+-+-+ * M: | EXTENDED PID | (RECOMMENDED) * +-+-+-+-+-+-+-+-+ * L: | TID |U| SID |D| (CONDITIONALLY RECOMMENDED) * +-+-+-+-+-+-+-+-+ * | TL0PICIDX | (CONDITIONALLY REQUIRED) * +-+-+-+-+-+-+-+-+ * V: | SS | * | .. | * +-+-+-+-+-+-+-+-+ */varvp9.Header := .Unmarshal()if != nil {return [][]byte{} } := len() := 0var [][]bytefor > 0 {varintif !.NonKeyFrame && == 0 { = 3 + 8 } else { = 3 } := int() - := minInt(, )if <= 0 {return [][]byte{} } := make([]byte, +) [0] = 0x80 | 0x01// I=1, Z=1if .NonKeyFrame { [0] |= 0x40// P=1 }if == 0 { [0] |= 0x08// B=1 }if == { [0] |= 0x04// E=1 } [1] = byte(.pictureID>>8) | 0x80 [2] = byte(.pictureID) := 3if !.NonKeyFrame && == 0 { [0] |= 0x02// V=1 [] = 0x10 | 0x08// N_S=0, Y=1, G=1 ++ := .Width() [] = byte( >> 8) ++ [] = byte( & 0xFF) ++ := .Height() [] = byte( >> 8) ++ [] = byte( & 0xFF) ++ [] = 0x01// N_G=1 ++ [] = 1<<4 | 1<<2// TID=0, U=1, R=1 ++ [] = 0x01// P_DIFF=1 }copy([:], [:+]) = append(, ) -= += }return}// VP9Packet represents the VP9 header that is stored in the payload of an RTP Packet.typeVP9Packetstruct {// Required header I bool// PictureID is present P bool// Inter-picture predicted frame L bool// Layer indices is present F bool// Flexible mode B bool// Start of a frame E bool// End of a frame V bool// Scalability structure (SS) data present Z bool// Not a reference frame for upper spatial layers// Recommended headers PictureID uint16// 7 or 16 bits, picture ID// Conditionally recommended headers TID uint8// Temporal layer ID U bool// Switching up point SID uint8// Spatial layer ID D bool// Inter-layer dependency used// Conditionally required headers PDiff []uint8// Reference index (F=1) TL0PICIDX uint8// Temporal layer zero index (F=0)// Scalability structure headers NS uint8// N_S + 1 indicates the number of spatial layers present in the VP9 stream Y bool// Each spatial layer's frame resolution present G bool// PG description present flag. NG uint8// N_G indicates the number of pictures in a Picture Group (PG) Width []uint16 Height []uint16 PGTID []uint8// Temporal layer ID of pictures in a Picture Group PGU []bool// Switching up point of pictures in a Picture Group PGPDiff [][]uint8// Reference indecies of pictures in a Picture Group Payload []bytevideoDepacketizer}// Unmarshal parses the passed byte slice and stores the result in the VP9Packet this method is called upon.func ( *VP9Packet) ( []byte) ([]byte, error) { // nolint:cyclopif == nil {returnnil, errNilPacket }iflen() < 1 {returnnil, errShortPacket } .I = [0]&0x80 != 0 .P = [0]&0x40 != 0 .L = [0]&0x20 != 0 .F = [0]&0x10 != 0 .B = [0]&0x08 != 0 .E = [0]&0x04 != 0 .V = [0]&0x02 != 0 .Z = [0]&0x01 != 0 := 1varerrorif .I { , = .parsePictureID(, )if != nil {returnnil, } }if .L { , = .parseLayerInfo(, )if != nil {returnnil, } }if .F && .P { , = .parseRefIndices(, )if != nil {returnnil, } }if .V { , = .parseSSData(, )if != nil {returnnil, } } .Payload = [:]return .Payload, nil}// Picture ID:/** +-+-+-+-+-+-+-+-+* I: |M| PICTURE ID | M:0 => picture id is 7 bits.* +-+-+-+-+-+-+-+-+ M:1 => picture id is 15 bits.* M: | EXTENDED PID |* +-+-+-+-+-+-+-+-+**/// .func ( *VP9Packet) ( []byte, int) (int, error) {iflen() <= {return , errShortPacket } .PictureID = uint16([] & 0x7F)if []&0x80 != 0 { ++iflen() <= {return , errShortPacket } .PictureID = .PictureID<<8 | uint16([]) } ++return , nil}func ( *VP9Packet) ( []byte, int) (int, error) { , := .parseLayerInfoCommon(, )if != nil {return , }if .F {return , nil }return .parseLayerInfoNonFlexibleMode(, )}// Layer indices (flexible mode):/** +-+-+-+-+-+-+-+-+* L: | T |U| S |D|* +-+-+-+-+-+-+-+-+**/// .func ( *VP9Packet) ( []byte, int) (int, error) {iflen() <= {return , errShortPacket } .TID = [] >> 5 .U = []&0x10 != 0 .SID = ([] >> 1) & 0x7 .D = []&0x01 != 0if .SID >= maxSpatialLayers {return , errTooManySpatialLayers } ++return , nil}// Layer indices (non-flexible mode):/** +-+-+-+-+-+-+-+-+* L: | T |U| S |D|* +-+-+-+-+-+-+-+-+* | TL0PICIDX |* +-+-+-+-+-+-+-+-+**/// .func ( *VP9Packet) ( []byte, int) (int, error) {iflen() <= {return , errShortPacket } .TL0PICIDX = [] ++return , nil}// Reference indices: ./** +-+-+-+-+-+-+-+-+ P=1,F=1: At least one reference index* P,F: | P_DIFF |N| up to 3 times has to be specified.* +-+-+-+-+-+-+-+-+ N=1: An additional P_DIFF follows* current P_DIFF.***/// .func ( *VP9Packet) ( []byte, int) (int, error) {for {iflen() <= {return , errShortPacket } .PDiff = append(.PDiff, []>>1)if []&0x01 == 0 {break }iflen(.PDiff) >= maxVP9RefPics {return , errTooManyPDiff } ++ } ++return , nil}// Scalability structure (SS):/** +-+-+-+-+-+-+-+-+* V: | N_S |Y|G|-|-|-|* +-+-+-+-+-+-+-+-+ -|* Y: | WIDTH | (OPTIONAL) .* + .* | | (OPTIONAL) .* +-+-+-+-+-+-+-+-+ . N_S + 1 times* | HEIGHT | (OPTIONAL) .* + .* | | (OPTIONAL) .* +-+-+-+-+-+-+-+-+ -|* G: | N_G | (OPTIONAL)* +-+-+-+-+-+-+-+-+ -|* N_G: | T |U| R |-|-| (OPTIONAL) .* +-+-+-+-+-+-+-+-+ -| . N_G times* | P_DIFF | (OPTIONAL) . R times .* +-+-+-+-+-+-+-+-+ -| -|**/// .func ( *VP9Packet) ( []byte, int) (int, error) { // nolint: cyclopiflen() <= {return , errShortPacket } .NS = [] >> 5 .Y = []&0x10 != 0 .G = []&0x8 != 0 ++ := .NS + 1 .NG = 0if .Y { .Width = make([]uint16, ) .Height = make([]uint16, )for := 0; < int(); ++ {iflen() <= ( + 3) {return , errShortPacket } .Width[] = uint16([])<<8 | uint16([+1]) += 2 .Height[] = uint16([])<<8 | uint16([+1]) += 2 } }if .G {iflen() <= {return , errShortPacket } .NG = [] ++ }for := 0; < int(.NG); ++ {iflen() <= {return , errShortPacket } .PGTID = append(.PGTID, []>>5) .PGU = append(.PGU, []&0x10 != 0) := ([] >> 2) & 0x3 ++ .PGPDiff = append(.PGPDiff, []uint8{})iflen() <= ( + int() - 1) {return , errShortPacket }for := 0; < int(); ++ { .PGPDiff[] = append(.PGPDiff[], []) ++ } }return , nil}// VP9PartitionHeadChecker checks VP9 partition head.//// Deprecated: replaced by VP9Packet.IsPartitionHead().typeVP9PartitionHeadCheckerstruct{}// IsPartitionHead checks whether if this is a head of the VP9 partition.//// Deprecated: replaced by VP9Packet.IsPartitionHead().func (*VP9PartitionHeadChecker) ( []byte) bool {return (&VP9Packet{}).IsPartitionHead()}// IsPartitionHead checks whether if this is a head of the VP9 partition.func (*VP9Packet) ( []byte) bool {iflen() < 1 {returnfalse }return ([0] & 0x08) != 0}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.