Skip to content

Commit 393a408

Browse files
authored
mpegts: add time decoder that works with native timestamp (#150)
1 parent 62c5cf1 commit 393a408

File tree

3 files changed

+115
-19
lines changed

3 files changed

+115
-19
lines changed

pkg/formats/mpegts/time_decoder.go

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ import (
55
)
66

77
const (
8-
maximum = 0x1FFFFFFFF // 33 bits
9-
negativeThreshold = 0x1FFFFFFFF / 2
10-
clockRate = 90000
8+
clockRate = 90000
119
)
1210

1311
// avoid an int64 overflow and preserve resolution by splitting division into two parts:
@@ -19,31 +17,22 @@ func multiplyAndDivide(v, m, d time.Duration) time.Duration {
1917
}
2018

2119
// TimeDecoder is a MPEG-TS timestamp decoder.
20+
//
21+
// Deprecated: replaced by TimeDecoder2
2222
type TimeDecoder struct {
23-
overall time.Duration
24-
prev int64
23+
wrapped *TimeDecoder2
2524
}
2625

2726
// NewTimeDecoder allocates a TimeDecoder.
27+
//
28+
// Deprecated: replaced by NewTimeDecoder2
2829
func NewTimeDecoder(start int64) *TimeDecoder {
2930
return &TimeDecoder{
30-
prev: start,
31+
wrapped: NewTimeDecoder2(start),
3132
}
3233
}
3334

3435
// Decode decodes a MPEG-TS timestamp.
3536
func (d *TimeDecoder) Decode(ts int64) time.Duration {
36-
diff := (ts - d.prev) & maximum
37-
38-
// negative difference
39-
if diff > negativeThreshold {
40-
diff = (d.prev - ts) & maximum
41-
d.prev = ts
42-
d.overall -= time.Duration(diff)
43-
} else {
44-
d.prev = ts
45-
d.overall += time.Duration(diff)
46-
}
47-
48-
return multiplyAndDivide(d.overall, time.Second, clockRate)
37+
return multiplyAndDivide(time.Duration(d.wrapped.Decode(ts)), time.Second, clockRate)
4938
}

pkg/formats/mpegts/time_decoder2.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package mpegts
2+
3+
const (
4+
maximum = 0x1FFFFFFFF // 33 bits
5+
negativeThreshold = 0x1FFFFFFFF / 2
6+
)
7+
8+
// TimeDecoder2 is a MPEG-TS timestamp decoder.
9+
type TimeDecoder2 struct {
10+
overall int64
11+
prev int64
12+
}
13+
14+
// NewTimeDecoder2 allocates a TimeDecoder.
15+
func NewTimeDecoder2(start int64) *TimeDecoder2 {
16+
return &TimeDecoder2{
17+
prev: start,
18+
}
19+
}
20+
21+
// Decode decodes a MPEG-TS timestamp.
22+
func (d *TimeDecoder2) Decode(ts int64) int64 {
23+
diff := (ts - d.prev) & maximum
24+
25+
// negative difference
26+
if diff > negativeThreshold {
27+
diff = (d.prev - ts) & maximum
28+
d.prev = ts
29+
d.overall -= diff
30+
} else {
31+
d.prev = ts
32+
d.overall += diff
33+
}
34+
35+
return d.overall
36+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package mpegts
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestTimeDecoder2NegativeDiff(t *testing.T) {
10+
d := NewTimeDecoder2(64523434)
11+
12+
ts := d.Decode(64523434 - 90000)
13+
require.Equal(t, int64(-90000), ts)
14+
15+
ts = d.Decode(64523434)
16+
require.Equal(t, int64(0), ts)
17+
18+
ts = d.Decode(64523434 + 90000*2)
19+
require.Equal(t, int64(2*90000), ts)
20+
21+
ts = d.Decode(64523434 + 90000)
22+
require.Equal(t, int64(1*90000), ts)
23+
}
24+
25+
func TestTimeDecoder2Overflow(t *testing.T) {
26+
d := NewTimeDecoder2(0x1FFFFFFFF - 20)
27+
28+
i := int64(0x1FFFFFFFF - 20)
29+
secs := int64(0)
30+
const stride = 150
31+
lim := int64(uint64(0x1FFFFFFFF - (stride * 90000)))
32+
33+
for n := 0; n < 100; n++ {
34+
// overflow
35+
i += 90000 * stride
36+
secs += stride
37+
ts := d.Decode(i)
38+
require.Equal(t, secs*90000, ts)
39+
40+
// reach 2^32 slowly
41+
secs += stride
42+
i += 90000 * stride
43+
for ; i < lim; i += 90000 * stride {
44+
ts = d.Decode(i)
45+
require.Equal(t, secs*90000, ts)
46+
secs += stride
47+
}
48+
}
49+
}
50+
51+
func TestTimeDecoder2OverflowAndBack(t *testing.T) {
52+
d := NewTimeDecoder2(0x1FFFFFFFF - 90000 + 1)
53+
54+
ts := d.Decode(0x1FFFFFFFF - 90000 + 1)
55+
require.Equal(t, int64(0), ts)
56+
57+
ts = d.Decode(90000)
58+
require.Equal(t, int64(2*90000), ts)
59+
60+
ts = d.Decode(0x1FFFFFFFF - 90000 + 1)
61+
require.Equal(t, int64(0), ts)
62+
63+
ts = d.Decode(0x1FFFFFFFF - 90000*2 + 1)
64+
require.Equal(t, int64(-1*90000), ts)
65+
66+
ts = d.Decode(0x1FFFFFFFF - 90000 + 1)
67+
require.Equal(t, int64(0), ts)
68+
69+
ts = d.Decode(90000)
70+
require.Equal(t, int64(2*90000), ts)
71+
}

0 commit comments

Comments
 (0)