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  }