mirror of
https://github.com/aler9/gortsplib
synced 2025-10-06 15:46:51 +08:00
rtptimedec: improve performance
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -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)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user