Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mpegts: add time decoder that works with native timestamp #150

Merged
merged 1 commit into from
Oct 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 8 additions & 19 deletions pkg/formats/mpegts/time_decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import (
)

const (
maximum = 0x1FFFFFFFF // 33 bits
negativeThreshold = 0x1FFFFFFFF / 2
clockRate = 90000
clockRate = 90000
)

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

// TimeDecoder is a MPEG-TS timestamp decoder.
//
// Deprecated: replaced by TimeDecoder2
type TimeDecoder struct {
overall time.Duration
prev int64
wrapped *TimeDecoder2
}

// NewTimeDecoder allocates a TimeDecoder.
//
// Deprecated: replaced by NewTimeDecoder2
func NewTimeDecoder(start int64) *TimeDecoder {
return &TimeDecoder{
prev: start,
wrapped: NewTimeDecoder2(start),
}
}

// Decode decodes a MPEG-TS timestamp.
func (d *TimeDecoder) Decode(ts int64) time.Duration {
diff := (ts - d.prev) & maximum

// negative difference
if diff > negativeThreshold {
diff = (d.prev - ts) & maximum
d.prev = ts
d.overall -= time.Duration(diff)
} else {
d.prev = ts
d.overall += time.Duration(diff)
}

return multiplyAndDivide(d.overall, time.Second, clockRate)
return multiplyAndDivide(time.Duration(d.wrapped.Decode(ts)), time.Second, clockRate)
}
36 changes: 36 additions & 0 deletions pkg/formats/mpegts/time_decoder2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package mpegts

const (
maximum = 0x1FFFFFFFF // 33 bits
negativeThreshold = 0x1FFFFFFFF / 2
)

// TimeDecoder2 is a MPEG-TS timestamp decoder.
type TimeDecoder2 struct {
overall int64
prev int64
}

// NewTimeDecoder2 allocates a TimeDecoder.
func NewTimeDecoder2(start int64) *TimeDecoder2 {
return &TimeDecoder2{
prev: start,
}
}

// Decode decodes a MPEG-TS timestamp.
func (d *TimeDecoder2) Decode(ts int64) int64 {
diff := (ts - d.prev) & maximum

// negative difference
if diff > negativeThreshold {
diff = (d.prev - ts) & maximum
d.prev = ts
d.overall -= diff
} else {
d.prev = ts
d.overall += diff
}

return d.overall
}
71 changes: 71 additions & 0 deletions pkg/formats/mpegts/time_decoder2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package mpegts

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestTimeDecoder2NegativeDiff(t *testing.T) {
d := NewTimeDecoder2(64523434)

ts := d.Decode(64523434 - 90000)
require.Equal(t, int64(-90000), ts)

ts = d.Decode(64523434)
require.Equal(t, int64(0), ts)

ts = d.Decode(64523434 + 90000*2)
require.Equal(t, int64(2*90000), ts)

ts = d.Decode(64523434 + 90000)
require.Equal(t, int64(1*90000), ts)
}

func TestTimeDecoder2Overflow(t *testing.T) {
d := NewTimeDecoder2(0x1FFFFFFFF - 20)

i := int64(0x1FFFFFFFF - 20)
secs := int64(0)
const stride = 150
lim := int64(uint64(0x1FFFFFFFF - (stride * 90000)))

for n := 0; n < 100; n++ {
// overflow
i += 90000 * stride
secs += stride
ts := d.Decode(i)
require.Equal(t, secs*90000, ts)

// reach 2^32 slowly
secs += stride
i += 90000 * stride
for ; i < lim; i += 90000 * stride {
ts = d.Decode(i)
require.Equal(t, secs*90000, ts)
secs += stride
}
}
}

func TestTimeDecoder2OverflowAndBack(t *testing.T) {
d := NewTimeDecoder2(0x1FFFFFFFF - 90000 + 1)

ts := d.Decode(0x1FFFFFFFF - 90000 + 1)
require.Equal(t, int64(0), ts)

ts = d.Decode(90000)
require.Equal(t, int64(2*90000), ts)

ts = d.Decode(0x1FFFFFFFF - 90000 + 1)
require.Equal(t, int64(0), ts)

ts = d.Decode(0x1FFFFFFFF - 90000*2 + 1)
require.Equal(t, int64(-1*90000), ts)

ts = d.Decode(0x1FFFFFFFF - 90000 + 1)
require.Equal(t, int64(0), ts)

ts = d.Decode(90000)
require.Equal(t, int64(2*90000), ts)
}
Loading