From 74f941be7166557d37f75ba631611dbe9cfc610c Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sun, 9 Oct 2022 11:14:20 +0200 Subject: [PATCH] rtptimedec: improve performance --- pkg/rtptimedec/decoder.go | 43 +++++++++++++++++----------------- pkg/rtptimedec/decoder_test.go | 37 +++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/pkg/rtptimedec/decoder.go b/pkg/rtptimedec/decoder.go index a2baa526..97d2bc16 100644 --- a/pkg/rtptimedec/decoder.go +++ b/pkg/rtptimedec/decoder.go @@ -5,11 +5,14 @@ import ( "time" ) +const negativeThreshold = 0xFFFFFFF + // Decoder is a RTP timestamp decoder. type Decoder struct { - clockRate time.Duration - tsAdd *int64 - tsPrev int64 + clockRate time.Duration + initialized bool + tsOverall time.Duration + tsPrev uint32 } // New allocates a Decoder. @@ -21,31 +24,27 @@ func New(clockRate int) *Decoder { // Decode decodes a RTP timestamp. func (d *Decoder) Decode(ts uint32) time.Duration { - ts64 := int64(ts) - - if d.tsAdd == nil { - d.tsPrev = ts64 - ts64 = -ts64 - d.tsAdd = &ts64 + if !d.initialized { + d.initialized = true + d.tsPrev = ts return 0 } - diff := ts64 - d.tsPrev - d.tsPrev = ts64 + diff := ts - d.tsPrev - switch { - case diff < -0xFFFFFF: // overflow - *d.tsAdd += 0x100000000 - - case diff > 0xFFFFFF: // timestamp overflowed then went back - *d.tsAdd -= 0x100000000 + // negative difference + if diff > negativeThreshold { + diff = d.tsPrev - ts + d.tsPrev = ts + d.tsOverall -= time.Duration(diff) + } else { + d.tsPrev = ts + d.tsOverall += time.Duration(diff) } - 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 + // first add the integer part, then the decimal part. + secs := d.tsOverall / d.clockRate + dec := d.tsOverall % 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 dbf7aaa1..5286a070 100644 --- a/pkg/rtptimedec/decoder_test.go +++ b/pkg/rtptimedec/decoder_test.go @@ -7,6 +7,26 @@ import ( "github.com/stretchr/testify/require" ) +func TestNegativeDiff(t *testing.T) { + d := New(90000) + + i := uint32(0) + pts := d.Decode(i) + require.Equal(t, time.Duration(0), pts) + + i += 90000 * 2 + pts = d.Decode(i) + require.Equal(t, 2*time.Second, pts) + + i -= 90000 * 1 + pts = d.Decode(i) + require.Equal(t, 1*time.Second, pts) + + i += 90000 * 2 + pts = d.Decode(i) + require.Equal(t, 3*time.Second, pts) +} + func TestOverflow(t *testing.T) { d := New(90000) @@ -57,3 +77,20 @@ func TestOverflowAndBack(t *testing.T) { pts = d.Decode(90000) require.Equal(t, 2*time.Second, pts) } + +func BenchmarkDecoder(b *testing.B) { + for i := 0; i < b.N; i++ { + func() { + d := New(90000) + n := uint32(0) + for j := 0; j < 200; j++ { + if (j % 2) == 0 { + n += 90000 + } else { + n -= 45000 + } + d.Decode(n) + } + }() + } +}