status-go/vendor/github.com/pion/rtp/codecs/av1_packet.go

205 lines
5.4 KiB
Go
Raw Normal View History

2024-06-05 20:10:03 +00:00
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
2024-05-15 23:15:00 +00:00
package codecs
import (
2024-06-05 20:10:03 +00:00
"github.com/pion/rtp/codecs/av1/obu"
2024-05-15 23:15:00 +00:00
)
const (
zMask = byte(0b10000000)
zBitshift = 7
yMask = byte(0b01000000)
yBitshift = 6
wMask = byte(0b00110000)
wBitshift = 4
nMask = byte(0b00001000)
nBitshift = 3
2024-06-05 20:10:03 +00:00
obuFrameTypeMask = byte(0b01111000)
obuFrameTypeBitshift = 3
obuFameTypeSequenceHeader = 1
2024-05-15 23:15:00 +00:00
av1PayloaderHeadersize = 1
2024-06-05 20:10:03 +00:00
leb128Size = 1
2024-05-15 23:15:00 +00:00
)
// AV1Payloader payloads AV1 packets
2024-06-05 20:10:03 +00:00
type AV1Payloader struct {
sequenceHeader []byte
}
2024-05-15 23:15:00 +00:00
// Payload fragments a AV1 packet across one or more byte arrays
// See AV1Packet for description of AV1 Payload Header
func (p *AV1Payloader) Payload(mtu uint16, payload []byte) (payloads [][]byte) {
payloadDataIndex := 0
2024-06-05 20:10:03 +00:00
payloadDataRemaining := len(payload)
2024-05-15 23:15:00 +00:00
2024-06-05 20:10:03 +00:00
// Payload Data and MTU is non-zero
if mtu <= 0 || payloadDataRemaining <= 0 {
2024-05-15 23:15:00 +00:00
return payloads
}
2024-06-05 20:10:03 +00:00
// Cache Sequence Header and packetize with next payload
frameType := (payload[0] & obuFrameTypeMask) >> obuFrameTypeBitshift
if frameType == obuFameTypeSequenceHeader {
p.sequenceHeader = payload
return
}
2024-05-15 23:15:00 +00:00
for payloadDataRemaining > 0 {
2024-06-05 20:10:03 +00:00
obuCount := byte(1)
metadataSize := av1PayloaderHeadersize
if len(p.sequenceHeader) != 0 {
obuCount++
metadataSize += leb128Size + len(p.sequenceHeader)
2024-05-15 23:15:00 +00:00
}
2024-06-05 20:10:03 +00:00
out := make([]byte, min(int(mtu), payloadDataRemaining+metadataSize))
outOffset := av1PayloaderHeadersize
out[0] = obuCount << wBitshift
2024-05-15 23:15:00 +00:00
2024-06-05 20:10:03 +00:00
if obuCount == 2 {
// This Payload contain the start of a Coded Video Sequence
out[0] ^= nMask
2024-05-15 23:15:00 +00:00
2024-06-05 20:10:03 +00:00
out[1] = byte(obu.EncodeLEB128(uint(len(p.sequenceHeader))))
copy(out[2:], p.sequenceHeader)
outOffset += leb128Size + len(p.sequenceHeader)
p.sequenceHeader = nil
}
2024-05-15 23:15:00 +00:00
2024-06-05 20:10:03 +00:00
outBufferRemaining := len(out) - outOffset
copy(out[outOffset:], payload[payloadDataIndex:payloadDataIndex+outBufferRemaining])
payloadDataRemaining -= outBufferRemaining
payloadDataIndex += outBufferRemaining
// Does this Fragment contain an OBU that started in a previous payload
if len(payloads) > 0 {
2024-05-15 23:15:00 +00:00
out[0] ^= zMask
}
2024-06-05 20:10:03 +00:00
// This OBU will be continued in next Payload
2024-05-15 23:15:00 +00:00
if payloadDataRemaining != 0 {
out[0] ^= yMask
}
2024-06-05 20:10:03 +00:00
payloads = append(payloads, out)
2024-05-15 23:15:00 +00:00
}
return payloads
}
// AV1Packet represents a depacketized AV1 RTP Packet
2024-06-05 20:10:03 +00:00
/*
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+
* |Z|Y| W |N|-|-|-|
* +-+-+-+-+-+-+-+-+
**/
2024-05-15 23:15:00 +00:00
// https://aomediacodec.github.io/av1-rtp-spec/#44-av1-aggregation-header
type AV1Packet struct {
// Z: MUST be set to 1 if the first OBU element is an
// OBU fragment that is a continuation of an OBU fragment
// from the previous packet, and MUST be set to 0 otherwise.
Z bool
// Y: MUST be set to 1 if the last OBU element is an OBU fragment
// that will continue in the next packet, and MUST be set to 0 otherwise.
Y bool
// W: two bit field that describes the number of OBU elements in the packet.
// This field MUST be set equal to 0 or equal to the number of OBU elements
// contained in the packet. If set to 0, each OBU element MUST be preceded by
// a length field. If not set to 0 (i.e., W = 1, 2 or 3) the last OBU element
// MUST NOT be preceded by a length field. Instead, the length of the last OBU
// element contained in the packet can be calculated as follows:
// Length of the last OBU element =
// length of the RTP payload
// - length of aggregation header
// - length of previous OBU elements including length fields
W byte
// N: MUST be set to 1 if the packet is the first packet of a coded video sequence, and MUST be set to 0 otherwise.
N bool
// Each AV1 RTP Packet is a collection of OBU Elements. Each OBU Element may be a full OBU, or just a fragment of one.
// AV1Frame provides the tools to construct a collection of OBUs from a collection of OBU Elements
OBUElements [][]byte
2024-06-05 20:10:03 +00:00
videoDepacketizer
2024-05-15 23:15:00 +00:00
}
// Unmarshal parses the passed byte slice and stores the result in the AV1Packet this method is called upon
func (p *AV1Packet) Unmarshal(payload []byte) ([]byte, error) {
if payload == nil {
return nil, errNilPacket
} else if len(payload) < 2 {
return nil, errShortPacket
}
p.Z = ((payload[0] & zMask) >> zBitshift) != 0
p.Y = ((payload[0] & yMask) >> yBitshift) != 0
p.N = ((payload[0] & nMask) >> nBitshift) != 0
p.W = (payload[0] & wMask) >> wBitshift
if p.Z && p.N {
return nil, errIsKeyframeAndFragment
}
2024-06-05 20:10:03 +00:00
if !p.zeroAllocation {
obuElements, err := p.parseBody(payload[1:])
if err != nil {
return nil, err
}
p.OBUElements = obuElements
}
return payload[1:], nil
}
2024-05-15 23:15:00 +00:00
2024-06-05 20:10:03 +00:00
func (p *AV1Packet) parseBody(payload []byte) ([][]byte, error) {
if p.OBUElements != nil {
return p.OBUElements, nil
}
obuElements := [][]byte{}
var obuElementLength, bytesRead uint
currentIndex := uint(0)
2024-05-15 23:15:00 +00:00
for i := 1; ; i++ {
if currentIndex == uint(len(payload)) {
break
}
// If W bit is set the last OBU Element will have no length header
if byte(i) == p.W {
bytesRead = 0
obuElementLength = uint(len(payload)) - currentIndex
} else {
2024-06-05 20:10:03 +00:00
var err error
2024-05-15 23:15:00 +00:00
obuElementLength, bytesRead, err = obu.ReadLeb128(payload[currentIndex:])
if err != nil {
return nil, err
}
}
currentIndex += bytesRead
if uint(len(payload)) < currentIndex+obuElementLength {
return nil, errShortPacket
}
2024-06-05 20:10:03 +00:00
obuElements = append(obuElements, payload[currentIndex:currentIndex+obuElementLength])
2024-05-15 23:15:00 +00:00
currentIndex += obuElementLength
}
2024-06-05 20:10:03 +00:00
return obuElements, nil
2024-05-15 23:15:00 +00:00
}