-
Notifications
You must be signed in to change notification settings - Fork 191
/
encoder.go
146 lines (121 loc) · 3.04 KB
/
encoder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package rtpav1
import (
"crypto/rand"
"github.com/bluenviron/mediacommon/pkg/codecs/av1"
"github.com/pion/rtp"
)
const (
rtpVersion = 2
defaultPayloadMaxSize = 1460 // 1500 (UDP MTU) - 20 (IP header) - 8 (UDP header) - 12 (RTP header)
)
func randUint32() (uint32, error) {
var b [4]byte
_, err := rand.Read(b[:])
if err != nil {
return 0, err
}
return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3]), nil
}
// Encoder is a RTP/AV1 encoder.
// Specification: https://aomediacodec.github.io/av1-rtp-spec/
type Encoder struct {
// payload type of packets.
PayloadType uint8
// SSRC of packets (optional).
// It defaults to a random value.
SSRC *uint32
// initial sequence number of packets (optional).
// It defaults to a random value.
InitialSequenceNumber *uint16
// maximum size of packet payloads (optional).
// It defaults to 1460.
PayloadMaxSize int
sequenceNumber uint16
}
// Init initializes the encoder.
func (e *Encoder) Init() error {
if e.SSRC == nil {
v, err := randUint32()
if err != nil {
return err
}
e.SSRC = &v
}
if e.InitialSequenceNumber == nil {
v, err := randUint32()
if err != nil {
return err
}
v2 := uint16(v)
e.InitialSequenceNumber = &v2
}
if e.PayloadMaxSize == 0 {
e.PayloadMaxSize = defaultPayloadMaxSize
}
e.sequenceNumber = *e.InitialSequenceNumber
return nil
}
// Encode encodes OBUs into RTP packets.
func (e *Encoder) Encode(obus [][]byte) ([]*rtp.Packet, error) {
isKeyFrame, err := av1.ContainsKeyFrame(obus)
if err != nil {
return nil, err
}
var curPacket *rtp.Packet
var packets []*rtp.Packet
curPayloadLen := 0
createNewPacket := func(z bool) {
curPacket = &rtp.Packet{
Header: rtp.Header{
Version: rtpVersion,
PayloadType: e.PayloadType,
SequenceNumber: e.sequenceNumber,
SSRC: *e.SSRC,
},
Payload: []byte{0},
}
e.sequenceNumber++
packets = append(packets, curPacket)
curPayloadLen = 1
if z {
curPacket.Payload[0] |= 1 << 7
}
}
finalizeCurPacket := func(y bool) {
if y {
curPacket.Payload[0] |= 1 << 6
}
}
createNewPacket(false)
for _, obu := range obus {
for {
avail := e.PayloadMaxSize - curPayloadLen
obuLen := len(obu)
needed := obuLen + 2
if needed <= avail {
buf := make([]byte, av1.LEB128MarshalSize(uint(obuLen)))
av1.LEB128MarshalTo(uint(obuLen), buf)
curPacket.Payload = append(curPacket.Payload, buf...)
curPacket.Payload = append(curPacket.Payload, obu...)
curPayloadLen += len(buf) + obuLen
break
}
if avail > 2 {
fragmentLen := avail - 2
buf := make([]byte, av1.LEB128MarshalSize(uint(fragmentLen)))
av1.LEB128MarshalTo(uint(fragmentLen), buf)
curPacket.Payload = append(curPacket.Payload, buf...)
curPacket.Payload = append(curPacket.Payload, obu[:fragmentLen]...)
obu = obu[fragmentLen:]
}
finalizeCurPacket(true)
createNewPacket(true)
}
}
finalizeCurPacket(false)
if isKeyFrame {
packets[0].Payload[0] |= 1 << 3
}
packets[len(packets)-1].Marker = true
return packets, nil
}