github.com/puellanivis/breton@v0.2.16/lib/mpeg/ts/stream.go (about)

     1  package ts
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"strings"
     7  	"sync"
     8  
     9  	"github.com/pkg/errors"
    10  	"github.com/puellanivis/breton/lib/mpeg/ts/psi"
    11  )
    12  
    13  // ProgramType defines an enum describing some common MPEG-TS program types.
    14  type ProgramType byte
    15  
    16  // ProgramType enum values.
    17  const (
    18  	ProgramTypeVideo ProgramType = 0x01
    19  	ProgramTypeAudio ProgramType = 0x03
    20  	ProgramTypeAAC   ProgramType = 0x0F
    21  	ProgramTypeH264  ProgramType = 0x1B
    22  
    23  	ProgramTypeUnknown ProgramType = 0x09 // TODO: this is a guess?
    24  )
    25  
    26  type stream struct {
    27  	mu sync.Mutex
    28  
    29  	ready         chan struct{}
    30  	discontinuity chan struct{}
    31  
    32  	err error
    33  
    34  	pid  uint16
    35  	data *psi.StreamData
    36  
    37  	rd io.Reader
    38  	wr io.Writer
    39  
    40  	closer func() error
    41  }
    42  
    43  func (s *stream) makeReady() {
    44  	s.mu.Lock()
    45  	defer s.mu.Unlock()
    46  
    47  	select {
    48  	case <-s.ready:
    49  	default:
    50  		close(s.ready)
    51  	}
    52  }
    53  
    54  func (s *stream) Discontinuity() {
    55  	s.mu.Lock()
    56  	defer s.mu.Unlock()
    57  
    58  	select {
    59  	case <-s.discontinuity:
    60  	default:
    61  		// already marked, avoid making more channels.
    62  		return
    63  	}
    64  
    65  	s.discontinuity = make(chan struct{})
    66  }
    67  
    68  func (s *stream) getDiscontinuity() bool {
    69  	select {
    70  	case <-s.discontinuity:
    71  		return false
    72  	default:
    73  	}
    74  
    75  	s.mu.Lock()
    76  	defer s.mu.Unlock()
    77  
    78  	if s.discontinuity == nil {
    79  		s.discontinuity = make(chan struct{})
    80  	}
    81  
    82  	select {
    83  	case <-s.discontinuity:
    84  		return false
    85  	default:
    86  	}
    87  
    88  	close(s.discontinuity)
    89  	return true
    90  }
    91  
    92  func (s *stream) String() string {
    93  	<-s.ready
    94  
    95  	out := []string{
    96  		"stream",
    97  		fmt.Sprintf("PID:x%04X", s.pid),
    98  	}
    99  
   100  	if s.rd != nil {
   101  		switch s.rd.(type) {
   102  		case fmt.Stringer:
   103  			out = append(out, fmt.Sprintf("R:%v", s.rd))
   104  		default:
   105  			out = append(out, "R")
   106  		}
   107  	}
   108  
   109  	if s.wr != nil {
   110  		switch s.wr.(type) {
   111  		case fmt.Stringer:
   112  			out = append(out, fmt.Sprintf("W:%v", s.wr))
   113  		default:
   114  			out = append(out, "W")
   115  		}
   116  	}
   117  
   118  	return fmt.Sprintf("{%s}", strings.Join(out, " "))
   119  }
   120  
   121  func (s *stream) Read(b []byte) (n int, err error) {
   122  	<-s.ready
   123  
   124  	if s.rd == nil {
   125  		if s.err != nil {
   126  			return 0, s.err
   127  		}
   128  
   129  		return 0, errors.Errorf("pid 0x%04X is not open for reading", s.pid)
   130  	}
   131  
   132  	return s.rd.Read(b)
   133  }
   134  
   135  func (s *stream) Write(b []byte) (n int, err error) {
   136  	<-s.ready
   137  
   138  	if s.wr == nil {
   139  		if s.err != nil {
   140  			return 0, s.err
   141  		}
   142  
   143  		return 0, errors.Errorf("pid 0x%04X is not open for writing", s.pid)
   144  	}
   145  
   146  	return s.wr.Write(b)
   147  }
   148  
   149  func (s *stream) Close() error {
   150  	s.makeReady()
   151  
   152  	if s.closer != nil {
   153  		return s.closer()
   154  	}
   155  
   156  	return nil
   157  }