forked from asticode/go-astits
-
Notifications
You must be signed in to change notification settings - Fork 0
/
data.go
110 lines (95 loc) · 2.69 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
package astits
import (
"fmt"
"github.com/asticode/go-astikit"
)
// PIDs
const (
PIDPAT = 0x0 // Program Association Table (PAT) contains a directory listing of all Program Map Tables.
PIDCAT = 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 = 0x2 // Transport Stream Description Table (TSDT) contains descriptors related to the overall transport stream
PIDNull = 0x1fff // Null Packet (used for fixed bandwidth padding)
)
// Data represents a data
type Data struct {
EIT *EITData
FirstPacket *Packet
NIT *NITData
PAT *PATData
PES *PESData
PID uint16
PMT *PMTData
SDT *SDTData
TOT *TOTData
}
// ParseData parses a payload spanning over multiple packets and returns a set of data
func ParseData(ps []*Packet, prs PacketsParser, pm ProgramMap) (ds []*Data, 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)
}
// Append payload
var payload = make([]byte, l)
var c int
for _, p := range ps {
c += copy(payload[c:], p.Payload)
}
// Create reader
i := astikit.NewBytesIterator(payload)
// Parse PID
pid := ps[0].Header.PID
// 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(ps[0], pid)
} else if isPESPayload(payload) {
// 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 = append(ds, &Data{
FirstPacket: ps[0],
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.Exists(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
}