forked from bluenviron/gortsplib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
decoder_generic.go
190 lines (157 loc) · 4.37 KB
/
decoder_generic.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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package rtpmpeg4audio
import (
"fmt"
"github.com/bluenviron/mediacommon/pkg/bits"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/pion/rtp"
)
func (d *Decoder) decodeGeneric(pkt *rtp.Packet) ([][]byte, error) {
if len(pkt.Payload) < 2 {
d.fragments = d.fragments[:0] // discard pending fragments
return nil, fmt.Errorf("payload is too short")
}
// AU-headers-length (16 bits)
headersLen := int(uint16(pkt.Payload[0])<<8 | uint16(pkt.Payload[1]))
if headersLen == 0 {
d.fragments = d.fragments[:0] // discard pending fragments
return nil, fmt.Errorf("invalid AU-headers-length")
}
payload := pkt.Payload[2:]
// AU-headers
dataLens, err := d.readAUHeaders(payload, headersLen)
if err != nil {
d.fragments = d.fragments[:0] // discard pending fragments
return nil, err
}
pos := (headersLen / 8)
if (headersLen % 8) != 0 {
pos++
}
payload = payload[pos:]
var aus [][]byte
if len(d.fragments) == 0 {
if pkt.Marker {
// AUs
aus = make([][]byte, len(dataLens))
for i, dataLen := range dataLens {
if len(payload) < int(dataLen) {
return nil, fmt.Errorf("payload is too short")
}
aus[i] = payload[:dataLen]
payload = payload[dataLen:]
}
} else {
if len(dataLens) != 1 {
return nil, fmt.Errorf("a fragmented packet can only contain one AU")
}
if len(payload) < int(dataLens[0]) {
return nil, fmt.Errorf("payload is too short")
}
d.fragmentsSize = int(dataLens[0])
d.fragments = append(d.fragments, payload[:dataLens[0]])
return nil, ErrMorePacketsNeeded
}
} else {
// we are decoding a fragmented AU
if len(dataLens) != 1 {
d.fragments = d.fragments[:0] // discard pending fragments
return nil, fmt.Errorf("a fragmented packet can only contain one AU")
}
if len(payload) < int(dataLens[0]) {
d.fragments = d.fragments[:0] // discard pending fragments
return nil, fmt.Errorf("payload is too short")
}
d.fragmentsSize += int(dataLens[0])
if d.fragmentsSize > mpeg4audio.MaxAccessUnitSize {
d.fragments = d.fragments[:0] // discard pending fragments
return nil, fmt.Errorf("access unit size (%d) is too big, maximum is %d",
d.fragmentsSize, mpeg4audio.MaxAccessUnitSize)
}
d.fragments = append(d.fragments, payload[:dataLens[0]])
if !pkt.Marker {
return nil, ErrMorePacketsNeeded
}
aus = [][]byte{joinFragments(d.fragments, d.fragmentsSize)}
d.fragments = d.fragments[:0]
}
return d.removeADTS(aus)
}
func (d *Decoder) readAUHeaders(buf []byte, headersLen int) ([]uint64, error) {
firstRead := false
count := 0
for i := 0; i < headersLen; {
if i == 0 {
i += d.SizeLength
i += d.IndexLength
} else {
i += d.SizeLength
i += d.IndexDeltaLength
}
count++
}
dataLens := make([]uint64, count)
pos := 0
i := 0
for headersLen > 0 {
dataLen, err := bits.ReadBits(buf, &pos, d.SizeLength)
if err != nil {
return nil, err
}
headersLen -= d.SizeLength
if !firstRead {
firstRead = true
if d.IndexLength > 0 {
auIndex, err := bits.ReadBits(buf, &pos, d.IndexLength)
if err != nil {
return nil, err
}
headersLen -= d.IndexLength
if auIndex != 0 {
return nil, fmt.Errorf("AU-index different than zero is not supported")
}
}
} else if d.IndexDeltaLength > 0 {
auIndexDelta, err := bits.ReadBits(buf, &pos, d.IndexDeltaLength)
if err != nil {
return nil, err
}
headersLen -= d.IndexDeltaLength
if auIndexDelta != 0 {
return nil, fmt.Errorf("AU-index-delta different than zero is not supported")
}
}
dataLens[i] = dataLen
i++
}
return dataLens, nil
}
// some cameras wrap AUs into ADTS
func (d *Decoder) removeADTS(aus [][]byte) ([][]byte, error) {
if !d.firstAUParsed {
d.firstAUParsed = true
if len(aus) == 1 && len(aus[0]) >= 2 {
if aus[0][0] == 0xFF && (aus[0][1]&0xF0) == 0xF0 {
var pkts mpeg4audio.ADTSPackets
err := pkts.Unmarshal(aus[0])
if err == nil && len(pkts) == 1 {
d.adtsMode = true
aus[0] = pkts[0].AU
}
}
}
} else if d.adtsMode {
if len(aus) != 1 {
return nil, fmt.Errorf("multiple AUs in ADTS mode are not supported")
}
var pkts mpeg4audio.ADTSPackets
err := pkts.Unmarshal(aus[0])
if err != nil {
return nil, fmt.Errorf("unable to decode ADTS: %s", err)
}
if len(pkts) != 1 {
return nil, fmt.Errorf("multiple ADTS packets are not supported")
}
aus[0] = pkts[0].AU
}
return aus, nil
}