-
Notifications
You must be signed in to change notification settings - Fork 50
/
data.go
184 lines (155 loc) · 4.17 KB
/
data.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
package astits
import (
"encoding/binary"
"fmt"
"github.com/asticode/go-astikit"
)
// PIDs
const (
PIDPAT uint16 = 0x0 // Program Association Table (PAT) contains a directory listing of all Program Map Tables.
PIDCAT uint16 = 0x1 // Conditional Access Table (CAT) contains a directory listing of all ITU-T Rec. H.222 entitlement management message streams used by Program Map Tables.
PIDTSDT uint16 = 0x2 // Transport Stream Description Table (TSDT) contains descriptors related to the overall transport stream
PIDNull uint16 = 0x1fff // Null Packet (used for fixed bandwidth padding)
)
// DemuxerData represents a data parsed by Demuxer
type DemuxerData struct {
EIT *EITData
FirstPacket *Packet
NIT *NITData
PAT *PATData
PES *PESData
PID uint16
PMT *PMTData
SDT *SDTData
TOT *TOTData
}
// MuxerData represents a data to be written by Muxer
type MuxerData struct {
PID uint16
AdaptationField *PacketAdaptationField
PES *PESData
}
// parseData parses a payload spanning over multiple packets and returns a set of data
func parseData(ps []*Packet, prs PacketsParser, pm *programMap) (ds []*DemuxerData, err error) {
// Use custom parser first
if prs != nil {
var skip bool
if ds, skip, err = prs(ps); err != nil {
err = fmt.Errorf("astits: custom packets parsing failed: %w", err)
return
} else if skip {
return
}
}
// Get payload length
var l int
for _, p := range ps {
l += len(p.Payload)
}
// Get the slice for payload from pool
payload := bytesPool.get(l)
defer bytesPool.put(payload)
// Append payload
var c int
for _, p := range ps {
c += copy(payload.s[c:], p.Payload)
}
// Create reader
i := astikit.NewBytesIterator(payload.s)
// Parse PID
pid := ps[0].Header.PID
// Copy first packet headers, so we can safely deallocate original payload
fp := &Packet{
Header: ps[0].Header,
AdaptationField: ps[0].AdaptationField,
}
// Parse payload
if pid == PIDCAT {
// Information in a CAT payload is private and dependent on the CA system. Use the PacketsParser
// to parse this type of payload
} else if isPSIPayload(pid, pm) {
// Parse PSI data
var psiData *PSIData
if psiData, err = parsePSIData(i); err != nil {
err = fmt.Errorf("astits: parsing PSI data failed: %w", err)
return
}
// Append data
ds = psiData.toData(fp, pid)
} else if isPESPayload(payload.s) {
// Parse PES data
var pesData *PESData
if pesData, err = parsePESData(i); err != nil {
err = fmt.Errorf("astits: parsing PES data failed: %w", err)
return
}
// Append data
ds = []*DemuxerData{
{
FirstPacket: fp,
PES: pesData,
PID: pid,
},
}
}
return
}
// isPSIPayload checks whether the payload is a PSI one
func isPSIPayload(pid uint16, pm *programMap) bool {
return pid == PIDPAT || // PAT
pm.existsUnlocked(pid) || // PMT
((pid >= 0x10 && pid <= 0x14) || (pid >= 0x1e && pid <= 0x1f)) //DVB
}
// isPESPayload checks whether the payload is a PES one
func isPESPayload(i []byte) bool {
// Packet is not big enough
if len(i) < 3 {
return false
}
// Check prefix
return uint32(i[0])<<16|uint32(i[1])<<8|uint32(i[2]) == 1
}
// isPSIComplete checks whether we have sufficient amount of packets to parse PSI
func isPSIComplete(ps []*Packet) bool {
// Get payload length
var l int
for _, p := range ps {
l += len(p.Payload)
}
// Get the slice for payload from pool
payload := bytesPool.get(l)
defer bytesPool.put(payload)
// Append payload
var o int
for _, p := range ps {
o += copy(payload.s[o:], p.Payload)
}
// Create reader
i := astikit.NewBytesIterator(payload.s)
// Get next byte
b, err := i.NextByte()
if err != nil {
return false
}
// Pointer filler bytes
i.Skip(int(b))
for i.HasBytesLeft() {
// Get PSI table ID
b, err = i.NextByte()
if err != nil {
return false
}
// Check whether we need to stop the parsing
if shouldStopPSIParsing(PSITableID(b)) {
break
}
// Get PSI section length
var bs []byte
bs, err = i.NextBytesNoCopy(2)
if err != nil {
return false
}
i.Skip(int(binary.BigEndian.Uint16(bs) & 0x0fff))
}
return i.Len() >= i.Offset()
}