streaming

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

commit 59f5025d611570198060cb837a0cac5dac6d5b26
parent 68956c4dceeca0d5f3e883c71743841791eca651
Author: Oliver Lowe <o@olowe.co>
Date:   Thu,  6 Jun 2024 15:44:12 +1000

mpegts: initial, basic decoding of packets

Diffstat:
Ampegts/codec.go | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmpegts/mpegts.go | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 123 insertions(+), 8 deletions(-)

diff --git a/mpegts/codec.go b/mpegts/codec.go @@ -0,0 +1,53 @@ +package mpegts + +import ( + "encoding/binary" + "fmt" + "io" +) + +func Decode(r io.Reader) (*Packet, error) { + buf := make([]byte, PacketSize) + n, err := r.Read(buf) + if n != PacketSize { + if err != nil { + return nil, fmt.Errorf("short read (%d bytes): %w", n, err) + } + return nil, fmt.Errorf("short read (%d bytes)", n) + } + if err != nil { + return nil, err + } + if buf[0] != Sync { + return nil, fmt.Errorf("expected sync byte, got %x", buf[0]) + } + var p Packet + if buf[1]&0x80 > 0 { + p.Error = true + } + if buf[1]&0x40 > 0 { + p.PayloadStart = true + } + if buf[1]&0x20 > 0 { + p.Priority = true + } + // Want next 13 bits. 5 from buf[1] and all of buf[2]. + pid := binary.BigEndian.Uint16([]byte{buf[1] & 0x1f, buf[2]}) + p.PID = PacketID(pid) + + // next 2 bits + p.Scrambling = Scramble(buf[3] & 0xc0) + // skip next 2 bits until later when we need to decode adaptation or payload. + // now just get last 4 bits + p.Continuity = buf[3] & 0x0f + afc := buf[3] >> 4 + switch afc { + case 0x01: + p.Payload = buf[4:] + case 0x03: + p.Adaptation = buf[4:] + default: + return &p, fmt.Errorf("cannot decode both payload and adaptation field") + } + return &p, nil +} diff --git a/mpegts/mpegts.go b/mpegts/mpegts.go @@ -1,22 +1,27 @@ // Package mpegts implements encoding and decoding of MPEG-TS packets as specified in ITU-T H.222.0. package mpegts +import "fmt" + const PacketSize int = 188 +const Sync byte = 'G' + type Packet struct { // If true, the packet should be discarded. Error bool + // Indicates whether the payload holds the first byte of a particular payload such as ... TODO(otl) + PayloadStart bool // If true, this packet has higher priority than other packets // with the same PID. Priority bool - // Indicates whether the payload holds the first byte of a particular payload such as ... TODO(otl) - PayloadStart bool - // Identifies the type of the payload. - PID uint16 + // Identifies the type of the packet. + PID PacketID // Specifies which algorithm, if any, is used to encrypt the payload. - ScrambleConrol Scramble - Adaptation *Adaptation - Payload []byte + Scrambling Scramble + Continuity uint8 + Adaptation []byte + Payload []byte } type Scramble uint8 @@ -28,4 +33,61 @@ const ( ScrambleOdd Scramble = 0xc0 ) -type Adaptation struct{} +type PacketID uint16 + +const ( + PAT PacketID = iota // Program association table + CAT // Conditional access table + TSDT // Transport stream description table + IPMP + _ // reserved through to + PacketNull = 8191 +) + +func (id PacketID) String() string { + switch id { + case PAT: + return "PAT" + case CAT: + return "CAT" + case TSDT: + return "TSDT" + case IPMP: + return "IPMP" + case PacketNull: + return "null" + } + return fmt.Sprintf("%d", id) +} + +// Adaptation represents an adaptation field including the header. +type Adaptation struct { + // If true, there is a discontinuity between this packet and + // either the continuity conter or PCR. + Discontinuous bool + // If true, the packet may be used as an index from which to + // randomly access other points in the stream. + RandomAccess bool + // Whether this stream is high priority. + Priority bool + PCR *PCR + // Original program clock reference. + OPCR *PCR + // The number of packets remaining until a splicing point. + SpliceCountdown uint8 + // Raw bytes of any application-specific data. + Private []byte + // Raw bytes of the adaptation extension field. + Extension []byte + // A slice of bytes all with the value 0xff; enough to ensure + // a packet's length is always PacketSize. + Stuffing []byte +} + +// PCR represents a Program Clock Reference +type PCR struct { + // Number of ticks of a 27MHz clock as a 33-bit integer. + Ticks uint64 + // 9-bit integer + Extension uint16 +}