github.com/puellanivis/breton@v0.2.16/lib/mpeg/ts/psi/pat.go (about) 1 package psi 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/pkg/errors" 8 ) 9 10 // ProgramMap defines an MPEG-TS Program Map entry. 11 type ProgramMap struct { 12 ProgramNumber uint16 13 PID uint16 14 } 15 16 // Set assigns a given program number and pid into the ProgramMap. 17 func (pm *ProgramMap) Set(pnum, pid uint16) { 18 pm.ProgramNumber = pnum 19 if pid > 0x1FFF { 20 panic("PAT pids cannot exceed 0x1FFF") 21 } 22 pm.PID = pid 23 } 24 25 // PAT defines an MPEG-TS Program Allocation Table. 26 type PAT struct { 27 Syntax *SectionSyntax 28 29 Map []ProgramMap 30 31 crc uint32 32 } 33 34 func (pat *PAT) String() string { 35 out := []string{ 36 "PAT", 37 } 38 39 if pat.Syntax != nil { 40 out = append(out, fmt.Sprint(pat.Syntax)) 41 } 42 43 for _, m := range pat.Map { 44 out = append(out, fmt.Sprintf("x%X:x%X", m.ProgramNumber, m.PID)) 45 } 46 47 out = append(out, fmt.Sprintf("crc:x%08X", pat.crc)) 48 49 return fmt.Sprintf("{%s}", strings.Join(out, " ")) 50 } 51 52 const ( 53 tableidPAT = 0x00 54 ) 55 56 func init() { 57 Register(tableidPAT, func() PSI { return new(PAT) }) 58 } 59 60 // TableID implements mpeg/ts/psi.PSI. 61 func (pat *PAT) TableID() uint8 { 62 return tableidPAT 63 } 64 65 // SectionSyntax returns the embedded SectionSyntax, and implements mpeg/ts/psi.PSI. 66 func (pat *PAT) SectionSyntax() *SectionSyntax { 67 return pat.Syntax 68 } 69 70 // Unmarshal decodes a byte slice into the PAT. 71 func (pat *PAT) Unmarshal(b []byte) error { 72 if b[0] != tableidPAT { 73 return errors.Errorf("table_id mismatch: x%02X != x%02X", b[0], tableidPAT) 74 } 75 76 syn, data, crc, err := CommonUnmarshal(b) 77 if err != nil { 78 return err 79 } 80 81 pat.Syntax = syn 82 pat.crc = crc 83 84 pat.Map = make([]ProgramMap, len(data)/4) 85 for i := range pat.Map { 86 b := data[i*4:] 87 88 pat.Map[i].ProgramNumber = (uint16(b[0]) << 8) | uint16(b[1]) 89 pat.Map[i].PID = (uint16(b[2]&0x1F) << 8) | uint16(b[3]) 90 } 91 92 return nil 93 } 94 95 // Marshal encodes the PAT into a byte slice. 96 func (pat *PAT) Marshal() ([]byte, error) { 97 data := make([]byte, len(pat.Map)*4) 98 99 for i := range pat.Map { 100 b := data[i*4:] 101 102 b[0] = byte((pat.Map[i].ProgramNumber >> 8) & 0xFF) 103 b[1] = byte(pat.Map[i].ProgramNumber & 0xFF) 104 105 b[2] = byte((pat.Map[i].PID>>8)&0x1F) | 0xE0 106 b[3] = byte(pat.Map[i].PID & 0xFF) 107 } 108 109 return CommonMarshal(tableidPAT, false, pat.Syntax, data) 110 }