fix wrong timestamp computation that happened at 28h28m

this was caused by a int64 overflow.
This commit is contained in:
aler9
2022-02-13 17:00:13 +01:00
parent ab50034c93
commit a235613fd6
2 changed files with 39 additions and 28 deletions

View File

@@ -8,9 +8,8 @@ import (
// Decoder is a RTP timestamp decoder. // Decoder is a RTP timestamp decoder.
type Decoder struct { type Decoder struct {
clockRate time.Duration clockRate time.Duration
tsAdd int64 tsAdd *int64
tsInitial *int64 tsPrev int64
tsPrev *int64
} }
// New allocates a Decoder. // New allocates a Decoder.
@@ -24,22 +23,29 @@ func New(clockRate int) *Decoder {
func (d *Decoder) Decode(ts uint32) time.Duration { func (d *Decoder) Decode(ts uint32) time.Duration {
ts64 := int64(ts) ts64 := int64(ts)
if d.tsPrev != nil { if d.tsAdd == nil {
diff := ts64 - *d.tsPrev d.tsPrev = ts64
ts64 = -ts64
d.tsAdd = &ts64
return 0
}
diff := ts64 - d.tsPrev
d.tsPrev = ts64
switch { switch {
case diff < -0xFFFFFF: // overflow case diff < -0xFFFFFF: // overflow
d.tsAdd += 0x100000000 *d.tsAdd += 0x100000000
case diff > 0xFFFFFF: // timestamp overflowed then went back case diff > 0xFFFFFF: // timestamp overflowed then went back
d.tsAdd -= 0x100000000 *d.tsAdd -= 0x100000000
}
} }
d.tsPrev = &ts64 tot := time.Duration(ts64 + *d.tsAdd)
if d.tsInitial == nil { // avoid an int64 overflow and preserve resolution by splitting division into two parts:
d.tsInitial = &ts64 // first add seconds, then the decimal part.
} secs := tot / d.clockRate
dec := tot % d.clockRate
return time.Duration(ts64+d.tsAdd-*d.tsInitial) * time.Second / d.clockRate return secs*time.Second + dec*time.Second/d.clockRate
} }

View File

@@ -11,24 +11,29 @@ func TestOverflow(t *testing.T) {
d := New(90000) d := New(90000)
i := uint32(4294877296) i := uint32(4294877296)
secs := time.Duration(0)
pts := d.Decode(i) pts := d.Decode(i)
require.Equal(t, time.Duration(0), pts) require.Equal(t, time.Duration(0), pts)
// 1st overflow const stride = 150
i += 90000 * 2 lim := uint32(uint64(4294967296 - (stride * 90000)))
pts = d.Decode(i)
require.Equal(t, 2*time.Second, pts)
// reach 4294890000 slowly for n := 0; n < 100; n++ {
for ; i < 4294890000; i += 90000 * 10 { // overflow
i += 90000 * stride
secs += stride
pts = d.Decode(i) pts = d.Decode(i)
require.Equal(t, 2*time.Second+time.Second*time.Duration(i-90000)/90000, pts) require.Equal(t, secs*time.Second, pts)
// reach 2^32 slowly
secs += stride
i += 90000 * stride
for ; i < lim; i += 90000 * stride {
pts = d.Decode(i)
require.Equal(t, secs*time.Second, pts)
secs += stride
}
} }
// 2nd overflow
i += 90000 * 10
pts = d.Decode(i)
require.Equal(t, 47732*time.Second, pts)
} }
func TestOverflowAndBack(t *testing.T) { func TestOverflowAndBack(t *testing.T) {