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:
| A | mpegts/codec.go | | | 53 | +++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | mpegts/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
+}