psi: starting to write read functions for psi and tss

This commit is contained in:
saxon 2018-12-06 13:50:17 +10:30
parent ba35615964
commit 2ffa0f9b7b
1 changed files with 122 additions and 60 deletions

View File

@ -5,6 +5,7 @@ import (
"math/bits" "math/bits"
) )
// Some common lengths
const ( const (
ESSDDefLen = 5 ESSDDefLen = 5
DescDefLen = 2 DescDefLen = 2
@ -14,26 +15,32 @@ const (
PSIDefLen = 3 PSIDefLen = 3
) )
// Table Type IDs
const (
PATTableID = 0x00
PMTTableID = 0x02
)
// Program specific information // Program specific information
type PSI struct { type PSI struct {
pf byte // Point field Pf byte // Point field
pfb []byte // Pointer filler bytes Pfb []byte // Pointer filler bytes
tid byte // Table ID Tid byte // Table ID
ssi bool // Section syntax indicator (1 for PAT, PMT, CAT) Ssi bool // Section syntax indicator (1 for PAT, PMT, CAT)
pb bool // Private bit (0 for PAT, PMT, CAT) Pb bool // Private bit (0 for PAT, PMT, CAT)
sl uint16 // Section length Sl uint16 // Section length
tss *TSS // Table syntax section (length defined by SL) if length 0 then nil Tss *TSS // Table syntax section (length defined by SL) if length 0 then nil
crc uint32 // crc32 of entire table excluding pointer field, pointer filler bytes and the trailing CRC32 Crc uint32 // crc32 of entire table excluding pointer field, pointer filler bytes and the trailing CRC32
} }
// Table syntax section // Table syntax section
type TSS struct { type TSS struct {
tide uint16 // Table ID extension Tide uint16 // Table ID extension
v byte // Version number V byte // Version number
cni bool // Current/next indicator Cni bool // Current/next indicator
sn byte // Section number Sn byte // Section number
lsn byte // Last section number Lsn byte // Last section number
sd SD // Specific data PAT/PMT Sd SD // Specific data PAT/PMT
} }
// Specific Data, (could be PAT or PMT) // Specific Data, (could be PAT or PMT)
@ -43,49 +50,92 @@ type SD interface {
// Program association table, implements SD // Program association table, implements SD
type PAT struct { type PAT struct {
pn uint16 // Program Number Pn uint16 // Program Number
pmpid uint16 // Program map PID Pmpid uint16 // Program map PID
} }
// Program mapping table, implements SD // Program mapping table, implements SD
type PMT struct { type PMT struct {
pcrpid uint16 // Program clock reference pid Pcrpid uint16 // Program clock reference pid
pil uint16 // Program info length Pil uint16 // Program info length
pd []Desc // Program descriptors Pd []Desc // Program descriptors
essd []ESSD // Elementary stream specific data Essd []ESSD // Elementary stream specific data
} }
// Elementary stream specific data // Elementary stream specific data
type ESSD struct { type ESSD struct {
st byte // Stream type St byte // Stream type
epid uint16 // Elementary pid Epid uint16 // Elementary pid
esil uint16 // Elementary stream Esil uint16 // Elementary stream
esd []Desc // Elementary stream desriptors Esd []Desc // Elementary stream desriptors
} }
// Descriptor // Descriptor
type Desc struct { type Desc struct {
dt byte // Descriptor tag Dt byte // Descriptor tag
dl byte // Descriptor length Dl byte // Descriptor length
dd []byte // Descriptor data Dd []byte // Descriptor data
} }
// TODO: Implement this // ReadPSI creates a PSI data structure from a given byte slice that represents a PSI
func ReadPSI(data []byte) *PSI { func ReadPSI(data []byte) *PSI {
psi := PSI{}
pos := 0
psi.Pf = data[pos]
if psi.Pf != 0 {
psi.Pfb = make([]byte, 0, psi.Pf)
pos++
for i := 0; i < int(psi.Pf); i++ {
psi.Pfb = append(psi.Pfb, data[pos])
pos++
}
}
psi.Tid = data[pos]
pos++
psi.Ssi = byteToBool(data[pos] & 0x80)
psi.Pb = byteToBool(data[pos] & 0x40)
psi.Sl = uint16(data[pos]&0x03)<<8 | uint16(data[pos+1])
pos += 2
psi.Tss = readTSS(data[pos:], &psi)
return &psi
}
// ReadTSS creates a TSS data structure from a given byte slice that represents a TSS
func readTSS(data []byte, p *PSI) *TSS {
tss := TSS{}
pos := 0
tss.Tide = uint16(data[pos])<<8 | uint16(data[pos+1])
pos += 2
tss.V = (data[pos] & 0x3e) >> 1
tss.Cni = byteToBool(data[pos] & 0x01)
pos++
tss.Sn = data[pos]
pos++
tss.Lsn = data[pos]
pos++
if p.Tid == PATTableID {
tss.Sd = readPAT(data, &tss)
} else if p.Tid == PMTTableID {
tss.Sd = readPMT(data, &tss)
} else {
panic("Can't yet deal with tables that are not PAT or PMT")
}
return nil return nil
} }
// Bytes outputs a byte slice representation of the PSI
func (p *PSI) Bytes() []byte { func (p *PSI) Bytes() []byte {
l := 1 + len(p.pfb) l := 1 + len(p.Pfb)
out := make([]byte, l+PSIDefLen) out := make([]byte, l+PSIDefLen)
out[0] = p.pf out[0] = p.Pf
for i, b := range p.pfb { for i, b := range p.Pfb {
out[1+i] = b out[1+i] = b
} }
out[l] = p.tid out[l] = p.Tid
out[l+1] = 0x80 | 0x40 | 0x30 | (0x03 & byte(p.sl>>8)) out[l+1] = 0x80 | 0x40 | 0x30 | (0x03 & byte(p.Sl>>8))
out[l+2] = byte(p.sl) out[l+2] = byte(p.Sl)
out = append(out, p.tss.Bytes()...) out = append(out, p.Tss.Bytes()...)
crc32 := crc32_Update(0xffffffff, crc32_MakeTable(bits.Reverse32(crc32.IEEE)), out[l:]) crc32 := crc32_Update(0xffffffff, crc32_MakeTable(bits.Reverse32(crc32.IEEE)), out[l:])
out = append(out, make([]byte, 0, 4)...) out = append(out, make([]byte, 0, 4)...)
out = append(out, byte(crc32>>24)) out = append(out, byte(crc32>>24))
@ -95,57 +145,62 @@ func (p *PSI) Bytes() []byte {
return out return out
} }
// Bytes outputs a byte slice representation of the TSS
func (t *TSS) Bytes() []byte { func (t *TSS) Bytes() []byte {
out := make([]byte, TSSDefLen) out := make([]byte, TSSDefLen)
out[0] = byte(t.tide >> 8) out[0] = byte(t.Tide >> 8)
out[1] = byte(t.tide) out[1] = byte(t.Tide)
out[2] = 0xc0 | (0x3e & (t.v << 1)) | (0x01 & boolToByte(t.cni)) out[2] = 0xc0 | (0x3e & (t.V << 1)) | (0x01 & boolToByte(t.Cni))
out[3] = t.sn out[3] = t.Sn
out[4] = t.lsn out[4] = t.Lsn
out = append(out, t.sd.Bytes()...) out = append(out, t.Sd.Bytes()...)
return out return out
} }
// Bytes outputs a byte slice representation of the PAT
func (p *PAT) Bytes() []byte { func (p *PAT) Bytes() []byte {
out := make([]byte, PATLen) out := make([]byte, PATLen)
out[0] = byte(p.pn >> 8) out[0] = byte(p.Pn >> 8)
out[1] = byte(p.pn) out[1] = byte(p.Pn)
out[2] = 0xe0 | (0x1f & byte(p.pmpid>>8)) out[2] = 0xe0 | (0x1f & byte(p.Pmpid>>8))
out[3] = byte(p.pmpid) out[3] = byte(p.Pmpid)
return out return out
} }
// Bytes outputs a byte slice representation of the PMT
func (p *PMT) Bytes() []byte { func (p *PMT) Bytes() []byte {
out := make([]byte, PMTDefLen) out := make([]byte, PMTDefLen)
out[0] = 0xe0 | (0x1f & byte(p.pcrpid>>8)) out[0] = 0xe0 | (0x1f & byte(p.Pcrpid>>8))
out[1] = byte(p.pcrpid) out[1] = byte(p.Pcrpid)
out[2] = 0xf0 | (0x03 & byte(p.pil>>8)) out[2] = 0xf0 | (0x03 & byte(p.Pil>>8))
out[3] = byte(p.pil) out[3] = byte(p.Pil)
for _, d := range p.pd { for _, d := range p.Pd {
out = append(out, d.Bytes()...) out = append(out, d.Bytes()...)
} }
for _, e := range p.essd { for _, e := range p.Essd {
out = append(out, e.Bytes()...) out = append(out, e.Bytes()...)
} }
return out return out
} }
// Bytes outputs a byte slice representation of the Desc
func (d *Desc) Bytes() []byte { func (d *Desc) Bytes() []byte {
out := make([]byte, DescDefLen) out := make([]byte, DescDefLen)
out[0] = d.dt out[0] = d.Dt
out[1] = d.dl out[1] = d.Dl
out = append(out, d.dd...) out = append(out, d.Dd...)
return out return out
} }
// Bytes outputs a byte slice representation of the ESSD
func (e *ESSD) Bytes() []byte { func (e *ESSD) Bytes() []byte {
out := make([]byte, ESSDDefLen) out := make([]byte, ESSDDefLen)
out[0] = e.st out[0] = e.St
out[1] = 0xe0 | (0x1f & byte(e.epid>>8)) out[1] = 0xe0 | (0x1f & byte(e.Epid>>8))
out[2] = byte(e.epid) out[2] = byte(e.Epid)
out[3] = 0xf0 | (0x03 & byte(e.esil>>8)) out[3] = 0xf0 | (0x03 & byte(e.Esil>>8))
out[4] = byte(e.esil) out[4] = byte(e.Esil)
for _, d := range e.esd { for _, d := range e.Esd {
out = append(out, d.Bytes()...) out = append(out, d.Bytes()...)
} }
return out return out
@ -158,6 +213,13 @@ func boolToByte(b bool) byte {
return 0x00 return 0x00
} }
func byteToBool(b byte) bool {
if b == 0 {
return false
}
return true
}
func crc32_MakeTable(poly uint32) *crc32.Table { func crc32_MakeTable(poly uint32) *crc32.Table {
var t crc32.Table var t crc32.Table
for i := range t { for i := range t {