96 lines
2.4 KiB
Go
96 lines
2.4 KiB
Go
|
package astits
|
||
|
|
||
|
import (
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
// 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 = errors.Wrap(err, "astits: custom packets parsing failed")
|
||
|
return
|
||
|
} else if skip {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Reconstruct payload
|
||
|
var l int
|
||
|
for _, p := range ps {
|
||
|
l += len(p.Payload)
|
||
|
}
|
||
|
var payload = make([]byte, l)
|
||
|
var c int
|
||
|
for _, p := range ps {
|
||
|
c += copy(payload[c:], p.Payload)
|
||
|
}
|
||
|
|
||
|
// Parse PID
|
||
|
var 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) {
|
||
|
var psiData *PSIData
|
||
|
if psiData, err = parsePSIData(payload); err != nil {
|
||
|
err = errors.Wrap(err, "astits: parsing PSI data failed")
|
||
|
return
|
||
|
}
|
||
|
ds = psiData.toData(ps[0], pid)
|
||
|
} else if isPESPayload(payload) {
|
||
|
d, err := parsePESData(payload)
|
||
|
if err == nil {
|
||
|
ds = append(ds, &Data{
|
||
|
FirstPacket: ps[0],
|
||
|
PES: d,
|
||
|
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
|
||
|
}
|