rtptimedec: improve performance

This commit is contained in:
aler9
2022-10-09 11:14:20 +02:00
parent b3c70f56f7
commit 74f941be71
2 changed files with 58 additions and 22 deletions

View File

@@ -5,11 +5,14 @@ import (
"time" "time"
) )
const negativeThreshold = 0xFFFFFFF
// 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 initialized bool
tsPrev int64 tsOverall time.Duration
tsPrev uint32
} }
// New allocates a Decoder. // New allocates a Decoder.
@@ -21,31 +24,27 @@ func New(clockRate int) *Decoder {
// Decode decodes a RTP timestamp. // Decode decodes a RTP timestamp.
func (d *Decoder) Decode(ts uint32) time.Duration { func (d *Decoder) Decode(ts uint32) time.Duration {
ts64 := int64(ts) if !d.initialized {
d.initialized = true
if d.tsAdd == nil { d.tsPrev = ts
d.tsPrev = ts64
ts64 = -ts64
d.tsAdd = &ts64
return 0 return 0
} }
diff := ts64 - d.tsPrev diff := ts - d.tsPrev
d.tsPrev = ts64
switch { // negative difference
case diff < -0xFFFFFF: // overflow if diff > negativeThreshold {
*d.tsAdd += 0x100000000 diff = d.tsPrev - ts
d.tsPrev = ts
case diff > 0xFFFFFF: // timestamp overflowed then went back d.tsOverall -= time.Duration(diff)
*d.tsAdd -= 0x100000000 } 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: // avoid an int64 overflow and preserve resolution by splitting division into two parts:
// first add seconds, then the decimal part. // first add the integer part, then the decimal part.
secs := tot / d.clockRate secs := d.tsOverall / d.clockRate
dec := tot % d.clockRate dec := d.tsOverall % d.clockRate
return secs*time.Second + dec*time.Second/d.clockRate return secs*time.Second + dec*time.Second/d.clockRate
} }

View File

@@ -7,6 +7,26 @@ import (
"github.com/stretchr/testify/require" "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) { func TestOverflow(t *testing.T) {
d := New(90000) d := New(90000)
@@ -57,3 +77,20 @@ func TestOverflowAndBack(t *testing.T) {
pts = d.Decode(90000) pts = d.Decode(90000)
require.Equal(t, 2*time.Second, pts) 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)
}
}()
}
}