commit 20f13bbb764ba43e808a29a70c4b5356a30ca6fe
parent 3ddfbb7700d66859a807bc21c6c22892838669c6
Author: Oliver Lowe <o@olowe.co>
Date: Fri, 14 Jun 2024 14:04:28 +1000
mpegts: correctly unpack, pack clock references; PES packets
Bugs! Finally unpack clock references correctly by reading in the
correct bit and byte order. PES payloads are only present when the
PayloadStart flag is set, so don't try to decode a PES packet
otherwise.
Diffstat:
2 files changed, 49 insertions(+), 26 deletions(-)
diff --git a/mpegts/codec.go b/mpegts/codec.go
@@ -123,11 +123,14 @@ func parseAdaptationField(buf []byte) *Adaptation {
return &af
}
+// 0 pppp pppp
+// 1 pppp pppp
+// 2 pppp pppp
+// 3 pppp pppp
+// 4 prrr rrre
+// 5 eeee eeee
func parsePCR(a [6]byte) PCR {
- b := []byte{0, 0, 0, a[4] & 0x80, a[3], a[2], a[1], a[0]}
- //copy(b[:4], a[:4])
- // b[4] &= 0x80 // only want left-most bit
- //var base uint64 = uint64(a[0] >>
+ b := []byte{0, 0, 0, a[0], a[1], a[2], a[3], a[4] & 0x80}
base := binary.BigEndian.Uint64(b)
// next 6 bits reserved, so remaining 1 bit in a[5] and all of a[6] have the extension.
ext := binary.BigEndian.Uint16([]byte{a[4] & 0x01, a[5]})
@@ -135,7 +138,7 @@ func parsePCR(a [6]byte) PCR {
}
func unmarshalPayload(payload []byte, p *Packet) error {
- if isPESPayload(payload) {
+ if isPESPayload(payload) && p.PayloadStart {
pes, err := decodePES(payload)
if err != nil {
return fmt.Errorf("decode PES packet: %w", err)
@@ -277,12 +280,10 @@ func putPCR(b []byte, pcr *PCR) error {
if pcr.Base > max {
return fmt.Errorf("base %d larger than max %d", pcr.Base, max)
}
- b[0] = byte(pcr.Base)
- b[1] = byte(pcr.Base >> 8)
- b[2] = byte(pcr.Base >> 16)
- b[3] = byte(pcr.Base >> 24)
- b[4] = byte(pcr.Base >> 32)
-
+ ubuf := make([]byte, 8)
+ binary.BigEndian.PutUint64(ubuf, pcr.Base)
+ ubuf = ubuf[3:] // we only want 33 bits, so get 4 + 1 bytes (32+1 bits)
+ copy(b, ubuf)
b[4] |= 0x7e // toggle 6 reserved bits
var emax uint16 = 512 - 1 // max 9-bit int
diff --git a/mpegts/codec_test.go b/mpegts/codec_test.go
@@ -2,6 +2,7 @@ package mpegts
import (
"bytes"
+ "crypto/md5"
"errors"
"io"
"os"
@@ -70,27 +71,48 @@ func TestDecode(t *testing.T) {
}
}
-func TestOnePacket(t *testing.T) {
- tstamp := Timestamp{
- PTS: true,
- Ticks: 900909,
+func TestScanner(t *testing.T) {
+ name := "testdata/193039199_mp4_h264_aac_hq_7.ts"
+ data, err := os.ReadFile(name)
+ if err != nil {
+ t.Fatal(err)
}
- var want = [5]byte{0x21, 0x00, 0x37, 0x7e, 0x5b}
+ sum := md5.Sum(data)
- unpacked, err := unpackTimestamp(want)
+ f, err := os.Open(name)
if err != nil {
t.Fatal(err)
}
- if unpacked.Ticks != tstamp.Ticks {
- t.Errorf("unpacked ticks %d, want %d", unpacked.Ticks, tstamp.Ticks)
- t.Logf("want\t%#033b", tstamp.Ticks)
- t.Logf("got\t%#033b", unpacked.Ticks)
+ defer f.Close()
+ buf := &bytes.Buffer{}
+ sc := NewScanner(f)
+ var i int
+ for sc.Scan() {
+ i++
+ p := sc.Packet()
+ if err := Encode(buf, p); err != nil {
+ t.Fatalf("packet %d: encode: %v", i, err)
+ }
+ }
+ if sc.Err() != nil {
+ t.Fatalf("scan: %v", sc.Err())
+ }
+ got := md5.Sum(buf.Bytes())
+ if got != sum {
+ t.Errorf("re-encoded stream differs from source: got checksum %x, want %x", got, sum)
}
+}
+
+func TestPCR(t *testing.T) {
+ a := [6]byte{0x00, 0x24, 0x52, 0xd4, 0x7e, 0x00}
+ pcr := parsePCR(a)
- packed := packTimestamp(tstamp)
- if packed != want {
- t.Errorf("packTimestamp(%v) = %#x, want %#x", tstamp, packed, want)
- t.Logf("got\t%08b", packed)
- t.Logf("want\t%08b", want)
+ var got [6]byte
+ if err := putPCR(got[:], &pcr); err != nil {
+ t.Errorf("put pcr: %v", err)
+ }
+ if got != a {
+ t.Errorf("PCR differs after decode, re-encode")
+ t.Errorf("putPCR(buf, %v) = %08b, want %08b", pcr, got, a)
}
}