| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- package codecs
- import (
- "github.com/pion/rtp/pkg/obu"
- )
- const (
- zMask = byte(0b10000000)
- zBitshift = 7
- yMask = byte(0b01000000)
- yBitshift = 6
- wMask = byte(0b00110000)
- wBitshift = 4
- nMask = byte(0b00001000)
- nBitshift = 3
- av1PayloaderHeadersize = 1
- )
- // AV1Payloader payloads AV1 packets
- type AV1Payloader struct{}
- // 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) {
- maxFragmentSize := int(mtu) - av1PayloaderHeadersize - 2
- payloadDataRemaining := len(payload)
- payloadDataIndex := 0
- // Make sure the fragment/payload size is correct
- if min(maxFragmentSize, payloadDataRemaining) <= 0 {
- return payloads
- }
- for payloadDataRemaining > 0 {
- currentFragmentSize := min(maxFragmentSize, payloadDataRemaining)
- leb128Size := 1
- if currentFragmentSize >= 127 {
- leb128Size = 2
- }
- out := make([]byte, av1PayloaderHeadersize+leb128Size+currentFragmentSize)
- leb128Value := obu.EncodeLEB128(uint(currentFragmentSize))
- if leb128Size == 1 {
- out[1] = byte(leb128Value)
- } else {
- out[1] = byte(leb128Value >> 8)
- out[2] = byte(leb128Value)
- }
- copy(out[av1PayloaderHeadersize+leb128Size:], payload[payloadDataIndex:payloadDataIndex+currentFragmentSize])
- payloads = append(payloads, out)
- payloadDataRemaining -= currentFragmentSize
- payloadDataIndex += currentFragmentSize
- if len(payloads) > 1 {
- out[0] ^= zMask
- }
- if payloadDataRemaining != 0 {
- out[0] ^= yMask
- }
- }
- return payloads
- }
- // AV1Packet represents a depacketized AV1 RTP Packet
- //
- // 0 1 2 3 4 5 6 7
- // +-+-+-+-+-+-+-+-+
- // |Z|Y| W |N|-|-|-|
- // +-+-+-+-+-+-+-+-+
- //
- // 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
- }
- // 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
- }
- currentIndex := uint(1)
- p.OBUElements = [][]byte{}
- var (
- obuElementLength, bytesRead uint
- err error
- )
- 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 {
- obuElementLength, bytesRead, err = obu.ReadLeb128(payload[currentIndex:])
- if err != nil {
- return nil, err
- }
- }
- currentIndex += bytesRead
- if uint(len(payload)) < currentIndex+obuElementLength {
- return nil, errShortPacket
- }
- p.OBUElements = append(p.OBUElements, payload[currentIndex:currentIndex+obuElementLength])
- currentIndex += obuElementLength
- }
- return payload[1:], nil
- }
|