2018-12-04 08:33:04 +03:00
|
|
|
package psi
|
|
|
|
|
2018-12-06 04:46:26 +03:00
|
|
|
import (
|
|
|
|
"hash/crc32"
|
|
|
|
"math/bits"
|
|
|
|
)
|
|
|
|
|
2018-12-05 14:16:06 +03:00
|
|
|
const (
|
2018-12-05 17:11:53 +03:00
|
|
|
ESSDDefLen = 5
|
|
|
|
DescDefLen = 2
|
|
|
|
PMTDefLen = 4
|
|
|
|
PATLen = 4
|
2018-12-05 17:58:14 +03:00
|
|
|
TSSDefLen = 5
|
|
|
|
PSIDefLen = 3
|
2018-12-05 14:16:06 +03:00
|
|
|
)
|
|
|
|
|
2018-12-04 08:33:04 +03:00
|
|
|
// Program specific information
|
|
|
|
type PSI struct {
|
2018-12-05 12:01:29 +03:00
|
|
|
pf byte // Point field
|
2018-12-05 14:16:06 +03:00
|
|
|
pfb []byte // Pointer filler bytes
|
2018-12-05 12:01:29 +03:00
|
|
|
tid byte // Table ID
|
2018-12-05 16:34:19 +03:00
|
|
|
ssi bool // Section syntax indicator (1 for PAT, PMT, CAT)
|
2018-12-05 12:01:29 +03:00
|
|
|
pb bool // Private bit (0 for PAT, PMT, CAT)
|
|
|
|
sl uint16 // Section length
|
|
|
|
tss *TSS // Table syntax section (length defined by SL) if length 0 then nil
|
2018-12-05 17:58:14 +03:00
|
|
|
crc uint32 // crc32 of entire table excluding pointer field, pointer filler bytes and the trailing CRC32
|
2018-12-04 08:33:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Table syntax section
|
|
|
|
type TSS struct {
|
2018-12-05 17:58:14 +03:00
|
|
|
tide uint16 // Table ID extension
|
|
|
|
v byte // Version number
|
|
|
|
cni bool // Current/next indicator
|
|
|
|
sn byte // Section number
|
|
|
|
lsn byte // Last section number
|
|
|
|
sd SD // Specific data PAT/PMT
|
2018-12-04 08:33:04 +03:00
|
|
|
}
|
|
|
|
|
2018-12-05 12:01:29 +03:00
|
|
|
// Specific Data, (could be PAT or PMT)
|
2018-12-04 08:33:04 +03:00
|
|
|
type SD interface {
|
2018-12-05 12:01:29 +03:00
|
|
|
Bytes() []byte
|
2018-12-04 08:33:04 +03:00
|
|
|
}
|
|
|
|
|
2018-12-05 12:01:29 +03:00
|
|
|
// Program association table, implements SD
|
|
|
|
type PAT struct {
|
|
|
|
pn uint16 // Program Number
|
2018-12-05 14:16:06 +03:00
|
|
|
pmpid uint16 // Program map PID
|
|
|
|
}
|
|
|
|
|
|
|
|
// Program mapping table, implements SD
|
|
|
|
type PMT struct {
|
2018-12-05 14:17:16 +03:00
|
|
|
pcrpid uint16 // Program clock reference pid
|
|
|
|
pil uint16 // Program info length
|
|
|
|
pd []Desc // Program descriptors
|
|
|
|
essd []ESSD // Elementary stream specific data
|
2018-12-04 08:33:04 +03:00
|
|
|
}
|
|
|
|
|
2018-12-05 14:16:06 +03:00
|
|
|
// Elementary stream specific data
|
|
|
|
type ESSD struct {
|
2018-12-05 14:17:16 +03:00
|
|
|
st byte // Stream type
|
2018-12-05 17:04:29 +03:00
|
|
|
epid uint16 // Elementary pid
|
2018-12-05 14:17:16 +03:00
|
|
|
esil uint16 // Elementary stream
|
|
|
|
esd []Desc // Elementary stream desriptors
|
2018-12-05 14:16:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Descriptor
|
|
|
|
type Desc struct {
|
2018-12-05 12:01:29 +03:00
|
|
|
dt byte // Descriptor tag
|
|
|
|
dl byte // Descriptor length
|
|
|
|
dd []byte // Descriptor data
|
|
|
|
}
|
|
|
|
|
2018-12-05 17:58:14 +03:00
|
|
|
// TODO: Implement this
|
2018-12-05 14:16:06 +03:00
|
|
|
func ReadPSI(data []byte) *PSI {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-12-05 17:58:14 +03:00
|
|
|
func (p *PSI) Bytes() []byte {
|
|
|
|
l := 1 + len(p.pfb)
|
|
|
|
out := make([]byte, l+PSIDefLen)
|
|
|
|
out[0] = p.pf
|
|
|
|
for i, b := range p.pfb {
|
|
|
|
out[1+i] = b
|
|
|
|
}
|
|
|
|
out[l] = p.tid
|
|
|
|
out[l+1] = 0x80 | 0x40 | 0x30 | (0x03 & byte(p.sl>>8))
|
|
|
|
out[l+2] = byte(p.sl)
|
|
|
|
out = append(out, p.tss.Bytes()...)
|
2018-12-06 04:46:26 +03:00
|
|
|
crc32 := crc32_Update(0xffffffff, crc32_MakeTable(bits.Reverse32(crc32.IEEE)), out[l:])
|
|
|
|
out = append(out, make([]byte, 0, 4)...)
|
|
|
|
out = append(out, byte(crc32>>24))
|
|
|
|
out = append(out, byte(crc32>>16))
|
|
|
|
out = append(out, byte(crc32>>8))
|
|
|
|
out = append(out, byte(crc32))
|
|
|
|
return out
|
2018-12-05 12:01:29 +03:00
|
|
|
}
|
|
|
|
|
2018-12-05 17:58:14 +03:00
|
|
|
func (t *TSS) Bytes() []byte {
|
|
|
|
out := make([]byte, TSSDefLen)
|
|
|
|
out[0] = byte(t.tide >> 8)
|
|
|
|
out[1] = byte(t.tide)
|
|
|
|
out[2] = 0xc0 | (0x3e & (t.v << 1)) | (0x01 & boolToByte(t.cni))
|
|
|
|
out[3] = t.sn
|
|
|
|
out[4] = t.lsn
|
|
|
|
out = append(out, t.sd.Bytes()...)
|
|
|
|
return out
|
2018-12-05 12:01:29 +03:00
|
|
|
}
|
|
|
|
|
2018-12-05 17:11:53 +03:00
|
|
|
func (p *PAT) Bytes() []byte {
|
|
|
|
out := make([]byte, PATLen)
|
|
|
|
out[0] = byte(p.pn >> 8)
|
|
|
|
out[1] = byte(p.pn)
|
|
|
|
out[2] = 0xe0 | (0x1f & byte(p.pmpid>>8))
|
|
|
|
out[3] = byte(p.pmpid)
|
|
|
|
return out
|
2018-12-05 12:01:29 +03:00
|
|
|
}
|
|
|
|
|
2018-12-05 17:04:29 +03:00
|
|
|
func (p *PMT) Bytes() []byte {
|
2018-12-05 17:11:53 +03:00
|
|
|
out := make([]byte, PMTDefLen)
|
2018-12-05 17:04:29 +03:00
|
|
|
out[0] = 0xe0 | (0x1f & byte(p.pcrpid>>8))
|
|
|
|
out[1] = byte(p.pcrpid)
|
|
|
|
out[2] = 0xf0 | (0x03 & byte(p.pil>>8))
|
|
|
|
out[3] = byte(p.pil)
|
|
|
|
for _, d := range p.pd {
|
|
|
|
out = append(out, d.Bytes()...)
|
|
|
|
}
|
|
|
|
for _, e := range p.essd {
|
|
|
|
out = append(out, e.Bytes()...)
|
|
|
|
}
|
|
|
|
return out
|
2018-12-05 12:01:29 +03:00
|
|
|
}
|
|
|
|
|
2018-12-05 17:04:29 +03:00
|
|
|
func (d *Desc) Bytes() []byte {
|
2018-12-05 17:11:53 +03:00
|
|
|
out := make([]byte, DescDefLen)
|
2018-12-05 16:34:19 +03:00
|
|
|
out[0] = d.dt
|
|
|
|
out[1] = d.dl
|
|
|
|
out = append(out, d.dd...)
|
2018-12-05 17:04:29 +03:00
|
|
|
return out
|
2018-12-04 08:33:04 +03:00
|
|
|
}
|
2018-12-05 14:16:06 +03:00
|
|
|
|
2018-12-05 17:04:29 +03:00
|
|
|
func (e *ESSD) Bytes() []byte {
|
2018-12-05 17:11:53 +03:00
|
|
|
out := make([]byte, ESSDDefLen)
|
2018-12-05 16:34:19 +03:00
|
|
|
out[0] = e.st
|
2018-12-05 17:04:29 +03:00
|
|
|
out[1] = 0xe0 | (0x1f & byte(e.epid>>8))
|
|
|
|
out[2] = byte(e.epid)
|
|
|
|
out[3] = 0xf0 | (0x03 & byte(e.esil>>8))
|
2018-12-05 16:34:19 +03:00
|
|
|
out[4] = byte(e.esil)
|
|
|
|
for _, d := range e.esd {
|
|
|
|
out = append(out, d.Bytes()...)
|
2018-12-05 14:16:06 +03:00
|
|
|
}
|
2018-12-05 17:04:29 +03:00
|
|
|
return out
|
2018-12-05 14:16:06 +03:00
|
|
|
}
|
2018-12-05 17:58:14 +03:00
|
|
|
|
|
|
|
func boolToByte(b bool) byte {
|
|
|
|
if b {
|
|
|
|
return 0x01
|
|
|
|
}
|
|
|
|
return 0x00
|
|
|
|
}
|
2018-12-06 04:46:26 +03:00
|
|
|
|
|
|
|
func crc32_MakeTable(poly uint32) *crc32.Table {
|
|
|
|
var t crc32.Table
|
|
|
|
for i := range t {
|
|
|
|
crc := uint32(i) << 24
|
|
|
|
for j := 0; j < 8; j++ {
|
|
|
|
if crc&0x80000000 != 0 {
|
|
|
|
crc = (crc << 1) ^ poly
|
|
|
|
} else {
|
|
|
|
crc <<= 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t[i] = crc
|
|
|
|
}
|
|
|
|
return &t
|
|
|
|
}
|
|
|
|
|
|
|
|
func crc32_Update(crc uint32, tab *crc32.Table, p []byte) uint32 {
|
|
|
|
for _, v := range p {
|
|
|
|
crc = tab[byte(crc>>24)^v] ^ (crc << 8)
|
|
|
|
}
|
|
|
|
return crc
|
|
|
|
}
|