streaming

Media streaming and broadcast systems in Go
Log | Files | Refs | README | LICENSE

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 }