github.com/puellanivis/breton@v0.2.16/lib/mpeg/ts/pes/pes.go (about) 1 package pes 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/pkg/errors" 8 ) 9 10 const ( 11 idPaddingStream = 0xBE 12 idPrivateStream2 = 0xBF 13 14 mandatoryHeaderLength = 6 15 ) 16 17 // Stream is a structure defining properties of a Primitive Elementary Stream. 18 type Stream struct { 19 ID byte // Stream ID 20 21 Header // Optional PES Header fields. 22 } 23 24 // HeaderLength returns the length in bytes of the Header for this Stream. 25 func (s *Stream) HeaderLength() (int, error) { 26 l := mandatoryHeaderLength 27 28 switch s.ID { 29 case idPaddingStream, idPrivateStream2: 30 // Optional PES Header not present for these streams. 31 default: 32 h, err := s.marshalHeader() 33 if err != nil { 34 return 0, err 35 } 36 37 l += len(h) 38 } 39 40 return l, nil 41 } 42 43 func (s *Stream) String() string { 44 out := []string{ 45 fmt.Sprintf("ID:x%02X", s.ID), 46 } 47 48 if s.ID != idPaddingStream && s.ID != idPrivateStream2 { 49 if s.ScrambleControl != 0 { 50 out = append(out, fmt.Sprintf("Scramble:x%X", s.ScrambleControl)) 51 } 52 53 if s.Priority { 54 out = append(out, "PRI") 55 } 56 57 if s.DataAlignment { 58 out = append(out, "ALIGN") 59 } 60 61 if s.Copyright { 62 out = append(out, "COPYRIGHT") 63 } 64 65 if s.IsOriginal { 66 out = append(out, "ORIG") 67 } 68 69 if s.PTS != nil { 70 out = append(out, fmt.Sprintf("PTS:x%09X", *s.PTS)) 71 } 72 73 if s.DTS != nil { 74 out = append(out, fmt.Sprintf("DTS:x%09X", *s.DTS)) 75 } 76 77 if s.extFlags != 0 { 78 out = append(out, fmt.Sprintf("flags:%02X", s.extFlags)) 79 } 80 81 if len(s.padding) > 0 { 82 out = append(out, fmt.Sprintf("padding[%d]{% 2X}", len(s.padding), s.padding)) 83 } 84 } 85 86 return fmt.Sprintf("{%s}", strings.Join(out, " ")) 87 } 88 89 // Header is the Optional PES Header defined in SO/IEC 13818-1 and ITU-T H.222.0. 90 // It does not currently support any of the options that yield a variable length Header. 91 type Header struct { 92 ScrambleControl byte 93 94 Priority bool 95 DataAlignment bool 96 Copyright bool 97 IsOriginal bool 98 99 PTS *uint64 100 DTS *uint64 101 102 extLen int 103 104 extFlags byte 105 padding []byte 106 } 107 108 const ( 109 markerBits = 0x80 110 111 maskScramble = 0x30 112 shiftScramble = 4 113 114 flagPriority = 0x08 115 flagAlignment = 0x04 116 flagCopyright = 0x02 117 flagOriginal = 0x01 118 119 flagPTSDTS = 0xC0 120 ) 121 122 // unmarshalHeader fills in the values of an Optional PES Header from those encoded in the given byte-slice. 123 func (h *Header) unmarshalHeader(b []byte) (int, error) { 124 length := 3 + int(b[2]) // full header length 125 b = b[:length] // enforce header length with slice boundaries 126 127 h.ScrambleControl = (b[0] & maskScramble) >> shiftScramble 128 h.Priority = b[0]&flagPriority != 0 129 h.DataAlignment = b[0]&flagAlignment != 0 130 h.Copyright = b[0]&flagCopyright != 0 131 h.IsOriginal = b[0]&flagOriginal != 0 132 133 // where the padding starts 134 padStart := 3 135 136 switch b[1] & flagPTSDTS { 137 case 0x40: 138 return length, errors.New("invalid PTS/DTS flag value") 139 140 case 0x80: 141 h.PTS = decodeTS(b[padStart:]) 142 padStart += 5 143 144 case 0xC0: 145 h.PTS = decodeTS(b[padStart:]) 146 padStart += 5 147 148 h.DTS = decodeTS(b[padStart:]) 149 padStart += 5 150 } 151 152 // we ignore all b[1] flags right now… 153 // if we were to read one of them, then padStart += lengthOf(field) 154 h.extFlags = b[1] &^ 0xc0 155 156 // we treat all of the rest of the header as “padding” for now 157 h.padding = append([]byte{}, b[padStart:]...) 158 159 return length, nil 160 } 161 162 // marshalHeader returns a byte-slice that is the encoding of a given Optional PES Header. 163 func (h *Header) marshalHeader() ([]byte, error) { 164 if h.ScrambleControl&^0x03 != 0 { 165 return nil, errors.Errorf("invalid scramble control: 0x%02X", h.ScrambleControl) 166 } 167 168 out := make([]byte, 3) 169 170 out[0] = markerBits | (h.ScrambleControl << shiftScramble) 171 172 if h.Priority { 173 out[0] |= flagPriority 174 } 175 176 if h.DataAlignment { 177 out[0] |= flagAlignment 178 } 179 180 if h.Copyright { 181 out[0] |= flagCopyright 182 } 183 184 if h.IsOriginal { 185 out[0] |= flagOriginal 186 } 187 188 out[1] = 0 189 190 var pts, dts []byte 191 192 if h.PTS != nil { 193 pts = encodeTS(*h.PTS) 194 pts[0] |= 0x20 195 out[1] |= 0x80 196 } 197 198 if h.DTS != nil { 199 dts = encodeTS(*h.DTS) 200 pts[0] |= 0x10 201 dts[0] |= 0x10 202 out[1] |= 0x40 203 } 204 205 if len(pts) > 0 { 206 out = append(out, pts...) 207 } 208 209 if len(dts) > 0 { 210 out = append(out, dts...) 211 } 212 213 // The following fields are not supported and given is their presumed values: 214 // They would need to be implemented in the following order, as they are concatted one-after-another. 215 // PTS/DTS = both not included 216 // ESCR = false 217 // ES Rate = false 218 // DSM Trick Mode = false 219 // Additional Copy Info = false 220 // CRC = false 221 // Extension = false 222 223 // Stuff any “padding” here at the end. 224 out = append(out, h.padding...) 225 226 // remaining header length 227 out[2] = byte(len(out) - 3) 228 229 return out, nil 230 }