feat: Waku v2 bridge

Issue #12610
This commit is contained in:
Michal Iskierko
2023-11-12 13:29:38 +01:00
parent 56e7bd01ca
commit 6d31343205
6716 changed files with 1982502 additions and 5891 deletions

24
vendor/github.com/pion/rtp/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,24 @@
### JetBrains IDE ###
#####################
.idea/
### Emacs Temporary Files ###
#############################
*~
### Folders ###
###############
bin/
vendor/
node_modules/
### Files ###
#############
*.ivf
*.ogg
tags
cover.out
*.sw[poe]
*.wasm
examples/sfu-ws/cert.pem
examples/sfu-ws/key.pem

89
vendor/github.com/pion/rtp/.golangci.yml generated vendored Normal file
View File

@@ -0,0 +1,89 @@
linters-settings:
govet:
check-shadowing: true
misspell:
locale: US
exhaustive:
default-signifies-exhaustive: true
gomodguard:
blocked:
modules:
- github.com/pkg/errors:
recommendations:
- errors
linters:
enable:
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
- bodyclose # checks whether HTTP response body is closed successfully
- deadcode # Finds unused code
- depguard # Go linter that checks if package imports are in a list of acceptable packages
- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
- dupl # Tool for code clone detection
- errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
- exhaustive # check exhaustiveness of enum switch statements
- exportloopref # checks for pointers to enclosing loop variables
- gci # Gci control golang package import order and make it always deterministic.
- gochecknoglobals # Checks that no globals are present in Go code
- gochecknoinits # Checks that no init functions are present in Go code
- gocognit # Computes and checks the cognitive complexity of functions
- goconst # Finds repeated strings that could be replaced by a constant
- gocritic # The most opinionated Go source code linter
- godox # Tool for detection of FIXME, TODO and other comment keywords
- goerr113 # Golang linter to check the errors handling expressions
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
- gofumpt # Gofumpt checks whether code was gofumpt-ed.
- goheader # Checks is file header matches to pattern
- goimports # Goimports does everything that gofmt does. Additionally it checks unused imports
- golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
- gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations.
- goprintffuncname # Checks that printf-like functions are named with `f` at the end
- gosec # Inspects source code for security problems
- gosimple # Linter for Go source code that specializes in simplifying a code
- govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
- ineffassign # Detects when assignments to existing variables are not used
- misspell # Finds commonly misspelled English words in comments
- nakedret # Finds naked returns in functions greater than a specified function length
- noctx # noctx finds sending http request without context.Context
- scopelint # Scopelint checks for unpinned variables in go programs
- staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
- structcheck # Finds unused struct fields
- stylecheck # Stylecheck is a replacement for golint
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
- unconvert # Remove unnecessary type conversions
- unparam # Reports unused function parameters
- unused # Checks Go code for unused constants, variables, functions and types
- varcheck # Finds unused global variables and constants
- whitespace # Tool for detection of leading and trailing whitespace
disable:
- funlen # Tool for detection of long functions
- gocyclo # Computes and checks the cyclomatic complexity of functions
- godot # Check if comments end in a period
- gomnd # An analyzer to detect magic numbers.
- lll # Reports long lines
- maligned # Tool to detect Go structs that would take less memory if their fields were sorted
- nestif # Reports deeply nested if statements
- nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity
- nolintlint # Reports ill-formed or insufficient nolint directives
- prealloc # Finds slice declarations that could potentially be preallocated
- rowserrcheck # checks whether Err of rows is checked successfully
- sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed.
- testpackage # linter that makes you use a separate _test package
- wsl # Whitespace Linter - Forces you to use empty lines!
issues:
exclude-use-default: false
exclude-rules:
# Allow complex tests, better to be self contained
- path: _test\.go
linters:
- gocognit
# Allow complex main function in examples
- path: examples
text: "of func `main` is high"
linters:
- gocognit
run:
skip-dirs-use-default: false

34
vendor/github.com/pion/rtp/AUTHORS.txt generated vendored Normal file
View File

@@ -0,0 +1,34 @@
# Thank you to everyone that made Pion possible. If you are interested in contributing
# we would love to have you https://github.com/pion/webrtc/wiki/Contributing
#
# This file is auto generated, using git to list all individuals contributors.
# see `.github/generate-authors.sh` for the scripting
adwpc <adwpc@hotmail.com>
aler9 <46489434+aler9@users.noreply.github.com>
Antoine Baché <antoine.bache@epitech.eu>
Antoine Baché <antoine@tenten.app>
Atsushi Watanabe <atsushi.w@ieee.org>
baiyufei <baiyufei@outlook.com>
Bao Nguyen <bao@n4n.dev>
boks1971 <raja.gobi@tutanota.com>
debiandebiandebian <debiandebiandebiandebian@gmail.com>
ffmiyo <leffmiyo@gmail.com>
Guilherme <gqgs@protonmail.com>
Haiyang Wang <ocean2811@outlook.com>
Hugo Arregui <hugo@decentraland.org>
John Bradley <jrb@turrettech.com>
Juliusz Chroboczek <jch@irif.fr>
Kazuyuki Honda <hakobera@gmail.com>
Luke Curley <kixelated@gmail.com>
lxb <xiangbing.li@uama.com.cn>
Michael MacDonald <github@macdonald.cx>
Michael MacDonald <mike.macdonald@savantsystems.com>
Michael Uti <utimichael9@gmail.com>
Raphael Derosso Pereira <raphaelpereira@gmail.com>
Rob Lofthouse <ri.lofthouse@gmail.com>
Robin Raymond <robin@goheadroom.com>
Sean DuBois <seaduboi@amazon.com>
Sean DuBois <sean@siobud.com>
Simone Gotti <simone.gotti@gmail.com>
Tarrence van As <tarrence13@gmail.com>
Woodrow Douglass <wdouglass@carnegierobotics.com>

21
vendor/github.com/pion/rtp/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

34
vendor/github.com/pion/rtp/README.md generated vendored Normal file
View File

@@ -0,0 +1,34 @@
<h1 align="center">
<br>
Pion RTP
<br>
</h1>
<h4 align="center">A Go implementation of RTP</h4>
<p align="center">
<a href="https://pion.ly"><img src="https://img.shields.io/badge/pion-rtp-gray.svg?longCache=true&colorB=brightgreen" alt="Pion RTP"></a>
<a href="https://sourcegraph.com/github.com/pion/rtp?badge"><img src="https://sourcegraph.com/github.com/pion/rtp/-/badge.svg" alt="Sourcegraph Widget"></a>
<a href="https://pion.ly/slack"><img src="https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen" alt="Slack Widget"></a>
<br>
<a href="https://travis-ci.org/pion/rtp"><img src="https://travis-ci.org/pion/rtp.svg?branch=master" alt="Build Status"></a>
<a href="https://pkg.go.dev/github.com/pion/rtp"><img src="https://godoc.org/github.com/pion/rtp?status.svg" alt="GoDoc"></a>
<a href="https://codecov.io/gh/pion/rtp"><img src="https://codecov.io/gh/pion/rtp/branch/master/graph/badge.svg" alt="Coverage Status"></a>
<a href="https://goreportcard.com/report/github.com/pion/rtp"><img src="https://goreportcard.com/badge/github.com/pion/rtp" alt="Go Report Card"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
</p>
<br>
### Roadmap
The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones.
### Community
Pion has an active community on the [Golang Slack](https://invite.slack.golangbridge.org/). Sign up and join the **#pion** channel for discussions and support. You can also use [Pion mailing list](https://groups.google.com/forum/#!forum/pion).
We are always looking to support **your projects**. Please reach out if you have something to build!
If you need commercial support or don't want to use public methods you can contact us at [team@pion.ly](mailto:team@pion.ly)
### Contributing
Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contributing)** to join the group of amazing people making this project possible:
### License
MIT License - see [LICENSE](LICENSE) for full text

78
vendor/github.com/pion/rtp/abssendtimeextension.go generated vendored Normal file
View File

@@ -0,0 +1,78 @@
package rtp
import (
"time"
)
const (
absSendTimeExtensionSize = 3
)
// AbsSendTimeExtension is a extension payload format in
// http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
type AbsSendTimeExtension struct {
Timestamp uint64
}
// Marshal serializes the members to buffer.
func (t *AbsSendTimeExtension) Marshal() ([]byte, error) {
return []byte{
byte(t.Timestamp & 0xFF0000 >> 16),
byte(t.Timestamp & 0xFF00 >> 8),
byte(t.Timestamp & 0xFF),
}, nil
}
// Unmarshal parses the passed byte slice and stores the result in the members.
func (t *AbsSendTimeExtension) Unmarshal(rawData []byte) error {
if len(rawData) < absSendTimeExtensionSize {
return errTooSmall
}
t.Timestamp = uint64(rawData[0])<<16 | uint64(rawData[1])<<8 | uint64(rawData[2])
return nil
}
// Estimate absolute send time according to the receive time.
// Note that if the transmission delay is larger than 64 seconds, estimated time will be wrong.
func (t *AbsSendTimeExtension) Estimate(receive time.Time) time.Time {
receiveNTP := toNtpTime(receive)
ntp := receiveNTP&0xFFFFFFC000000000 | (t.Timestamp&0xFFFFFF)<<14
if receiveNTP < ntp {
// Receive time must be always later than send time
ntp -= 0x1000000 << 14
}
return toTime(ntp)
}
// NewAbsSendTimeExtension makes new AbsSendTimeExtension from time.Time.
func NewAbsSendTimeExtension(sendTime time.Time) *AbsSendTimeExtension {
return &AbsSendTimeExtension{
Timestamp: toNtpTime(sendTime) >> 14,
}
}
func toNtpTime(t time.Time) uint64 {
var s uint64
var f uint64
u := uint64(t.UnixNano())
s = u / 1e9
s += 0x83AA7E80 // offset in seconds between unix epoch and ntp epoch
f = u % 1e9
f <<= 32
f /= 1e9
s <<= 32
return s | f
}
func toTime(t uint64) time.Time {
s := t >> 32
f := t & 0xFFFFFFFF
f *= 1e9
f >>= 32
s -= 0x83AA7E80
u := s*1e9 + f
return time.Unix(0, int64(u))
}

60
vendor/github.com/pion/rtp/audiolevelextension.go generated vendored Normal file
View File

@@ -0,0 +1,60 @@
package rtp
import (
"errors"
)
const (
// audioLevelExtensionSize One byte header size
audioLevelExtensionSize = 1
)
var errAudioLevelOverflow = errors.New("audio level overflow")
// AudioLevelExtension is a extension payload format described in
// https://tools.ietf.org/html/rfc6464
//
// Implementation based on:
// https://chromium.googlesource.com/external/webrtc/+/e2a017725570ead5946a4ca8235af27470ca0df9/webrtc/modules/rtp_rtcp/source/rtp_header_extensions.cc#49
//
// One byte format:
// 0 1
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | len=0 |V| level |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Two byte format:
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | len=1 |V| level | 0 (pad) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type AudioLevelExtension struct {
Level uint8
Voice bool
}
// Marshal serializes the members to buffer
func (a *AudioLevelExtension) Marshal() ([]byte, error) {
if a.Level > 127 {
return nil, errAudioLevelOverflow
}
voice := uint8(0x00)
if a.Voice {
voice = 0x80
}
buf := make([]byte, audioLevelExtensionSize)
buf[0] = voice | a.Level
return buf, nil
}
// Unmarshal parses the passed byte slice and stores the result in the members
func (a *AudioLevelExtension) Unmarshal(rawData []byte) error {
if len(rawData) < audioLevelExtensionSize {
return errTooSmall
}
a.Level = rawData[0] & 0x7F
a.Voice = rawData[0]&0x80 != 0
return nil
}

20
vendor/github.com/pion/rtp/codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,20 @@
#
# DO NOT EDIT THIS FILE
#
# It is automatically copied from https://github.com/pion/.goassets repository.
#
coverage:
status:
project:
default:
# Allow decreasing 2% of total coverage to avoid noise.
threshold: 2%
patch:
default:
target: 70%
only_pulls: true
ignore:
- "examples/*"
- "examples/**/*"

2
vendor/github.com/pion/rtp/codecs/codecs.go generated vendored Normal file
View File

@@ -0,0 +1,2 @@
// Package codecs implements codec specific RTP payloader/depayloaders
package codecs

26
vendor/github.com/pion/rtp/codecs/common.go generated vendored Normal file
View File

@@ -0,0 +1,26 @@
package codecs
func min(a, b int) int {
if a < b {
return a
}
return b
}
// audioDepacketizer is a mixin for audio codec depacketizers
type audioDepacketizer struct{}
func (d *audioDepacketizer) IsPartitionTail(marker bool, payload []byte) bool {
return true
}
func (d *audioDepacketizer) IsPartitionHead(payload []byte) bool {
return true
}
// videoDepacketizer is a mixin for video codec depacketizers
type videoDepacketizer struct{}
func (d *videoDepacketizer) IsPartitionTail(marker bool, payload []byte) bool {
return marker
}

11
vendor/github.com/pion/rtp/codecs/error.go generated vendored Normal file
View File

@@ -0,0 +1,11 @@
package codecs
import "errors"
var (
errShortPacket = errors.New("packet is not large enough")
errNilPacket = errors.New("invalid nil packet")
errTooManyPDiff = errors.New("too many PDiff")
errTooManySpatialLayers = errors.New("too many spatial layers")
errUnhandledNALUType = errors.New("NALU Type is unhandled")
)

22
vendor/github.com/pion/rtp/codecs/g711_packet.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
package codecs
// G711Payloader payloads G711 packets
type G711Payloader struct{}
// Payload fragments an G711 packet across one or more byte arrays
func (p *G711Payloader) Payload(mtu uint16, payload []byte) [][]byte {
var out [][]byte
if payload == nil || mtu <= 0 {
return out
}
for len(payload) > int(mtu) {
o := make([]byte, mtu)
copy(o, payload[:mtu])
payload = payload[mtu:]
out = append(out, o)
}
o := make([]byte, len(payload))
copy(o, payload)
return append(out, o)
}

22
vendor/github.com/pion/rtp/codecs/g722_packet.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
package codecs
// G722Payloader payloads G722 packets
type G722Payloader struct{}
// Payload fragments an G722 packet across one or more byte arrays
func (p *G722Payloader) Payload(mtu uint16, payload []byte) [][]byte {
var out [][]byte
if payload == nil || mtu == 0 {
return out
}
for len(payload) > int(mtu) {
o := make([]byte, mtu)
copy(o, payload[:mtu])
payload = payload[mtu:]
out = append(out, o)
}
o := make([]byte, len(payload))
copy(o, payload)
return append(out, o)
}

285
vendor/github.com/pion/rtp/codecs/h264_packet.go generated vendored Normal file
View File

@@ -0,0 +1,285 @@
package codecs
import (
"encoding/binary"
"fmt"
)
// H264Payloader payloads H264 packets
type H264Payloader struct {
spsNalu, ppsNalu []byte
}
const (
stapaNALUType = 24
fuaNALUType = 28
fubNALUType = 29
spsNALUType = 7
ppsNALUType = 8
audNALUType = 9
fillerNALUType = 12
fuaHeaderSize = 2
stapaHeaderSize = 1
stapaNALULengthSize = 2
naluTypeBitmask = 0x1F
naluRefIdcBitmask = 0x60
fuStartBitmask = 0x80
fuEndBitmask = 0x40
outputStapAHeader = 0x78
)
func annexbNALUStartCode() []byte { return []byte{0x00, 0x00, 0x00, 0x01} }
func emitNalus(nals []byte, emit func([]byte)) {
nextInd := func(nalu []byte, start int) (indStart int, indLen int) {
zeroCount := 0
for i, b := range nalu[start:] {
if b == 0 {
zeroCount++
continue
} else if b == 1 {
if zeroCount >= 2 {
return start + i - zeroCount, zeroCount + 1
}
}
zeroCount = 0
}
return -1, -1
}
nextIndStart, nextIndLen := nextInd(nals, 0)
if nextIndStart == -1 {
emit(nals)
} else {
for nextIndStart != -1 {
prevStart := nextIndStart + nextIndLen
nextIndStart, nextIndLen = nextInd(nals, prevStart)
if nextIndStart != -1 {
emit(nals[prevStart:nextIndStart])
} else {
// Emit until end of stream, no end indicator found
emit(nals[prevStart:])
}
}
}
}
// Payload fragments a H264 packet across one or more byte arrays
func (p *H264Payloader) Payload(mtu uint16, payload []byte) [][]byte {
var payloads [][]byte
if len(payload) == 0 {
return payloads
}
emitNalus(payload, func(nalu []byte) {
if len(nalu) == 0 {
return
}
naluType := nalu[0] & naluTypeBitmask
naluRefIdc := nalu[0] & naluRefIdcBitmask
switch {
case naluType == audNALUType || naluType == fillerNALUType:
return
case naluType == spsNALUType:
p.spsNalu = nalu
return
case naluType == ppsNALUType:
p.ppsNalu = nalu
return
case p.spsNalu != nil && p.ppsNalu != nil:
// Pack current NALU with SPS and PPS as STAP-A
spsLen := make([]byte, 2)
binary.BigEndian.PutUint16(spsLen, uint16(len(p.spsNalu)))
ppsLen := make([]byte, 2)
binary.BigEndian.PutUint16(ppsLen, uint16(len(p.ppsNalu)))
stapANalu := []byte{outputStapAHeader}
stapANalu = append(stapANalu, spsLen...)
stapANalu = append(stapANalu, p.spsNalu...)
stapANalu = append(stapANalu, ppsLen...)
stapANalu = append(stapANalu, p.ppsNalu...)
if len(stapANalu) <= int(mtu) {
out := make([]byte, len(stapANalu))
copy(out, stapANalu)
payloads = append(payloads, out)
}
p.spsNalu = nil
p.ppsNalu = nil
}
// Single NALU
if len(nalu) <= int(mtu) {
out := make([]byte, len(nalu))
copy(out, nalu)
payloads = append(payloads, out)
return
}
// FU-A
maxFragmentSize := int(mtu) - fuaHeaderSize
// The FU payload consists of fragments of the payload of the fragmented
// NAL unit so that if the fragmentation unit payloads of consecutive
// FUs are sequentially concatenated, the payload of the fragmented NAL
// unit can be reconstructed. The NAL unit type octet of the fragmented
// NAL unit is not included as such in the fragmentation unit payload,
// but rather the information of the NAL unit type octet of the
// fragmented NAL unit is conveyed in the F and NRI fields of the FU
// indicator octet of the fragmentation unit and in the type field of
// the FU header. An FU payload MAY have any number of octets and MAY
// be empty.
naluData := nalu
// According to the RFC, the first octet is skipped due to redundant information
naluDataIndex := 1
naluDataLength := len(nalu) - naluDataIndex
naluDataRemaining := naluDataLength
if min(maxFragmentSize, naluDataRemaining) <= 0 {
return
}
for naluDataRemaining > 0 {
currentFragmentSize := min(maxFragmentSize, naluDataRemaining)
out := make([]byte, fuaHeaderSize+currentFragmentSize)
// +---------------+
// |0|1|2|3|4|5|6|7|
// +-+-+-+-+-+-+-+-+
// |F|NRI| Type |
// +---------------+
out[0] = fuaNALUType
out[0] |= naluRefIdc
// +---------------+
// |0|1|2|3|4|5|6|7|
// +-+-+-+-+-+-+-+-+
// |S|E|R| Type |
// +---------------+
out[1] = naluType
if naluDataRemaining == naluDataLength {
// Set start bit
out[1] |= 1 << 7
} else if naluDataRemaining-currentFragmentSize == 0 {
// Set end bit
out[1] |= 1 << 6
}
copy(out[fuaHeaderSize:], naluData[naluDataIndex:naluDataIndex+currentFragmentSize])
payloads = append(payloads, out)
naluDataRemaining -= currentFragmentSize
naluDataIndex += currentFragmentSize
}
})
return payloads
}
// H264Packet represents the H264 header that is stored in the payload of an RTP Packet
type H264Packet struct {
IsAVC bool
fuaBuffer []byte
videoDepacketizer
}
func (p *H264Packet) doPackaging(nalu []byte) []byte {
if p.IsAVC {
naluLength := make([]byte, 4)
binary.BigEndian.PutUint32(naluLength, uint32(len(nalu)))
return append(naluLength, nalu...)
}
return append(annexbNALUStartCode(), nalu...)
}
// IsDetectedFinalPacketInSequence returns true of the packet passed in has the
// marker bit set indicated the end of a packet sequence
func (p *H264Packet) IsDetectedFinalPacketInSequence(rtpPacketMarketBit bool) bool {
return rtpPacketMarketBit
}
// Unmarshal parses the passed byte slice and stores the result in the H264Packet this method is called upon
func (p *H264Packet) Unmarshal(payload []byte) ([]byte, error) {
if payload == nil {
return nil, errNilPacket
} else if len(payload) <= 2 {
return nil, fmt.Errorf("%w: %d <= 2", errShortPacket, len(payload))
}
// NALU Types
// https://tools.ietf.org/html/rfc6184#section-5.4
naluType := payload[0] & naluTypeBitmask
switch {
case naluType > 0 && naluType < 24:
return p.doPackaging(payload), nil
case naluType == stapaNALUType:
currOffset := int(stapaHeaderSize)
result := []byte{}
for currOffset < len(payload) {
naluSize := int(binary.BigEndian.Uint16(payload[currOffset:]))
currOffset += stapaNALULengthSize
if len(payload) < currOffset+naluSize {
return nil, fmt.Errorf("%w STAP-A declared size(%d) is larger than buffer(%d)", errShortPacket, naluSize, len(payload)-currOffset)
}
result = append(result, p.doPackaging(payload[currOffset:currOffset+naluSize])...)
currOffset += naluSize
}
return result, nil
case naluType == fuaNALUType:
if len(payload) < fuaHeaderSize {
return nil, errShortPacket
}
if p.fuaBuffer == nil {
p.fuaBuffer = []byte{}
}
p.fuaBuffer = append(p.fuaBuffer, payload[fuaHeaderSize:]...)
if payload[1]&fuEndBitmask != 0 {
naluRefIdc := payload[0] & naluRefIdcBitmask
fragmentedNaluType := payload[1] & naluTypeBitmask
nalu := append([]byte{}, naluRefIdc|fragmentedNaluType)
nalu = append(nalu, p.fuaBuffer...)
p.fuaBuffer = nil
return p.doPackaging(nalu), nil
}
return []byte{}, nil
}
return nil, fmt.Errorf("%w: %d", errUnhandledNALUType, naluType)
}
// H264PartitionHeadChecker is obsolete
type H264PartitionHeadChecker struct{}
// IsPartitionHead checks if this is the head of a packetized nalu stream.
func (*H264Packet) IsPartitionHead(payload []byte) bool {
if len(payload) < 2 {
return false
}
if payload[0]&naluTypeBitmask == fuaNALUType ||
payload[0]&naluTypeBitmask == fubNALUType {
return payload[1]&fuStartBitmask != 0
}
return true
}

803
vendor/github.com/pion/rtp/codecs/h265_packet.go generated vendored Normal file
View File

@@ -0,0 +1,803 @@
package codecs
import (
"errors"
"fmt"
)
//
// Errors
//
var (
errH265CorruptedPacket = errors.New("corrupted h265 packet")
errInvalidH265PacketType = errors.New("invalid h265 packet type")
)
//
// Network Abstraction Unit Header implementation
//
const (
// sizeof(uint16)
h265NaluHeaderSize = 2
// https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
h265NaluAggregationPacketType = 48
// https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3
h265NaluFragmentationUnitType = 49
// https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.4
h265NaluPACIPacketType = 50
)
// H265NALUHeader is a H265 NAL Unit Header
// https://datatracker.ietf.org/doc/html/rfc7798#section-1.1.4
// +---------------+---------------+
// |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |F| Type | LayerID | TID |
// +-------------+-----------------+
type H265NALUHeader uint16
func newH265NALUHeader(highByte, lowByte uint8) H265NALUHeader {
return H265NALUHeader((uint16(highByte) << 8) | uint16(lowByte))
}
// F is the forbidden bit, should always be 0.
func (h H265NALUHeader) F() bool {
return (uint16(h) >> 15) != 0
}
// Type of NAL Unit.
func (h H265NALUHeader) Type() uint8 {
// 01111110 00000000
const mask = 0b01111110 << 8
return uint8((uint16(h) & mask) >> (8 + 1))
}
// IsTypeVCLUnit returns whether or not the NAL Unit type is a VCL NAL unit.
func (h H265NALUHeader) IsTypeVCLUnit() bool {
// Type is coded on 6 bits
const msbMask = 0b00100000
return (h.Type() & msbMask) == 0
}
// LayerID should always be 0 in non-3D HEVC context.
func (h H265NALUHeader) LayerID() uint8 {
// 00000001 11111000
const mask = (0b00000001 << 8) | 0b11111000
return uint8((uint16(h) & mask) >> 3)
}
// TID is the temporal identifier of the NAL unit +1.
func (h H265NALUHeader) TID() uint8 {
const mask = 0b00000111
return uint8(uint16(h) & mask)
}
// IsAggregationPacket returns whether or not the packet is an Aggregation packet.
func (h H265NALUHeader) IsAggregationPacket() bool {
return h.Type() == h265NaluAggregationPacketType
}
// IsFragmentationUnit returns whether or not the packet is a Fragmentation Unit packet.
func (h H265NALUHeader) IsFragmentationUnit() bool {
return h.Type() == h265NaluFragmentationUnitType
}
// IsPACIPacket returns whether or not the packet is a PACI packet.
func (h H265NALUHeader) IsPACIPacket() bool {
return h.Type() == h265NaluPACIPacketType
}
//
// Single NAL Unit Packet implementation
//
// H265SingleNALUnitPacket represents a NALU packet, containing exactly one NAL unit.
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | PayloadHdr | DONL (conditional) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// | NAL unit payload data |
// | |
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | :...OPTIONAL RTP padding |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.1
type H265SingleNALUnitPacket struct {
// payloadHeader is the header of the H265 packet.
payloadHeader H265NALUHeader
// donl is a 16-bit field, that may or may not be present.
donl *uint16
// payload of the fragmentation unit.
payload []byte
mightNeedDONL bool
}
// WithDONL can be called to specify whether or not DONL might be parsed.
// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
func (p *H265SingleNALUnitPacket) WithDONL(value bool) {
p.mightNeedDONL = value
}
// Unmarshal parses the passed byte slice and stores the result in the H265SingleNALUnitPacket this method is called upon.
func (p *H265SingleNALUnitPacket) Unmarshal(payload []byte) ([]byte, error) {
// sizeof(headers)
const totalHeaderSize = h265NaluHeaderSize
if payload == nil {
return nil, errNilPacket
} else if len(payload) <= totalHeaderSize {
return nil, fmt.Errorf("%w: %d <= %v", errShortPacket, len(payload), totalHeaderSize)
}
payloadHeader := newH265NALUHeader(payload[0], payload[1])
if payloadHeader.F() {
return nil, errH265CorruptedPacket
}
if payloadHeader.IsFragmentationUnit() || payloadHeader.IsPACIPacket() || payloadHeader.IsAggregationPacket() {
return nil, errInvalidH265PacketType
}
payload = payload[2:]
if p.mightNeedDONL {
// sizeof(uint16)
if len(payload) <= 2 {
return nil, errShortPacket
}
donl := (uint16(payload[0]) << 8) | uint16(payload[1])
p.donl = &donl
payload = payload[2:]
}
p.payloadHeader = payloadHeader
p.payload = payload
return nil, nil
}
// PayloadHeader returns the NALU header of the packet.
func (p *H265SingleNALUnitPacket) PayloadHeader() H265NALUHeader {
return p.payloadHeader
}
// DONL returns the DONL of the packet.
func (p *H265SingleNALUnitPacket) DONL() *uint16 {
return p.donl
}
// Payload returns the Fragmentation Unit packet payload.
func (p *H265SingleNALUnitPacket) Payload() []byte {
return p.payload
}
func (p *H265SingleNALUnitPacket) isH265Packet() {}
//
// Aggregation Packets implementation
//
// H265AggregationUnitFirst represent the First Aggregation Unit in an AP.
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : DONL (conditional) | NALU size |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | NALU size | |
// +-+-+-+-+-+-+-+-+ NAL unit |
// | |
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | :
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
type H265AggregationUnitFirst struct {
donl *uint16
nalUnitSize uint16
nalUnit []byte
}
// DONL field, when present, specifies the value of the 16 least
// significant bits of the decoding order number of the aggregated NAL
// unit.
func (u H265AggregationUnitFirst) DONL() *uint16 {
return u.donl
}
// NALUSize represents the size, in bytes, of the NalUnit.
func (u H265AggregationUnitFirst) NALUSize() uint16 {
return u.nalUnitSize
}
// NalUnit payload.
func (u H265AggregationUnitFirst) NalUnit() []byte {
return u.nalUnit
}
// H265AggregationUnit represent the an Aggregation Unit in an AP, which is not the first one.
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : DOND (cond) | NALU size |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// | NAL unit |
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | :
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
type H265AggregationUnit struct {
dond *uint8
nalUnitSize uint16
nalUnit []byte
}
// DOND field plus 1 specifies the difference between
// the decoding order number values of the current aggregated NAL unit
// and the preceding aggregated NAL unit in the same AP.
func (u H265AggregationUnit) DOND() *uint8 {
return u.dond
}
// NALUSize represents the size, in bytes, of the NalUnit.
func (u H265AggregationUnit) NALUSize() uint16 {
return u.nalUnitSize
}
// NalUnit payload.
func (u H265AggregationUnit) NalUnit() []byte {
return u.nalUnit
}
// H265AggregationPacket represents an Aggregation packet.
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | PayloadHdr (Type=48) | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
// | |
// | two or more aggregation units |
// | |
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | :...OPTIONAL RTP padding |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2
type H265AggregationPacket struct {
firstUnit *H265AggregationUnitFirst
otherUnits []H265AggregationUnit
mightNeedDONL bool
}
// WithDONL can be called to specify whether or not DONL might be parsed.
// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
func (p *H265AggregationPacket) WithDONL(value bool) {
p.mightNeedDONL = value
}
// Unmarshal parses the passed byte slice and stores the result in the H265AggregationPacket this method is called upon.
func (p *H265AggregationPacket) Unmarshal(payload []byte) ([]byte, error) {
// sizeof(headers)
const totalHeaderSize = h265NaluHeaderSize
if payload == nil {
return nil, errNilPacket
} else if len(payload) <= totalHeaderSize {
return nil, fmt.Errorf("%w: %d <= %v", errShortPacket, len(payload), totalHeaderSize)
}
payloadHeader := newH265NALUHeader(payload[0], payload[1])
if payloadHeader.F() {
return nil, errH265CorruptedPacket
}
if !payloadHeader.IsAggregationPacket() {
return nil, errInvalidH265PacketType
}
// First parse the first aggregation unit
payload = payload[2:]
firstUnit := &H265AggregationUnitFirst{}
if p.mightNeedDONL {
if len(payload) < 2 {
return nil, errShortPacket
}
donl := (uint16(payload[0]) << 8) | uint16(payload[1])
firstUnit.donl = &donl
payload = payload[2:]
}
if len(payload) < 2 {
return nil, errShortPacket
}
firstUnit.nalUnitSize = (uint16(payload[0]) << 8) | uint16(payload[1])
payload = payload[2:]
if len(payload) < int(firstUnit.nalUnitSize) {
return nil, errShortPacket
}
firstUnit.nalUnit = payload[:firstUnit.nalUnitSize]
payload = payload[firstUnit.nalUnitSize:]
// Parse remaining Aggregation Units
var units []H265AggregationUnit
for {
unit := H265AggregationUnit{}
if p.mightNeedDONL {
if len(payload) < 1 {
break
}
dond := payload[0]
unit.dond = &dond
payload = payload[1:]
}
if len(payload) < 2 {
break
}
unit.nalUnitSize = (uint16(payload[0]) << 8) | uint16(payload[1])
payload = payload[2:]
if len(payload) < int(unit.nalUnitSize) {
break
}
unit.nalUnit = payload[:unit.nalUnitSize]
payload = payload[unit.nalUnitSize:]
units = append(units, unit)
}
// There need to be **at least** two Aggregation Units (first + another one)
if len(units) == 0 {
return nil, errShortPacket
}
p.firstUnit = firstUnit
p.otherUnits = units
return nil, nil
}
// FirstUnit returns the first Aggregated Unit of the packet.
func (p *H265AggregationPacket) FirstUnit() *H265AggregationUnitFirst {
return p.firstUnit
}
// OtherUnits returns the all the other Aggregated Unit of the packet (excluding the first one).
func (p *H265AggregationPacket) OtherUnits() []H265AggregationUnit {
return p.otherUnits
}
func (p *H265AggregationPacket) isH265Packet() {}
//
// Fragmentation Unit implementation
//
const (
// sizeof(uint8)
h265FragmentationUnitHeaderSize = 1
)
// H265FragmentationUnitHeader is a H265 FU Header
// +---------------+
// |0|1|2|3|4|5|6|7|
// +-+-+-+-+-+-+-+-+
// |S|E| FuType |
// +---------------+
type H265FragmentationUnitHeader uint8
// S represents the start of a fragmented NAL unit.
func (h H265FragmentationUnitHeader) S() bool {
const mask = 0b10000000
return ((h & mask) >> 7) != 0
}
// E represents the end of a fragmented NAL unit.
func (h H265FragmentationUnitHeader) E() bool {
const mask = 0b01000000
return ((h & mask) >> 6) != 0
}
// FuType MUST be equal to the field Type of the fragmented NAL unit.
func (h H265FragmentationUnitHeader) FuType() uint8 {
const mask = 0b00111111
return uint8(h) & mask
}
// H265FragmentationUnitPacket represents a single Fragmentation Unit packet.
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | PayloadHdr (Type=49) | FU header | DONL (cond) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
// | DONL (cond) | |
// |-+-+-+-+-+-+-+-+ |
// | FU payload |
// | |
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | :...OPTIONAL RTP padding |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.3
type H265FragmentationUnitPacket struct {
// payloadHeader is the header of the H265 packet.
payloadHeader H265NALUHeader
// fuHeader is the header of the fragmentation unit
fuHeader H265FragmentationUnitHeader
// donl is a 16-bit field, that may or may not be present.
donl *uint16
// payload of the fragmentation unit.
payload []byte
mightNeedDONL bool
}
// WithDONL can be called to specify whether or not DONL might be parsed.
// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
func (p *H265FragmentationUnitPacket) WithDONL(value bool) {
p.mightNeedDONL = value
}
// Unmarshal parses the passed byte slice and stores the result in the H265FragmentationUnitPacket this method is called upon.
func (p *H265FragmentationUnitPacket) Unmarshal(payload []byte) ([]byte, error) {
// sizeof(headers)
const totalHeaderSize = h265NaluHeaderSize + h265FragmentationUnitHeaderSize
if payload == nil {
return nil, errNilPacket
} else if len(payload) <= totalHeaderSize {
return nil, fmt.Errorf("%w: %d <= %v", errShortPacket, len(payload), totalHeaderSize)
}
payloadHeader := newH265NALUHeader(payload[0], payload[1])
if payloadHeader.F() {
return nil, errH265CorruptedPacket
}
if !payloadHeader.IsFragmentationUnit() {
return nil, errInvalidH265PacketType
}
fuHeader := H265FragmentationUnitHeader(payload[2])
payload = payload[3:]
if fuHeader.S() && p.mightNeedDONL {
// sizeof(uint16)
if len(payload) <= 2 {
return nil, errShortPacket
}
donl := (uint16(payload[0]) << 8) | uint16(payload[1])
p.donl = &donl
payload = payload[2:]
}
p.payloadHeader = payloadHeader
p.fuHeader = fuHeader
p.payload = payload
return nil, nil
}
// PayloadHeader returns the NALU header of the packet.
func (p *H265FragmentationUnitPacket) PayloadHeader() H265NALUHeader {
return p.payloadHeader
}
// FuHeader returns the Fragmentation Unit Header of the packet.
func (p *H265FragmentationUnitPacket) FuHeader() H265FragmentationUnitHeader {
return p.fuHeader
}
// DONL returns the DONL of the packet.
func (p *H265FragmentationUnitPacket) DONL() *uint16 {
return p.donl
}
// Payload returns the Fragmentation Unit packet payload.
func (p *H265FragmentationUnitPacket) Payload() []byte {
return p.payload
}
func (p *H265FragmentationUnitPacket) isH265Packet() {}
//
// PACI implementation
//
// H265PACIPacket represents a single H265 PACI packet.
//
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | PayloadHdr (Type=50) |A| cType | PHSsize |F0..2|Y|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Payload Header Extension Structure (PHES) |
// |=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=|
// | |
// | PACI payload: NAL unit |
// | . . . |
// | |
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | :...OPTIONAL RTP padding |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.4
type H265PACIPacket struct {
// payloadHeader is the header of the H265 packet.
payloadHeader H265NALUHeader
// Field which holds value for `A`, `cType`, `PHSsize`, `F0`, `F1`, `F2` and `Y` fields.
paciHeaderFields uint16
// phes is a header extension, of byte length `PHSsize`
phes []byte
// Payload contains NAL units & optional padding
payload []byte
}
// PayloadHeader returns the NAL Unit Header.
func (p *H265PACIPacket) PayloadHeader() H265NALUHeader {
return p.payloadHeader
}
// A copies the F bit of the PACI payload NALU.
func (p *H265PACIPacket) A() bool {
const mask = 0b10000000 << 8
return (p.paciHeaderFields & mask) != 0
}
// CType copies the Type field of the PACI payload NALU.
func (p *H265PACIPacket) CType() uint8 {
const mask = 0b01111110 << 8
return uint8((p.paciHeaderFields & mask) >> (8 + 1))
}
// PHSsize indicates the size of the PHES field.
func (p *H265PACIPacket) PHSsize() uint8 {
const mask = (0b00000001 << 8) | 0b11110000
return uint8((p.paciHeaderFields & mask) >> 4)
}
// F0 indicates the presence of a Temporal Scalability support extension in the PHES.
func (p *H265PACIPacket) F0() bool {
const mask = 0b00001000
return (p.paciHeaderFields & mask) != 0
}
// F1 must be zero, reserved for future extensions.
func (p *H265PACIPacket) F1() bool {
const mask = 0b00000100
return (p.paciHeaderFields & mask) != 0
}
// F2 must be zero, reserved for future extensions.
func (p *H265PACIPacket) F2() bool {
const mask = 0b00000010
return (p.paciHeaderFields & mask) != 0
}
// Y must be zero, reserved for future extensions.
func (p *H265PACIPacket) Y() bool {
const mask = 0b00000001
return (p.paciHeaderFields & mask) != 0
}
// PHES contains header extensions. Its size is indicated by PHSsize.
func (p *H265PACIPacket) PHES() []byte {
return p.phes
}
// Payload is a single NALU or NALU-like struct, not including the first two octets (header).
func (p *H265PACIPacket) Payload() []byte {
return p.payload
}
// TSCI returns the Temporal Scalability Control Information extension, if present.
func (p *H265PACIPacket) TSCI() *H265TSCI {
if !p.F0() || p.PHSsize() < 3 {
return nil
}
tsci := H265TSCI((uint32(p.phes[0]) << 16) | (uint32(p.phes[1]) << 8) | uint32(p.phes[0]))
return &tsci
}
// Unmarshal parses the passed byte slice and stores the result in the H265PACIPacket this method is called upon.
func (p *H265PACIPacket) Unmarshal(payload []byte) ([]byte, error) {
// sizeof(headers)
const totalHeaderSize = h265NaluHeaderSize + 2
if payload == nil {
return nil, errNilPacket
} else if len(payload) <= totalHeaderSize {
return nil, fmt.Errorf("%w: %d <= %v", errShortPacket, len(payload), totalHeaderSize)
}
payloadHeader := newH265NALUHeader(payload[0], payload[1])
if payloadHeader.F() {
return nil, errH265CorruptedPacket
}
if !payloadHeader.IsPACIPacket() {
return nil, errInvalidH265PacketType
}
paciHeaderFields := (uint16(payload[2]) << 8) | uint16(payload[3])
payload = payload[4:]
p.paciHeaderFields = paciHeaderFields
headerExtensionSize := p.PHSsize()
if len(payload) < int(headerExtensionSize)+1 {
p.paciHeaderFields = 0
return nil, errShortPacket
}
p.payloadHeader = payloadHeader
if headerExtensionSize > 0 {
p.phes = payload[:headerExtensionSize]
}
payload = payload[headerExtensionSize:]
p.payload = payload
return nil, nil
}
func (p *H265PACIPacket) isH265Packet() {}
//
// Temporal Scalability Control Information
//
// H265TSCI is a Temporal Scalability Control Information header extension.
// Reference: https://datatracker.ietf.org/doc/html/rfc7798#section-4.5
type H265TSCI uint32
// TL0PICIDX see RFC7798 for more details.
func (h H265TSCI) TL0PICIDX() uint8 {
const m1 = 0xFFFF0000
const m2 = 0xFF00
return uint8((((h & m1) >> 16) & m2) >> 8)
}
// IrapPicID see RFC7798 for more details.
func (h H265TSCI) IrapPicID() uint8 {
const m1 = 0xFFFF0000
const m2 = 0x00FF
return uint8(((h & m1) >> 16) & m2)
}
// S see RFC7798 for more details.
func (h H265TSCI) S() bool {
const m1 = 0xFF00
const m2 = 0b10000000
return (uint8((h&m1)>>8) & m2) != 0
}
// E see RFC7798 for more details.
func (h H265TSCI) E() bool {
const m1 = 0xFF00
const m2 = 0b01000000
return (uint8((h&m1)>>8) & m2) != 0
}
// RES see RFC7798 for more details.
func (h H265TSCI) RES() uint8 {
const m1 = 0xFF00
const m2 = 0b00111111
return uint8((h&m1)>>8) & m2
}
//
// H265 Packet interface
//
type isH265Packet interface {
isH265Packet()
}
var (
_ isH265Packet = (*H265FragmentationUnitPacket)(nil)
_ isH265Packet = (*H265PACIPacket)(nil)
_ isH265Packet = (*H265SingleNALUnitPacket)(nil)
_ isH265Packet = (*H265AggregationPacket)(nil)
)
//
// Packet implementation
//
// H265Packet represents a H265 packet, stored in the payload of an RTP packet.
type H265Packet struct {
packet isH265Packet
mightNeedDONL bool
}
// WithDONL can be called to specify whether or not DONL might be parsed.
// DONL may need to be parsed if `sprop-max-don-diff` is greater than 0 on the RTP stream.
func (p *H265Packet) WithDONL(value bool) {
p.mightNeedDONL = value
}
// Unmarshal parses the passed byte slice and stores the result in the H265Packet this method is called upon
func (p *H265Packet) Unmarshal(payload []byte) ([]byte, error) {
if payload == nil {
return nil, errNilPacket
} else if len(payload) <= h265NaluHeaderSize {
return nil, fmt.Errorf("%w: %d <= %v", errShortPacket, len(payload), h265NaluHeaderSize)
}
payloadHeader := newH265NALUHeader(payload[0], payload[1])
if payloadHeader.F() {
return nil, errH265CorruptedPacket
}
switch {
case payloadHeader.IsPACIPacket():
decoded := &H265PACIPacket{}
if _, err := decoded.Unmarshal(payload); err != nil {
return nil, err
}
p.packet = decoded
case payloadHeader.IsFragmentationUnit():
decoded := &H265FragmentationUnitPacket{}
decoded.WithDONL(p.mightNeedDONL)
if _, err := decoded.Unmarshal(payload); err != nil {
return nil, err
}
p.packet = decoded
case payloadHeader.IsAggregationPacket():
decoded := &H265AggregationPacket{}
decoded.WithDONL(p.mightNeedDONL)
if _, err := decoded.Unmarshal(payload); err != nil {
return nil, err
}
p.packet = decoded
default:
decoded := &H265SingleNALUnitPacket{}
decoded.WithDONL(p.mightNeedDONL)
if _, err := decoded.Unmarshal(payload); err != nil {
return nil, err
}
p.packet = decoded
}
return nil, nil
}
// Packet returns the populated packet.
// Must be casted to one of:
// - *H265SingleNALUnitPacket
// - *H265FragmentationUnitPacket
// - *H265AggregationPacket
// - *H265PACIPacket
// nolint:golint
func (p *H265Packet) Packet() isH265Packet {
return p.packet
}

37
vendor/github.com/pion/rtp/codecs/opus_packet.go generated vendored Normal file
View File

@@ -0,0 +1,37 @@
package codecs
// OpusPayloader payloads Opus packets
type OpusPayloader struct{}
// Payload fragments an Opus packet across one or more byte arrays
func (p *OpusPayloader) Payload(mtu uint16, payload []byte) [][]byte {
if payload == nil {
return [][]byte{}
}
out := make([]byte, len(payload))
copy(out, payload)
return [][]byte{out}
}
// OpusPacket represents the Opus header that is stored in the payload of an RTP Packet
type OpusPacket struct {
Payload []byte
audioDepacketizer
}
// Unmarshal parses the passed byte slice and stores the result in the OpusPacket this method is called upon
func (p *OpusPacket) Unmarshal(packet []byte) ([]byte, error) {
if packet == nil {
return nil, errNilPacket
} else if len(packet) == 0 {
return nil, errShortPacket
}
p.Payload = packet
return packet, nil
}
// OpusPartitionHeadChecker is obsolete
type OpusPartitionHeadChecker struct{}

201
vendor/github.com/pion/rtp/codecs/vp8_packet.go generated vendored Normal file
View File

@@ -0,0 +1,201 @@
package codecs
// VP8Payloader payloads VP8 packets
type VP8Payloader struct {
EnablePictureID bool
pictureID uint16
}
const (
vp8HeaderSize = 1
)
// Payload fragments a VP8 packet across one or more byte arrays
func (p *VP8Payloader) Payload(mtu uint16, payload []byte) [][]byte {
/*
* https://tools.ietf.org/html/rfc7741#section-4.2
*
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+
* |X|R|N|S|R| PID | (REQUIRED)
* +-+-+-+-+-+-+-+-+
* X: |I|L|T|K| RSV | (OPTIONAL)
* +-+-+-+-+-+-+-+-+
* I: |M| PictureID | (OPTIONAL)
* +-+-+-+-+-+-+-+-+
* L: | TL0PICIDX | (OPTIONAL)
* +-+-+-+-+-+-+-+-+
* T/K: |TID|Y| KEYIDX | (OPTIONAL)
* +-+-+-+-+-+-+-+-+
* S: Start of VP8 partition. SHOULD be set to 1 when the first payload
* octet of the RTP packet is the beginning of a new VP8 partition,
* and MUST NOT be 1 otherwise. The S bit MUST be set to 1 for the
* first packet of each encoded frame.
*/
usingHeaderSize := vp8HeaderSize
if p.EnablePictureID {
switch {
case p.pictureID == 0:
case p.pictureID < 128:
usingHeaderSize = vp8HeaderSize + 2
default:
usingHeaderSize = vp8HeaderSize + 3
}
}
maxFragmentSize := int(mtu) - usingHeaderSize
payloadData := payload
payloadDataRemaining := len(payload)
payloadDataIndex := 0
var payloads [][]byte
// Make sure the fragment/payload size is correct
if min(maxFragmentSize, payloadDataRemaining) <= 0 {
return payloads
}
first := true
for payloadDataRemaining > 0 {
currentFragmentSize := min(maxFragmentSize, payloadDataRemaining)
out := make([]byte, usingHeaderSize+currentFragmentSize)
if first {
out[0] = 0x10
first = false
}
if p.EnablePictureID {
switch usingHeaderSize {
case vp8HeaderSize:
case vp8HeaderSize + 2:
out[0] |= 0x80
out[1] |= 0x80
out[2] |= uint8(p.pictureID & 0x7F)
case vp8HeaderSize + 3:
out[0] |= 0x80
out[1] |= 0x80
out[2] |= 0x80 | uint8((p.pictureID>>8)&0x7F)
out[3] |= uint8(p.pictureID & 0xFF)
}
}
copy(out[usingHeaderSize:], payloadData[payloadDataIndex:payloadDataIndex+currentFragmentSize])
payloads = append(payloads, out)
payloadDataRemaining -= currentFragmentSize
payloadDataIndex += currentFragmentSize
}
p.pictureID++
p.pictureID &= 0x7FFF
return payloads
}
// VP8Packet represents the VP8 header that is stored in the payload of an RTP Packet
type VP8Packet struct {
// Required Header
X uint8 /* extended control bits present */
N uint8 /* when set to 1 this frame can be discarded */
S uint8 /* start of VP8 partition */
PID uint8 /* partition index */
// Extended control bits
I uint8 /* 1 if PictureID is present */
L uint8 /* 1 if TL0PICIDX is present */
T uint8 /* 1 if TID is present */
K uint8 /* 1 if KEYIDX is present */
// Optional extension
PictureID uint16 /* 8 or 16 bits, picture ID */
TL0PICIDX uint8 /* 8 bits temporal level zero index */
TID uint8 /* 2 bits temporal layer index */
Y uint8 /* 1 bit layer sync bit */
KEYIDX uint8 /* 5 bits temporal key frame index */
Payload []byte
videoDepacketizer
}
// Unmarshal parses the passed byte slice and stores the result in the VP8Packet this method is called upon
func (p *VP8Packet) Unmarshal(payload []byte) ([]byte, error) {
if payload == nil {
return nil, errNilPacket
}
payloadLen := len(payload)
if payloadLen < 4 {
return nil, errShortPacket
}
payloadIndex := 0
p.X = (payload[payloadIndex] & 0x80) >> 7
p.N = (payload[payloadIndex] & 0x20) >> 5
p.S = (payload[payloadIndex] & 0x10) >> 4
p.PID = payload[payloadIndex] & 0x07
payloadIndex++
if p.X == 1 {
p.I = (payload[payloadIndex] & 0x80) >> 7
p.L = (payload[payloadIndex] & 0x40) >> 6
p.T = (payload[payloadIndex] & 0x20) >> 5
p.K = (payload[payloadIndex] & 0x10) >> 4
payloadIndex++
}
if p.I == 1 { // PID present?
if payload[payloadIndex]&0x80 > 0 { // M == 1, PID is 16bit
p.PictureID = (uint16(payload[payloadIndex]&0x7F) << 8) | uint16(payload[payloadIndex+1])
payloadIndex += 2
} else {
p.PictureID = uint16(payload[payloadIndex])
payloadIndex++
}
}
if payloadIndex >= payloadLen {
return nil, errShortPacket
}
if p.L == 1 {
p.TL0PICIDX = payload[payloadIndex]
payloadIndex++
}
if payloadIndex >= payloadLen {
return nil, errShortPacket
}
if p.T == 1 || p.K == 1 {
if p.T == 1 {
p.TID = payload[payloadIndex] >> 6
p.Y = (payload[payloadIndex] >> 5) & 0x1
}
if p.K == 1 {
p.KEYIDX = payload[payloadIndex] & 0x1F
}
payloadIndex++
}
if payloadIndex >= payloadLen {
return nil, errShortPacket
}
p.Payload = payload[payloadIndex:]
return p.Payload, nil
}
// VP8PartitionHeadChecker is obsolete
type VP8PartitionHeadChecker struct{}
// IsPartitionHead checks whether if this is a head of the VP8 partition
func (*VP8Packet) IsPartitionHead(payload []byte) bool {
if len(payload) < 1 {
return false
}
return (payload[0] & 0x10) != 0
}

388
vendor/github.com/pion/rtp/codecs/vp9_packet.go generated vendored Normal file
View File

@@ -0,0 +1,388 @@
package codecs
import (
"github.com/pion/randutil"
)
// Use global random generator to properly seed by crypto grade random.
var globalMathRandomGenerator = randutil.NewMathRandomGenerator() // nolint:gochecknoglobals
// VP9Payloader payloads VP9 packets
type VP9Payloader struct {
pictureID uint16
initialized bool
// InitialPictureIDFn is a function that returns random initial picture ID.
InitialPictureIDFn func() uint16
}
const (
vp9HeaderSize = 3 // Flexible mode 15 bit picture ID
maxSpatialLayers = 5
maxVP9RefPics = 3
)
// Payload fragments an VP9 packet across one or more byte arrays
func (p *VP9Payloader) Payload(mtu uint16, payload []byte) [][]byte {
/*
* https://www.ietf.org/id/draft-ietf-payload-vp9-13.txt
*
* 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 |
* | .. |
* +-+-+-+-+-+-+-+-+
*
* 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 |
* | .. |
* +-+-+-+-+-+-+-+-+
*/
if !p.initialized {
if p.InitialPictureIDFn == nil {
p.InitialPictureIDFn = func() uint16 {
return uint16(globalMathRandomGenerator.Intn(0x7FFF))
}
}
p.pictureID = p.InitialPictureIDFn() & 0x7FFF
p.initialized = true
}
if payload == nil {
return [][]byte{}
}
maxFragmentSize := int(mtu) - vp9HeaderSize
payloadDataRemaining := len(payload)
payloadDataIndex := 0
if min(maxFragmentSize, payloadDataRemaining) <= 0 {
return [][]byte{}
}
var payloads [][]byte
for payloadDataRemaining > 0 {
currentFragmentSize := min(maxFragmentSize, payloadDataRemaining)
out := make([]byte, vp9HeaderSize+currentFragmentSize)
out[0] = 0x90 // F=1 I=1
if payloadDataIndex == 0 {
out[0] |= 0x08 // B=1
}
if payloadDataRemaining == currentFragmentSize {
out[0] |= 0x04 // E=1
}
out[1] = byte(p.pictureID>>8) | 0x80
out[2] = byte(p.pictureID)
copy(out[vp9HeaderSize:], payload[payloadDataIndex:payloadDataIndex+currentFragmentSize])
payloads = append(payloads, out)
payloadDataRemaining -= currentFragmentSize
payloadDataIndex += currentFragmentSize
}
p.pictureID++
if p.pictureID >= 0x8000 {
p.pictureID = 0
}
return payloads
}
// VP9Packet represents the VP9 header that is stored in the payload of an RTP Packet
type VP9Packet struct {
// 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 []byte
videoDepacketizer
}
// Unmarshal parses the passed byte slice and stores the result in the VP9Packet this method is called upon
func (p *VP9Packet) Unmarshal(packet []byte) ([]byte, error) {
if packet == nil {
return nil, errNilPacket
}
if len(packet) < 1 {
return nil, errShortPacket
}
p.I = packet[0]&0x80 != 0
p.P = packet[0]&0x40 != 0
p.L = packet[0]&0x20 != 0
p.F = packet[0]&0x10 != 0
p.B = packet[0]&0x08 != 0
p.E = packet[0]&0x04 != 0
p.V = packet[0]&0x02 != 0
p.Z = packet[0]&0x01 != 0
pos := 1
var err error
if p.I {
pos, err = p.parsePictureID(packet, pos)
if err != nil {
return nil, err
}
}
if p.L {
pos, err = p.parseLayerInfo(packet, pos)
if err != nil {
return nil, err
}
}
if p.F && p.P {
pos, err = p.parseRefIndices(packet, pos)
if err != nil {
return nil, err
}
}
if p.V {
pos, err = p.parseSSData(packet, pos)
if err != nil {
return nil, err
}
}
p.Payload = packet[pos:]
return p.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 (p *VP9Packet) parsePictureID(packet []byte, pos int) (int, error) {
if len(packet) <= pos {
return pos, errShortPacket
}
p.PictureID = uint16(packet[pos] & 0x7F)
if packet[pos]&0x80 != 0 {
pos++
if len(packet) <= pos {
return pos, errShortPacket
}
p.PictureID = p.PictureID<<8 | uint16(packet[pos])
}
pos++
return pos, nil
}
func (p *VP9Packet) parseLayerInfo(packet []byte, pos int) (int, error) {
pos, err := p.parseLayerInfoCommon(packet, pos)
if err != nil {
return pos, err
}
if p.F {
return pos, nil
}
return p.parseLayerInfoNonFlexibleMode(packet, pos)
}
// Layer indices (flexible mode):
//
// +-+-+-+-+-+-+-+-+
// L: | T |U| S |D|
// +-+-+-+-+-+-+-+-+
//
func (p *VP9Packet) parseLayerInfoCommon(packet []byte, pos int) (int, error) {
if len(packet) <= pos {
return pos, errShortPacket
}
p.TID = packet[pos] >> 5
p.U = packet[pos]&0x10 != 0
p.SID = (packet[pos] >> 1) & 0x7
p.D = packet[pos]&0x01 != 0
if p.SID >= maxSpatialLayers {
return pos, errTooManySpatialLayers
}
pos++
return pos, nil
}
// Layer indices (non-flexible mode):
//
// +-+-+-+-+-+-+-+-+
// L: | T |U| S |D|
// +-+-+-+-+-+-+-+-+
// | TL0PICIDX |
// +-+-+-+-+-+-+-+-+
//
func (p *VP9Packet) parseLayerInfoNonFlexibleMode(packet []byte, pos int) (int, error) {
if len(packet) <= pos {
return pos, errShortPacket
}
p.TL0PICIDX = packet[pos]
pos++
return pos, 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 (p *VP9Packet) parseRefIndices(packet []byte, pos int) (int, error) {
for {
if len(packet) <= pos {
return pos, errShortPacket
}
p.PDiff = append(p.PDiff, packet[pos]>>1)
if packet[pos]&0x01 == 0 {
break
}
if len(p.PDiff) >= maxVP9RefPics {
return pos, errTooManyPDiff
}
pos++
}
pos++
return pos, 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 (p *VP9Packet) parseSSData(packet []byte, pos int) (int, error) {
if len(packet) <= pos {
return pos, errShortPacket
}
p.NS = packet[pos] >> 5
p.Y = packet[pos]&0x10 != 0
p.G = (packet[pos]>>1)&0x7 != 0
pos++
NS := p.NS + 1
p.NG = 0
if p.Y {
p.Width = make([]uint16, NS)
p.Height = make([]uint16, NS)
for i := 0; i < int(NS); i++ {
p.Width[i] = uint16(packet[pos])<<8 | uint16(packet[pos+1])
pos += 2
p.Height[i] = uint16(packet[pos])<<8 | uint16(packet[pos+1])
pos += 2
}
}
if p.G {
p.NG = packet[pos]
pos++
}
for i := 0; i < int(p.NG); i++ {
p.PGTID = append(p.PGTID, packet[pos]>>5)
p.PGU = append(p.PGU, packet[pos]&0x10 != 0)
R := (packet[pos] >> 2) & 0x3
pos++
p.PGPDiff = append(p.PGPDiff, []uint8{})
for j := 0; j < int(R); j++ {
p.PGPDiff[i] = append(p.PGPDiff[i], packet[pos])
pos++
}
}
return pos, nil
}
// VP9PartitionHeadChecker is obsolete
type VP9PartitionHeadChecker struct{}
// IsPartitionHead checks whether if this is a head of the VP9 partition
func (*VP9Packet) IsPartitionHead(payload []byte) bool {
if len(payload) < 1 {
return false
}
return (payload[0] & 0x08) != 0
}

13
vendor/github.com/pion/rtp/depacketizer.go generated vendored Normal file
View File

@@ -0,0 +1,13 @@
package rtp
// Depacketizer depacketizes a RTP payload, removing any RTP specific data from the payload
type Depacketizer interface {
Unmarshal(packet []byte) ([]byte, error)
// Checks if the packet is at the beginning of a partition. This
// should return false if the result could not be determined, in
// which case the caller will detect timestamp discontinuities.
IsPartitionHead(payload []byte) bool
// Checks if the packet is at the end of a partition. This should
// return false if the result could not be determined.
IsPartitionTail(marker bool, payload []byte) bool
}

21
vendor/github.com/pion/rtp/error.go generated vendored Normal file
View File

@@ -0,0 +1,21 @@
package rtp
import (
"errors"
)
var (
errHeaderSizeInsufficient = errors.New("RTP header size insufficient")
errHeaderSizeInsufficientForExtension = errors.New("RTP header size insufficient for extension")
errTooSmall = errors.New("buffer too small")
errHeaderExtensionsNotEnabled = errors.New("h.Extension not enabled")
errHeaderExtensionNotFound = errors.New("extension not found")
errRFC8285OneByteHeaderIDRange = errors.New("header extension id must be between 1 and 14 for RFC 5285 one byte extensions")
errRFC8285OneByteHeaderSize = errors.New("header extension payload must be 16bytes or less for RFC 5285 one byte extensions")
errRFC8285TwoByteHeaderIDRange = errors.New("header extension id must be between 1 and 255 for RFC 5285 two byte extensions")
errRFC8285TwoByteHeaderSize = errors.New("header extension payload must be 255bytes or less for RFC 5285 two byte extensions")
errRFC3550HeaderIDRange = errors.New("header extension id must be 0 for non-RFC 5285 extensions")
)

521
vendor/github.com/pion/rtp/packet.go generated vendored Normal file
View File

@@ -0,0 +1,521 @@
package rtp
import (
"encoding/binary"
"fmt"
"io"
)
// Extension RTP Header extension
type Extension struct {
id uint8
payload []byte
}
// Header represents an RTP packet header
type Header struct {
Version uint8
Padding bool
Extension bool
Marker bool
PayloadType uint8
SequenceNumber uint16
Timestamp uint32
SSRC uint32
CSRC []uint32
ExtensionProfile uint16
Extensions []Extension
}
// Packet represents an RTP Packet
type Packet struct {
Header
Payload []byte
}
const (
headerLength = 4
versionShift = 6
versionMask = 0x3
paddingShift = 5
paddingMask = 0x1
extensionShift = 4
extensionMask = 0x1
extensionProfileOneByte = 0xBEDE
extensionProfileTwoByte = 0x1000
extensionIDReserved = 0xF
ccMask = 0xF
markerShift = 7
markerMask = 0x1
ptMask = 0x7F
seqNumOffset = 2
seqNumLength = 2
timestampOffset = 4
timestampLength = 4
ssrcOffset = 8
ssrcLength = 4
csrcOffset = 12
csrcLength = 4
)
// String helps with debugging by printing packet information in a readable way
func (p Packet) String() string {
out := "RTP PACKET:\n"
out += fmt.Sprintf("\tVersion: %v\n", p.Version)
out += fmt.Sprintf("\tMarker: %v\n", p.Marker)
out += fmt.Sprintf("\tPayload Type: %d\n", p.PayloadType)
out += fmt.Sprintf("\tSequence Number: %d\n", p.SequenceNumber)
out += fmt.Sprintf("\tTimestamp: %d\n", p.Timestamp)
out += fmt.Sprintf("\tSSRC: %d (%x)\n", p.SSRC, p.SSRC)
out += fmt.Sprintf("\tPayload Length: %d\n", len(p.Payload))
return out
}
// Unmarshal parses the passed byte slice and stores the result in the Header.
// It returns the number of bytes read n and any error.
func (h *Header) Unmarshal(buf []byte) (n int, err error) { //nolint:gocognit
if len(buf) < headerLength {
return 0, fmt.Errorf("%w: %d < %d", errHeaderSizeInsufficient, len(buf), headerLength)
}
/*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |V=2|P|X| CC |M| PT | sequence number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | timestamp |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | synchronization source (SSRC) identifier |
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* | contributing source (CSRC) identifiers |
* | .... |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
h.Version = buf[0] >> versionShift & versionMask
h.Padding = (buf[0] >> paddingShift & paddingMask) > 0
h.Extension = (buf[0] >> extensionShift & extensionMask) > 0
nCSRC := int(buf[0] & ccMask)
if cap(h.CSRC) < nCSRC || h.CSRC == nil {
h.CSRC = make([]uint32, nCSRC)
} else {
h.CSRC = h.CSRC[:nCSRC]
}
n = csrcOffset + (nCSRC * csrcLength)
if len(buf) < n {
return n, fmt.Errorf("size %d < %d: %w", len(buf), n,
errHeaderSizeInsufficient)
}
h.Marker = (buf[1] >> markerShift & markerMask) > 0
h.PayloadType = buf[1] & ptMask
h.SequenceNumber = binary.BigEndian.Uint16(buf[seqNumOffset : seqNumOffset+seqNumLength])
h.Timestamp = binary.BigEndian.Uint32(buf[timestampOffset : timestampOffset+timestampLength])
h.SSRC = binary.BigEndian.Uint32(buf[ssrcOffset : ssrcOffset+ssrcLength])
for i := range h.CSRC {
offset := csrcOffset + (i * csrcLength)
h.CSRC[i] = binary.BigEndian.Uint32(buf[offset:])
}
if h.Extensions != nil {
h.Extensions = h.Extensions[:0]
}
if h.Extension {
if expected := n + 4; len(buf) < expected {
return n, fmt.Errorf("size %d < %d: %w",
len(buf), expected,
errHeaderSizeInsufficientForExtension,
)
}
h.ExtensionProfile = binary.BigEndian.Uint16(buf[n:])
n += 2
extensionLength := int(binary.BigEndian.Uint16(buf[n:])) * 4
n += 2
if expected := n + extensionLength; len(buf) < expected {
return n, fmt.Errorf("size %d < %d: %w",
len(buf), expected,
errHeaderSizeInsufficientForExtension,
)
}
switch h.ExtensionProfile {
// RFC 8285 RTP One Byte Header Extension
case extensionProfileOneByte:
end := n + extensionLength
for n < end {
if buf[n] == 0x00 { // padding
n++
continue
}
extid := buf[n] >> 4
len := int(buf[n]&^0xF0 + 1)
n++
if extid == extensionIDReserved {
break
}
extension := Extension{id: extid, payload: buf[n : n+len]}
h.Extensions = append(h.Extensions, extension)
n += len
}
// RFC 8285 RTP Two Byte Header Extension
case extensionProfileTwoByte:
end := n + extensionLength
for n < end {
if buf[n] == 0x00 { // padding
n++
continue
}
extid := buf[n]
n++
len := int(buf[n])
n++
extension := Extension{id: extid, payload: buf[n : n+len]}
h.Extensions = append(h.Extensions, extension)
n += len
}
default: // RFC3550 Extension
if len(buf) < n+extensionLength {
return n, fmt.Errorf("%w: %d < %d",
errHeaderSizeInsufficientForExtension, len(buf), n+extensionLength)
}
extension := Extension{id: 0, payload: buf[n : n+extensionLength]}
h.Extensions = append(h.Extensions, extension)
n += len(h.Extensions[0].payload)
}
}
return n, nil
}
// Unmarshal parses the passed byte slice and stores the result in the Packet.
func (p *Packet) Unmarshal(buf []byte) error {
n, err := p.Header.Unmarshal(buf)
if err != nil {
return err
}
end := len(buf)
if p.Header.Padding {
end -= int(buf[end-1])
}
if end < n {
return errTooSmall
}
p.Payload = buf[n:end]
return nil
}
// Marshal serializes the header into bytes.
func (h *Header) Marshal() (buf []byte, err error) {
buf = make([]byte, h.MarshalSize())
n, err := h.MarshalTo(buf)
if err != nil {
return nil, err
}
return buf[:n], nil
}
// MarshalTo serializes the header and writes to the buffer.
func (h *Header) MarshalTo(buf []byte) (n int, err error) {
/*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |V=2|P|X| CC |M| PT | sequence number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | timestamp |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | synchronization source (SSRC) identifier |
* +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
* | contributing source (CSRC) identifiers |
* | .... |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
size := h.MarshalSize()
if size > len(buf) {
return 0, io.ErrShortBuffer
}
// The first byte contains the version, padding bit, extension bit,
// and csrc size.
buf[0] = (h.Version << versionShift) | uint8(len(h.CSRC))
if h.Padding {
buf[0] |= 1 << paddingShift
}
if h.Extension {
buf[0] |= 1 << extensionShift
}
// The second byte contains the marker bit and payload type.
buf[1] = h.PayloadType
if h.Marker {
buf[1] |= 1 << markerShift
}
binary.BigEndian.PutUint16(buf[2:4], h.SequenceNumber)
binary.BigEndian.PutUint32(buf[4:8], h.Timestamp)
binary.BigEndian.PutUint32(buf[8:12], h.SSRC)
n = 12
for _, csrc := range h.CSRC {
binary.BigEndian.PutUint32(buf[n:n+4], csrc)
n += 4
}
if h.Extension {
extHeaderPos := n
binary.BigEndian.PutUint16(buf[n+0:n+2], h.ExtensionProfile)
n += 4
startExtensionsPos := n
switch h.ExtensionProfile {
// RFC 8285 RTP One Byte Header Extension
case extensionProfileOneByte:
for _, extension := range h.Extensions {
buf[n] = extension.id<<4 | (uint8(len(extension.payload)) - 1)
n++
n += copy(buf[n:], extension.payload)
}
// RFC 8285 RTP Two Byte Header Extension
case extensionProfileTwoByte:
for _, extension := range h.Extensions {
buf[n] = extension.id
n++
buf[n] = uint8(len(extension.payload))
n++
n += copy(buf[n:], extension.payload)
}
default: // RFC3550 Extension
extlen := len(h.Extensions[0].payload)
if extlen%4 != 0 {
// the payload must be in 32-bit words.
return 0, io.ErrShortBuffer
}
n += copy(buf[n:], h.Extensions[0].payload)
}
// calculate extensions size and round to 4 bytes boundaries
extSize := n - startExtensionsPos
roundedExtSize := ((extSize + 3) / 4) * 4
binary.BigEndian.PutUint16(buf[extHeaderPos+2:extHeaderPos+4], uint16(roundedExtSize/4))
// add padding to reach 4 bytes boundaries
for i := 0; i < roundedExtSize-extSize; i++ {
buf[n] = 0
n++
}
}
return n, nil
}
// MarshalSize returns the size of the header once marshaled.
func (h *Header) MarshalSize() int {
// NOTE: Be careful to match the MarshalTo() method.
size := 12 + (len(h.CSRC) * csrcLength)
if h.Extension {
extSize := 4
switch h.ExtensionProfile {
// RFC 8285 RTP One Byte Header Extension
case extensionProfileOneByte:
for _, extension := range h.Extensions {
extSize += 1 + len(extension.payload)
}
// RFC 8285 RTP Two Byte Header Extension
case extensionProfileTwoByte:
for _, extension := range h.Extensions {
extSize += 2 + len(extension.payload)
}
default:
extSize += len(h.Extensions[0].payload)
}
// extensions size must have 4 bytes boundaries
size += ((extSize + 3) / 4) * 4
}
return size
}
// SetExtension sets an RTP header extension
func (h *Header) SetExtension(id uint8, payload []byte) error { //nolint:gocognit
if h.Extension {
switch h.ExtensionProfile {
// RFC 8285 RTP One Byte Header Extension
case extensionProfileOneByte:
if id < 1 || id > 14 {
return fmt.Errorf("%w actual(%d)", errRFC8285OneByteHeaderIDRange, id)
}
if len(payload) > 16 {
return fmt.Errorf("%w actual(%d)", errRFC8285OneByteHeaderSize, len(payload))
}
// RFC 8285 RTP Two Byte Header Extension
case extensionProfileTwoByte:
if id < 1 || id > 255 {
return fmt.Errorf("%w actual(%d)", errRFC8285TwoByteHeaderIDRange, id)
}
if len(payload) > 255 {
return fmt.Errorf("%w actual(%d)", errRFC8285TwoByteHeaderSize, len(payload))
}
default: // RFC3550 Extension
if id != 0 {
return fmt.Errorf("%w actual(%d)", errRFC3550HeaderIDRange, id)
}
}
// Update existing if it exists else add new extension
for i, extension := range h.Extensions {
if extension.id == id {
h.Extensions[i].payload = payload
return nil
}
}
h.Extensions = append(h.Extensions, Extension{id: id, payload: payload})
return nil
}
// No existing header extensions
h.Extension = true
switch len := len(payload); {
case len <= 16:
h.ExtensionProfile = extensionProfileOneByte
case len > 16 && len < 256:
h.ExtensionProfile = extensionProfileTwoByte
}
h.Extensions = append(h.Extensions, Extension{id: id, payload: payload})
return nil
}
// GetExtensionIDs returns an extension id array
func (h *Header) GetExtensionIDs() []uint8 {
if !h.Extension {
return nil
}
if len(h.Extensions) == 0 {
return nil
}
ids := make([]uint8, 0, len(h.Extensions))
for _, extension := range h.Extensions {
ids = append(ids, extension.id)
}
return ids
}
// GetExtension returns an RTP header extension
func (h *Header) GetExtension(id uint8) []byte {
if !h.Extension {
return nil
}
for _, extension := range h.Extensions {
if extension.id == id {
return extension.payload
}
}
return nil
}
// DelExtension Removes an RTP Header extension
func (h *Header) DelExtension(id uint8) error {
if !h.Extension {
return errHeaderExtensionsNotEnabled
}
for i, extension := range h.Extensions {
if extension.id == id {
h.Extensions = append(h.Extensions[:i], h.Extensions[i+1:]...)
return nil
}
}
return errHeaderExtensionNotFound
}
// Marshal serializes the packet into bytes.
func (p *Packet) Marshal() (buf []byte, err error) {
buf = make([]byte, p.MarshalSize())
n, err := p.MarshalTo(buf)
if err != nil {
return nil, err
}
return buf[:n], nil
}
// MarshalTo serializes the packet and writes to the buffer.
func (p *Packet) MarshalTo(buf []byte) (n int, err error) {
n, err = p.Header.MarshalTo(buf)
if err != nil {
return 0, err
}
// Make sure the buffer is large enough to hold the packet.
if n+len(p.Payload) > len(buf) {
return 0, io.ErrShortBuffer
}
m := copy(buf[n:], p.Payload)
return n + m, nil
}
// MarshalSize returns the size of the packet once marshaled.
func (p *Packet) MarshalSize() int {
return p.Header.MarshalSize() + len(p.Payload)
}
// Clone returns a deep copy of p.
func (p *Packet) Clone() *Packet {
clone := &Packet{}
clone.Header = p.Header.Clone()
if p.Payload != nil {
clone.Payload = make([]byte, len(p.Payload))
copy(clone.Payload, p.Payload)
}
return clone
}
// Clone returns a deep copy h.
func (h Header) Clone() Header {
clone := h
if h.CSRC != nil {
clone.CSRC = make([]uint32, len(h.CSRC))
copy(clone.CSRC, h.CSRC)
}
if h.Extensions != nil {
ext := make([]Extension, len(h.Extensions))
for i, e := range h.Extensions {
ext[i] = e
if e.payload != nil {
ext[i].payload = make([]byte, len(e.payload))
copy(ext[i].payload, e.payload)
}
}
clone.Extensions = ext
}
return clone
}

98
vendor/github.com/pion/rtp/packetizer.go generated vendored Normal file
View File

@@ -0,0 +1,98 @@
package rtp
import (
"time"
)
// Payloader payloads a byte array for use as rtp.Packet payloads
type Payloader interface {
Payload(mtu uint16, payload []byte) [][]byte
}
// Packetizer packetizes a payload
type Packetizer interface {
Packetize(payload []byte, samples uint32) []*Packet
EnableAbsSendTime(value int)
SkipSamples(skippedSamples uint32)
}
type packetizer struct {
MTU uint16
PayloadType uint8
SSRC uint32
Payloader Payloader
Sequencer Sequencer
Timestamp uint32
ClockRate uint32
extensionNumbers struct { // put extension numbers in here. If they're 0, the extension is disabled (0 is not a legal extension number)
AbsSendTime int // http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
}
timegen func() time.Time
}
// NewPacketizer returns a new instance of a Packetizer for a specific payloader
func NewPacketizer(mtu uint16, pt uint8, ssrc uint32, payloader Payloader, sequencer Sequencer, clockRate uint32) Packetizer {
return &packetizer{
MTU: mtu,
PayloadType: pt,
SSRC: ssrc,
Payloader: payloader,
Sequencer: sequencer,
Timestamp: globalMathRandomGenerator.Uint32(),
ClockRate: clockRate,
timegen: time.Now,
}
}
func (p *packetizer) EnableAbsSendTime(value int) {
p.extensionNumbers.AbsSendTime = value
}
// Packetize packetizes the payload of an RTP packet and returns one or more RTP packets
func (p *packetizer) Packetize(payload []byte, samples uint32) []*Packet {
// Guard against an empty payload
if len(payload) == 0 {
return nil
}
payloads := p.Payloader.Payload(p.MTU-12, payload)
packets := make([]*Packet, len(payloads))
for i, pp := range payloads {
packets[i] = &Packet{
Header: Header{
Version: 2,
Padding: false,
Extension: false,
Marker: i == len(payloads)-1,
PayloadType: p.PayloadType,
SequenceNumber: p.Sequencer.NextSequenceNumber(),
Timestamp: p.Timestamp, // Figure out how to do timestamps
SSRC: p.SSRC,
},
Payload: pp,
}
}
p.Timestamp += samples
if len(packets) != 0 && p.extensionNumbers.AbsSendTime != 0 {
sendTime := NewAbsSendTimeExtension(p.timegen())
// apply http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
b, err := sendTime.Marshal()
if err != nil {
return nil // never happens
}
err = packets[len(packets)-1].SetExtension(uint8(p.extensionNumbers.AbsSendTime), b)
if err != nil {
return nil // never happens
}
}
return packets
}
// SkipSamples causes a gap in sample count between Packetize requests so the
// RTP payloads produced have a gap in timestamps
func (p *packetizer) SkipSamples(skippedSamples uint32) {
p.Timestamp += skippedSamples
}

6
vendor/github.com/pion/rtp/partitionheadchecker.go generated vendored Normal file
View File

@@ -0,0 +1,6 @@
package rtp
// PartitionHeadChecker is the interface that checks whether the packet is keyframe or not
type PartitionHeadChecker interface {
IsPartitionHead([]byte) bool
}

8
vendor/github.com/pion/rtp/rand.go generated vendored Normal file
View File

@@ -0,0 +1,8 @@
package rtp
import (
"github.com/pion/randutil"
)
// Use global random generator to properly seed by crypto grade random.
var globalMathRandomGenerator = randutil.NewMathRandomGenerator() // nolint:gochecknoglobals

26
vendor/github.com/pion/rtp/renovate.json generated vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"extends": [
"config:base"
],
"postUpdateOptions": [
"gomodTidy"
],
"commitBody": "Generated by renovateBot",
"packageRules": [
{
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],
"automerge": true
},
{
"packagePatterns": ["^golang.org/x/"],
"schedule": ["on the first day of the month"]
}
],
"ignorePaths": [
".github/workflows/generate-authors.yml",
".github/workflows/lint.yaml",
".github/workflows/renovate-go-mod-fix.yaml",
".github/workflows/test.yaml",
".github/workflows/tidy-check.yaml"
]
}

2
vendor/github.com/pion/rtp/rtp.go generated vendored Normal file
View File

@@ -0,0 +1,2 @@
// Package rtp provides RTP packetizer and depacketizer
package rtp

57
vendor/github.com/pion/rtp/sequencer.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
package rtp
import (
"math"
"sync"
)
// Sequencer generates sequential sequence numbers for building RTP packets
type Sequencer interface {
NextSequenceNumber() uint16
RollOverCount() uint64
}
// NewRandomSequencer returns a new sequencer starting from a random sequence
// number
func NewRandomSequencer() Sequencer {
return &sequencer{
sequenceNumber: uint16(globalMathRandomGenerator.Intn(math.MaxUint16)),
}
}
// NewFixedSequencer returns a new sequencer starting from a specific
// sequence number
func NewFixedSequencer(s uint16) Sequencer {
return &sequencer{
sequenceNumber: s - 1, // -1 because the first sequence number prepends 1
}
}
type sequencer struct {
sequenceNumber uint16
rollOverCount uint64
mutex sync.Mutex
}
// NextSequenceNumber increment and returns a new sequence number for
// building RTP packets
func (s *sequencer) NextSequenceNumber() uint16 {
s.mutex.Lock()
defer s.mutex.Unlock()
s.sequenceNumber++
if s.sequenceNumber == 0 {
s.rollOverCount++
}
return s.sequenceNumber
}
// RollOverCount returns the amount of times the 16bit sequence number
// has wrapped
func (s *sequencer) RollOverCount() uint64 {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.rollOverCount
}

39
vendor/github.com/pion/rtp/transportccextension.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
package rtp
import (
"encoding/binary"
)
const (
// transport-wide sequence
transportCCExtensionSize = 2
)
// TransportCCExtension is a extension payload format in
// https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | 0xBE | 0xDE | length=1 |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | L=1 |transport-wide sequence number | zero padding |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type TransportCCExtension struct {
TransportSequence uint16
}
// Marshal serializes the members to buffer
func (t *TransportCCExtension) Marshal() ([]byte, error) {
buf := make([]byte, transportCCExtensionSize)
binary.BigEndian.PutUint16(buf[0:2], t.TransportSequence)
return buf, nil
}
// Unmarshal parses the passed byte slice and stores the result in the members
func (t *TransportCCExtension) Unmarshal(rawData []byte) error {
if len(rawData) < transportCCExtensionSize {
return errTooSmall
}
t.TransportSequence = binary.BigEndian.Uint16(rawData[0:2])
return nil
}