pes.go (9229B)
1 package mpegts 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 ) 7 8 // PESPacket represents a packetised elementary stream (PES) packet. 9 // These are transported in MPEG-TS packet payloads. 10 type PESPacket struct { 11 // ID uniquely identifies this stream from other elementary streams. 12 ID byte 13 // Length is the number of bytes for this packet. 14 // A value of zero indicates the packet can be of any length, 15 // but is only valid when the underlying stream is video. 16 Length uint16 17 Header *PESHeader 18 // Data contains raw audio/video data. 19 Data []byte 20 } 21 22 // PESHeader represents the optional header of a PES packet. 23 type PESHeader struct { 24 // Scrambling informs decoders how packet contents are encrypted or "scrambled". 25 // Zero indicates the stream is not scrambled. 26 Scrambling uint8 27 // Priority signals to decoders that this packet should be processed before others. 28 Priority bool 29 // Alignment indicates thatheader is immediately followed by 30 // the video start code or audio syncword. 31 Alignment bool 32 // Copyrighted signals that stream's content is copyrighted. 33 Copyrighted bool 34 // Original signals whether the stream is an original or copy. 35 Original bool 36 // Fields indicates which optional fields are present in Optional. 37 Fields uint8 38 Presentation *Timestamp 39 Decode *Timestamp 40 // Optional holds any bytes that we don't know how to decode (yet). 41 // TOOD(otl): also contains stuffing bytes, which should be stored separately. 42 Optional []byte 43 } 44 45 func (h PESHeader) packedLength() int { 46 n := headerLength 47 if h.Presentation != nil { 48 n += 5 // packed timestamps are [5]byte 49 } 50 if h.Decode != nil { 51 n += 5 // packed timestamps are [5]byte 52 } 53 return n + len(h.Optional) 54 } 55 56 // flags + fields + field length 57 const headerLength int = 3 58 59 // Flags indicating which optional fields are present in a PES header's payload. 60 const ( 61 FieldPTS uint8 = 1 << (7 - iota) 62 FieldDTS 63 FieldESCR 64 FieldESRate 65 FieldTrickMode 66 FieldCopyInfo 67 FieldCRC 68 FieldExtension 69 ) 70 71 var pesHeaderPrefix [3]byte = [3]byte{0, 0, 1} 72 73 func isPESPayload(payload []byte) bool { 74 if len(payload) < 6 { 75 return false // too short 76 } 77 var prefix [3]byte 78 copy(prefix[:], payload[:3]) 79 if prefix == pesHeaderPrefix { 80 return true 81 } 82 return false 83 } 84 85 func decodePES(buf []byte) (*PESPacket, error) { 86 if !isPESPayload(buf) { 87 return nil, fmt.Errorf("no PES packet") 88 } 89 var pes PESPacket 90 pes.ID = buf[3] 91 pes.Length = binary.BigEndian.Uint16(buf[4:6]) 92 buf = buf[6:] 93 // is there a header to decode? 94 if pes.Length >= 3 { 95 header, err := decodePESHeader(buf) 96 if err != nil { 97 return nil, fmt.Errorf("decode header: %w", err) 98 } 99 pes.Header = header 100 // how many bytes we read from buf 101 read := pes.Header.packedLength() 102 buf = buf[read:] 103 } 104 pes.Data = buf 105 return &pes, nil 106 } 107 108 func encodePESPacket(p *PESPacket) ([]byte, error) { 109 // length is startcode + id + length 110 buf := make([]byte, 3+1+2) 111 copy(buf[:3], pesHeaderPrefix[:]) 112 buf[3] = p.ID 113 binary.BigEndian.PutUint16(buf[4:6], p.Length) 114 if p.Header != nil { 115 b, err := encodePESHeader(p.Header) 116 if err != nil { 117 return nil, fmt.Errorf("encode PES header: %w", err) 118 } 119 buf = append(buf, b...) 120 } 121 if p.Data != nil { 122 buf = append(buf, p.Data...) 123 } 124 return buf, nil 125 } 126 127 func decodePESHeader(buf []byte) (*PESHeader, error) { 128 if len(buf) < 3 { 129 return nil, fmt.Errorf("short buffer length %d: need at least 3", len(buf)) 130 } 131 if buf[0]&0xc0 == 0 { 132 return nil, fmt.Errorf("decode header: bad marker bits") 133 } 134 var h PESHeader 135 flags := buf[0] 136 h.Scrambling = flags & 0b00110000 137 h.Priority = flags&0b00001000 > 0 138 h.Alignment = flags&0b00000100 > 0 139 h.Copyrighted = flags&0b00000010 > 0 140 h.Original = flags&0b00000001 > 0 141 142 h.Fields = buf[1] 143 144 hlength := int(buf[2]) 145 if len(buf[3:]) < hlength { 146 return nil, fmt.Errorf("short buffer: header reports %d, have %d", hlength, len(buf[3:])) 147 } 148 buf = buf[3 : 3+hlength] 149 150 if h.Fields&FieldPTS > 0 { 151 var tstamp Timestamp 152 tstamp.PTS = h.Fields&FieldPTS > 0 153 tstamp.DTS = h.Fields&FieldDTS > 0 154 if !tstamp.PTS { 155 return nil, fmt.Errorf("timestamp present but missing PTS") 156 } 157 var err error 158 var a [5]byte 159 copy(a[:], buf[:5]) 160 tstamp, err = unpackTimestamp(a) 161 if err != nil { 162 return nil, fmt.Errorf("read timestamp: %w", err) 163 } 164 h.Presentation = &tstamp 165 buf = buf[5:] 166 } 167 if h.Fields&FieldDTS > 0 { 168 var tstamp Timestamp 169 tstamp.PTS = h.Fields&FieldPTS > 0 170 tstamp.DTS = h.Fields&FieldDTS > 0 171 if !tstamp.PTS { 172 return nil, fmt.Errorf("timestamp present but missing PTS") 173 } 174 var err error 175 var a [5]byte 176 copy(a[:], buf[:5]) 177 tstamp, err = unpackTimestamp(a) 178 if err != nil { 179 return nil, fmt.Errorf("read timestamp: %w", err) 180 } 181 h.Decode = &tstamp 182 buf = buf[5:] 183 } 184 h.Optional = buf 185 return &h, nil 186 } 187 188 func encodePESHeader(h *PESHeader) ([]byte, error) { 189 // length of 3: flags + fields + header length 190 buf := make([]byte, 3) 191 buf[0] |= (1 << 7) // marker bits 192 buf[0] |= h.Scrambling 193 if h.Priority { 194 buf[0] |= (1 << 3) 195 } 196 if h.Alignment { 197 buf[0] |= (1 << 2) 198 } 199 if h.Copyrighted { 200 buf[0] |= (1 << 1) 201 } 202 if h.Original { 203 buf[0] |= 1 204 } 205 buf[1] = h.Fields 206 var opt []byte 207 if h.Presentation != nil { 208 if !h.Presentation.PTS && h.Presentation.DTS { 209 return nil, fmt.Errorf("bad timestamp: DTS set without PTS") 210 } 211 packed := packTimestamp(*h.Presentation) 212 opt = append(opt, packed[:]...) 213 } 214 if h.Decode != nil { 215 if !h.Decode.PTS && h.Decode.DTS { 216 return nil, fmt.Errorf("bad timestamp: DTS set without PTS") 217 } 218 packed := packTimestamp(*h.Decode) 219 opt = append(opt, packed[:]...) 220 } 221 if h.Optional != nil { 222 opt = append(opt, h.Optional...) 223 } 224 // TODO(otl): decode, encode stuffing 225 buf[2] = byte(len(opt)) 226 buf = append(buf, opt...) 227 return buf, nil 228 } 229 230 // Timestamp represents the timestamp transported in a PES packet 231 // header. It is used by decoders to reliably time and synchronise 232 // playback of video/audio payloads. 233 type Timestamp struct { 234 // PTS indicates the packet carrying the timestamp contains a presentation timestamp. 235 PTS bool 236 // DTS indicates the packet carrying this timestamp contains a decode timestamp. 237 DTS bool 238 // Ticks holds a 33-bit integer counting the number of ticks of a 90KHz clock. 239 Ticks uint64 240 } 241 242 const maxTicks uint64 = 0x1ffffffff // max 33-bit integer 243 244 // unpackTimestamp unpacks the Timestamp stored in a. 245 // It is packed in 40 bits across 5 bytes, shown in the following bitfield diagram: 246 // 247 // 0 00pd ttt1 248 // 1 tttt tttt 249 // 2 tttt ttt1 250 // 3 tttt tttt 251 // 4 tttt ttt1 252 // 253 // 0, 1, 2, 3, 4 are each byte index in the array a. 254 // The two leading 0s are padding bits. 255 // P and D hold the values for PTS and DTS in Timestamp. 256 // The 1s are check bits which must be toggled. 257 // Ts are the 33-bit big-endian encoded integer. 258 func unpackTimestamp(a [5]byte) (Timestamp, error) { 259 var tstamp Timestamp 260 tstamp.PTS = a[0]&0b00100000 > 0 261 tstamp.DTS = a[0]&0b00010000 > 0 262 if tstamp.DTS && !tstamp.PTS { 263 return Timestamp{}, fmt.Errorf("DTS set but no PTS set") 264 } 265 if a[0]&a[2]&a[4]&0x01 == 0 { 266 return Timestamp{}, fmt.Errorf("corrupt timestamp") 267 } 268 269 tbuf := make([]byte, 5) // enough for 33-bit integer 270 tbuf[0] = (a[0] & 0b00001000) >> 3 271 272 tbuf[1] = (a[0] & 0b00000110) << 5 273 tbuf[1] |= (a[1] & 0b11111100) >> 2 274 275 tbuf[2] = (a[1] & 0b00000011) << 6 276 tbuf[2] |= (a[2] & 0b11111100) >> 2 277 278 tbuf[3] = (a[2] & 0b00000010) << 6 279 tbuf[3] |= (a[3] & 0b11111110) >> 1 280 281 tbuf[4] = (a[3] & 0b00000001) << 7 282 tbuf[4] |= (a[4] & 0b11111110) >> 1 283 buf := make([]byte, 8) 284 copy(buf[3:], tbuf) 285 tstamp.Ticks = binary.BigEndian.Uint64(buf) 286 return tstamp, nil 287 } 288 289 // packTimestamp returns an array containing a packed Timestamp. 290 // The Timestamp is packed according to the bitfield layout documented 291 // in unpackTimestamp. 292 func packTimestamp(t Timestamp) [5]byte { 293 var a [5]byte 294 if t.PTS { 295 a[0] |= (1 << 5) 296 } 297 if t.DTS { 298 a[0] |= (1 << 4) 299 } 300 ticks := make([]byte, 8) // sizeof uint64 301 binary.BigEndian.PutUint64(ticks, t.Ticks) 302 // we don't want the whole 64-bit integer, only enough for 33 bits. 303 ticks = ticks[3:] 304 305 b := ticks[0] & 0b00000001 306 a[0] |= (b << 3) 307 308 // ticks[0] is packed. 309 // 2 bits remaining before check bit in a[0]. 310 b = ticks[1] & 0b11000000 311 a[0] |= (b >> 5) 312 a[0] |= 1 // toggle check bit 313 314 // 6 bits remaining in ticks[1]. 315 b = ticks[1] & 0b00111111 316 a[1] |= (b << 2) 317 318 // 2 bits remaining in a[1]. 319 // we're done with ticks[1], so pack left-most 2 bits from ticks[2]. 320 b = ticks[2] & 0b11000000 321 a[1] |= (b >> 6) 322 323 // a[1] packed. 324 // pack remaining 6 bits from ticks[2] into a[2]. 325 b = ticks[2] & 0b00111111 326 a[2] |= (b << 2) 327 328 // ticks[2] done. 329 // 1 bit remaining in a[2] before the check bit. 330 // pack 1 bit from ticks[3] into a[2]. 331 b = ticks[3] & 0b10000000 332 a[2] |= (b >> 6) 333 a[2] |= 1 // toggle check bit 334 335 // 7 bits remaining in ticks[3]. 336 // a[2] done. 337 b = ticks[3] & 0b01111111 338 a[3] |= (b << 1) 339 340 // ticks[3] all packed. 341 // a[3] has 1 bit remaining. 342 b = ticks[4] & 0b10000000 343 a[3] |= (b >> 7) 344 345 // a[3] done. 346 // 7 bits remaining to pack from ticks[4]. 347 b = ticks[4] & 0b01111111 348 a[4] = (b << 1) 349 350 // just 1 bit left to pack from ticks[4]! woo hoo! 351 // just 1 bit free in a[4] before the check bit. 352 b = ticks[4] & 0b10000000 353 a[4] |= (b >> 7) 354 a[4] |= 1 // toggle check bit 355 return a 356 }