From a235613fd67421f34925c489c2a77fd8a6451366 Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sun, 13 Feb 2022 17:00:13 +0100 Subject: [PATCH] fix wrong timestamp computation that happened at 28h28m this was caused by a int64 overflow. --- pkg/rtptimedec/decoder.go | 38 ++++++++++++++++++++-------------- pkg/rtptimedec/decoder_test.go | 29 +++++++++++++++----------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/pkg/rtptimedec/decoder.go b/pkg/rtptimedec/decoder.go index 89d91eae..a2baa526 100644 --- a/pkg/rtptimedec/decoder.go +++ b/pkg/rtptimedec/decoder.go @@ -8,9 +8,8 @@ import ( // Decoder is a RTP timestamp decoder. type Decoder struct { clockRate time.Duration - tsAdd int64 - tsInitial *int64 - tsPrev *int64 + tsAdd *int64 + tsPrev int64 } // New allocates a Decoder. @@ -24,22 +23,29 @@ func New(clockRate int) *Decoder { func (d *Decoder) Decode(ts uint32) time.Duration { ts64 := int64(ts) - if d.tsPrev != nil { - diff := ts64 - *d.tsPrev - switch { - case diff < -0xFFFFFF: // overflow - d.tsAdd += 0x100000000 - - case diff > 0xFFFFFF: // timestamp overflowed then went back - d.tsAdd -= 0x100000000 - } + if d.tsAdd == nil { + d.tsPrev = ts64 + ts64 = -ts64 + d.tsAdd = &ts64 + return 0 } - d.tsPrev = &ts64 + diff := ts64 - d.tsPrev + d.tsPrev = ts64 - if d.tsInitial == nil { - d.tsInitial = &ts64 + switch { + case diff < -0xFFFFFF: // overflow + *d.tsAdd += 0x100000000 + + case diff > 0xFFFFFF: // timestamp overflowed then went back + *d.tsAdd -= 0x100000000 } - return time.Duration(ts64+d.tsAdd-*d.tsInitial) * time.Second / d.clockRate + tot := time.Duration(ts64 + *d.tsAdd) + + // avoid an int64 overflow and preserve resolution by splitting division into two parts: + // first add seconds, then the decimal part. + secs := tot / d.clockRate + dec := tot % d.clockRate + return secs*time.Second + dec*time.Second/d.clockRate } diff --git a/pkg/rtptimedec/decoder_test.go b/pkg/rtptimedec/decoder_test.go index 721ecc1e..dbf7aaa1 100644 --- a/pkg/rtptimedec/decoder_test.go +++ b/pkg/rtptimedec/decoder_test.go @@ -11,24 +11,29 @@ func TestOverflow(t *testing.T) { d := New(90000) i := uint32(4294877296) + secs := time.Duration(0) pts := d.Decode(i) require.Equal(t, time.Duration(0), pts) - // 1st overflow - i += 90000 * 2 - pts = d.Decode(i) - require.Equal(t, 2*time.Second, pts) + const stride = 150 + lim := uint32(uint64(4294967296 - (stride * 90000))) - // reach 4294890000 slowly - for ; i < 4294890000; i += 90000 * 10 { + for n := 0; n < 100; n++ { + // overflow + i += 90000 * stride + secs += stride 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) - // 2nd overflow - i += 90000 * 10 - pts = d.Decode(i) - require.Equal(t, 47732*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 + } + } } func TestOverflowAndBack(t *testing.T) {