github.com/puellanivis/breton@v0.2.16/lib/mpeg/ts/program.go (about) 1 package ts 2 3 import ( 4 "context" 5 "io" 6 "sync" 7 8 "github.com/pkg/errors" 9 "github.com/puellanivis/breton/lib/mpeg/ts/packet" 10 "github.com/puellanivis/breton/lib/mpeg/ts/psi" 11 ) 12 13 // Program defines a MPEG-TS program within a Transport Stream. 14 type Program struct { 15 mu sync.Mutex 16 17 ts *TransportStream 18 19 pid uint16 20 pmt *psi.PMT 21 wr io.WriteCloser 22 } 23 24 // PID returns the Program ID assigned to this Program. 25 func (p *Program) PID() uint16 { 26 return p.pid 27 } 28 29 // StreamID returns the Stream ID assigned to the Program itself, not to its underlying Streams. 30 func (p *Program) StreamID() uint16 { 31 p.mu.Lock() 32 defer p.mu.Unlock() 33 34 if p.pmt == nil { 35 return 0 36 } 37 38 if p.pmt.Syntax == nil { 39 return 0 40 } 41 42 return p.pmt.Syntax.TableIDExtension 43 } 44 45 // NewWriter returns a newly allocated Stream for the Program. 46 func (p *Program) NewWriter(ctx context.Context, typ ProgramType) (io.WriteCloser, error) { 47 p.mu.Lock() 48 defer p.mu.Unlock() 49 50 if p.pmt == nil { 51 return nil, errors.New("program is not initialized") 52 } 53 54 spid := p.ts.newStreamPID() 55 56 if p.pmt.PCRPID == 0x1FFF { 57 p.pmt.PCRPID = spid 58 } 59 60 sdata := &psi.StreamData{ 61 Type: byte(typ), 62 PID: spid, 63 } 64 65 p.pmt.Streams = append(p.pmt.Streams, sdata) 66 67 w, err := p.ts.m.WriterByPID(ctx, spid, true) 68 if err != nil { 69 return nil, err 70 } 71 72 if s, ok := w.(*stream); ok { 73 s.data = sdata 74 } 75 76 return w, nil 77 } 78 79 // StreamPIDs returns the PIDs of all of the Streams for the Program. 80 func (p *Program) StreamPIDs() []uint16 { 81 p.mu.Lock() 82 defer p.mu.Unlock() 83 84 if p.pmt == nil { 85 return nil 86 } 87 88 var streamPIDs []uint16 89 90 for _, s := range p.pmt.Streams { 91 streamPIDs = append(streamPIDs, s.PID) 92 } 93 94 return streamPIDs 95 } 96 97 func (p *Program) packet(continuity byte) (*packet.Packet, error) { 98 p.mu.Lock() 99 defer p.mu.Unlock() 100 101 b, err := p.pmt.Marshal() 102 if err != nil { 103 return nil, err 104 } 105 106 return &packet.Packet{ 107 PID: p.pid, 108 PUSI: true, 109 Continuity: continuity & 0x0F, 110 Payload: b, 111 }, nil 112 }