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 }