clone

a desktop tv and program guide for over-the-air broadcasts: what's on air, what your tuner gets, live tv, recordings

main
airwaves / internal / ts / ts.go
ts.go 3.9K
1// Package ts reads MPEG transport streams as an HDHomeRun sends them: a2// whole RF channel's multiplex, cut into packets, with its tables followed3// (PAT, PMTs and ATSC's virtual channel table), one program taken out of it4// for each viewer or recording, and the damage that arrived counted.5package ts67// PacketSize is the size of a transport stream packet.8const PacketSize = 188910const (11 syncByte = 0x4712 nullPID = 0x1fff13 psipPID = 0x1ffb // ATSC's PSIP base PID, which carries the VCT14)1516// PID is a packet's packet identifier.17func PID(pkt []byte) int { return int(pkt[1]&0x1f)<<8 | int(pkt[2]) }1819// payload is a packet's payload, nil if it has none.20func payload(pkt []byte) []byte {21 switch pkt[3] >> 4 & 3 {22 case 1:23 return pkt[4:]24 case 3:25 if n := int(pkt[4]); n < PacketSize-5 {26 return pkt[5+n:]27 }28 }29 return nil30}3132// Splitter cuts a byte stream into whole packets. When the sync byte isn't33// where the next packet should start, it looks for two sync bytes a packet34// apart and carries on from there, counting the resync.35type Splitter struct {36 buf []byte37 lost bool38 resyncs int6439}4041// Write calls each for every whole packet in p, in order, keeping a partial42// packet for the next call. pkt is only valid during the call.43func (s *Splitter) Write(p []byte, each func(pkt []byte)) {44 s.buf = append(s.buf, p...)45 b := s.buf46 i := 047 for len(b)-i >= PacketSize {48 // A packet is whole when the next one starts after it, where that49 // has arrived.50 next := i+PacketSize >= len(b) || b[i+PacketSize] == syncByte51 if b[i] == syncByte && next && !s.lost {52 each(b[i : i+PacketSize])53 i += PacketSize54 continue55 }56 if !s.lost {57 s.lost = true58 s.resyncs++59 }60 j := i61 for j+PacketSize < len(b) && (b[j] != syncByte || b[j+PacketSize] != syncByte) {62 j++63 }64 i = j65 if j+PacketSize >= len(b) {66 break // no confirmed start yet; wait for more67 }68 s.lost = false69 }70 s.buf = s.buf[:copy(s.buf, b[i:])]71}7273// Resyncs counts the times the stream lost packet alignment.74func (s *Splitter) Resyncs() int64 { return s.resyncs }7576// Counter counts packets and the damage in them: packets the demodulator77// flagged with the transport error indicator, and gaps in a PID's78// continuity counter (packets lost on the way).79type Counter struct {80 Packets, TEI, CC int6481 // state is by PID: bit 7 seen, bit 6 the last packet was a duplicate,82 // the low bits its continuity counter.83 state [8192]uint884}8586// Packet counts pkt. Only packets carrying a payload advance a continuity87// counter; one duplicate packet in a row is allowed; the adaptation88// field's discontinuity indicator starts the count over; the null PID89// isn't followed.90func (c *Counter) Packet(pkt []byte) {91 c.Packets++92 pid := PID(pkt)93 afc := pkt[3] >> 4 & 394 tei := pkt[1]&0x80 != 095 if tei {96 c.TEI++97 }98 if pid == nullPID || afc == 0 {99 return100 }101 cc := pkt[3] & 0x0f102 // A flagged packet arrived, so its PID's count goes on from it without103 // counting a gap twice; so does one that starts the count over.104 if tei || afc&2 != 0 && pkt[4] > 0 && pkt[5]&0x80 != 0 {105 c.state[pid] = 0x80 | cc106 return107 }108 if afc&1 == 0 {109 return110 }111 st := c.state[pid]112 last := st & 0x0f113 switch {114 case st&0x80 == 0, cc == (last+1)&0x0f:115 c.state[pid] = 0x80 | cc116 case cc == last && st&0x40 == 0:117 c.state[pid] = 0xc0 | cc118 default:119 c.CC++120 c.state[pid] = 0x80 | cc121 }122}123124// Errors is the damage counted: flagged packets and continuity gaps.125func (c *Counter) Errors() int64 { return c.TEI + c.CC }126127var crcTable = func() (t [256]uint32) {128 for i := range t {129 c := uint32(i) << 24130 for range 8 {131 if c&0x80000000 != 0 {132 c = c<<1 ^ 0x04c11db7133 } else {134 c <<= 1135 }136 }137 t[i] = c138 }139 return t140}()141142// CRC32 is the MPEG-2 CRC that PSI sections end with. Over a whole section,143// its CRC included, it is 0 when the section arrived intact.144func CRC32(b []byte) uint32 {145 crc := uint32(0xffffffff)146 for _, x := range b {147 crc = crc<<8 ^ crcTable[byte(crc>>24)^x]148 }149 return crc150}