1
Fork 0
mirror of https://github.com/jech/galene.git synced 2024-11-24 17:45:58 +01:00

Rework handling of buffered keyframes.

Instead of buffering the last keyframe, we merely keep track of its
seqno, and use the main cache for recovering.  We also send the whole
sequence of packets rather than just the keyframe itself.
This commit is contained in:
Juliusz Chroboczek 2021-08-04 02:25:56 +02:00
parent f4aa86a491
commit 9093339b62
3 changed files with 35 additions and 282 deletions

View file

@ -38,13 +38,6 @@ type bitmap struct {
bitmap uint32 bitmap uint32
} }
// frame is used for storing the last keyframe
type frame struct {
timestamp uint32
complete bool
entries []entry
}
type Cache struct { type Cache struct {
mu sync.Mutex mu sync.Mutex
//stats //stats
@ -55,10 +48,11 @@ type Cache struct {
totalExpected uint32 totalExpected uint32
received uint32 received uint32
totalReceived uint32 totalReceived uint32
// last seen keyframe
keyframe uint16
keyframeValid bool
// bitmap // bitmap
bitmap bitmap bitmap bitmap
// buffered keyframe
keyframe frame
// the actual cache // the actual cache
tail uint16 tail uint16
entries []entry entries []entry
@ -162,94 +156,6 @@ func (bitmap *bitmap) get(next uint16) (bool, uint16, uint16) {
return true, first, uint16(bm >> 1) return true, first, uint16(bm >> 1)
} }
// insert inserts a packet into a frame.
func (frame *frame) insert(seqno uint16, timestamp uint32, marker bool, data []byte) bool {
n := len(frame.entries)
i := 0
if n == 0 || seqno > frame.entries[n-1].seqno {
// fast path
i = n
} else {
for i < n {
if frame.entries[i].seqno >= seqno {
break
}
i++
}
if i < n && frame.entries[i].seqno == seqno {
// duplicate
return false
}
}
if n >= maxFrame {
// overflow
return false
}
lam := uint16(len(data))
if marker {
lam |= 0x8000
}
e := entry{
seqno: seqno,
lengthAndMarker: lam,
timestamp: timestamp,
}
copy(e.buf[:], data)
if i >= n {
frame.entries = append(frame.entries, e)
return true
}
frame.entries = append(frame.entries, entry{})
copy(frame.entries[i+1:], frame.entries[i:])
frame.entries[i] = e
return true
}
// store checks whether a packet is part of the current keyframe and, if
// so, inserts it.
func (frame *frame) store(seqno uint16, timestamp uint32, first bool, marker bool, data []byte) bool {
if first {
if frame.timestamp != timestamp {
frame.timestamp = timestamp
frame.complete = false
frame.entries = frame.entries[:0]
}
} else if len(frame.entries) > 0 {
if frame.timestamp != timestamp {
delta := seqno - frame.entries[0].seqno
if (delta&0x8000) == 0 && delta > 0x4000 {
frame.complete = false
frame.entries = frame.entries[:0]
}
return false
}
} else {
return false
}
done := frame.insert(seqno, timestamp, marker, data)
if done && !frame.complete {
marker := false
fst := frame.entries[0].seqno
for i := 1; i < len(frame.entries); i++ {
if frame.entries[i].seqno != fst+uint16(i) {
return done
}
if frame.entries[i].marker() {
marker = true
}
}
if marker {
frame.complete = true
}
}
return done
}
// Store stores a packet in the cache. It returns the first seqno in the // Store stores a packet in the cache. It returns the first seqno in the
// bitmap, and the index at which the packet was stored. // bitmap, and the index at which the packet was stored.
func (cache *Cache) Store(seqno uint16, timestamp uint32, keyframe bool, marker bool, buf []byte) (uint16, uint16) { func (cache *Cache) Store(seqno uint16, timestamp uint32, keyframe bool, marker bool, buf []byte) (uint16, uint16) {
@ -270,6 +176,10 @@ func (cache *Cache) Store(seqno uint16, timestamp uint32, keyframe bool, marker
cache.cycle++ cache.cycle++
} }
cache.last = seqno cache.last = seqno
if cache.keyframeValid &&
compare(cache.keyframe, seqno) > 0 {
cache.keyframeValid = false
}
} else if cmp > 0 { } else if cmp > 0 {
if cache.received < cache.expected { if cache.received < cache.expected {
cache.received++ cache.received++
@ -278,9 +188,9 @@ func (cache *Cache) Store(seqno uint16, timestamp uint32, keyframe bool, marker
} }
cache.bitmap.set(seqno) cache.bitmap.set(seqno)
done := cache.keyframe.store(seqno, timestamp, keyframe, marker, buf) if keyframe {
if done && !cache.keyframe.complete { cache.keyframe = seqno
completeKeyframe(cache) cache.keyframeValid = true
} }
i := cache.tail i := cache.tail
@ -297,58 +207,6 @@ func (cache *Cache) Store(seqno uint16, timestamp uint32, keyframe bool, marker
return cache.bitmap.first, i return cache.bitmap.first, i
} }
// completeKeyFrame attempts to complete the current keyframe.
func completeKeyframe(cache *Cache) {
l := len(cache.keyframe.entries)
if l == 0 {
return
}
first := cache.keyframe.entries[0].seqno
last := cache.keyframe.entries[l-1].seqno
count := (last - first) // may wrap around
if count > 0x4000 {
// this shouldn't happen
return
}
var buf []byte
if count > 1 {
if buf == nil {
buf = make([]byte, BufSize)
}
for i := uint16(1); i < count; i++ {
n, ts, marker := get(first+i, cache.entries, buf)
if n > 0 {
cache.keyframe.store(
first+i, ts, false, marker, buf,
)
}
}
}
if !cache.keyframe.complete {
// Try to find packets after the last one.
for {
l := len(cache.keyframe.entries)
if cache.keyframe.entries[l-1].marker() {
break
}
if buf == nil {
buf = make([]byte, BufSize)
}
seqno := cache.keyframe.entries[l-1].seqno + 1
n, ts, marker := get(seqno, cache.entries, buf)
if n <= 0 {
break
}
done := cache.keyframe.store(
seqno, ts, false, marker, buf,
)
if !done || marker {
break
}
}
}
}
// Expect records that we expect n additional packets. // Expect records that we expect n additional packets.
func (cache *Cache) Expect(n int) { func (cache *Cache) Expect(n int) {
if n <= 0 { if n <= 0 {
@ -384,12 +242,7 @@ func (cache *Cache) Get(seqno uint16, result []byte) uint16 {
cache.mu.Lock() cache.mu.Lock()
defer cache.mu.Unlock() defer cache.mu.Unlock()
n, _, _ := get(seqno, cache.keyframe.entries, result) n, _, _ := get(seqno, cache.entries, result)
if n > 0 {
return n
}
n, _, _ = get(seqno, cache.entries, result)
if n > 0 { if n > 0 {
return n return n
} }
@ -397,17 +250,13 @@ func (cache *Cache) Get(seqno uint16, result []byte) uint16 {
return 0 return 0
} }
func (cache *Cache) Last() (bool, uint16, uint32) { func (cache *Cache) Last() (uint16, bool) {
cache.mu.Lock() cache.mu.Lock()
defer cache.mu.Unlock() defer cache.mu.Unlock()
if !cache.lastValid { if !cache.lastValid {
return false, 0, 0 return 0, false
} }
len, ts, _ := get(cache.last, cache.entries, nil) return cache.last, true
if len == 0 {
return false, 0, 0
}
return true, cache.last, ts
} }
// GetAt retrieves a packet from the cache assuming it is at the given index. // GetAt retrieves a packet from the cache assuming it is at the given index.
@ -427,32 +276,15 @@ func (cache *Cache) GetAt(seqno uint16, index uint16, result []byte) uint16 {
) )
} }
// Keyframe returns the last buffered keyframe. It returns the frame's // Keyframe returns the seqno of the last seen keyframe
// timestamp and a boolean indicating if the frame is complete. func (cache *Cache) Keyframe() (uint16, bool) {
func (cache *Cache) Keyframe() (uint32, bool, []uint16) {
cache.mu.Lock() cache.mu.Lock()
defer cache.mu.Unlock() defer cache.mu.Unlock()
if len(cache.keyframe.entries) == 0 { if !cache.keyframeValid {
return 0, false, nil return 0, false
} }
return cache.keyframe, true
seqnos := make([]uint16, len(cache.keyframe.entries))
for i := range cache.keyframe.entries {
seqnos[i] = cache.keyframe.entries[i].seqno
}
return cache.keyframe.timestamp, cache.keyframe.complete, seqnos
}
func (cache *Cache) KeyframeSeqno() (bool, uint16, uint32) {
cache.mu.Lock()
defer cache.mu.Unlock()
if len(cache.keyframe.entries) == 0 {
return false, 0, 0
}
return true, cache.keyframe.entries[0].seqno, cache.keyframe.timestamp
} }
func (cache *Cache) resize(capacity int) { func (cache *Cache) resize(capacity int) {

View file

@ -22,7 +22,7 @@ func TestCache(t *testing.T) {
buf2 := randomBuf() buf2 := randomBuf()
cache := New(16) cache := New(16)
found, _, _ := cache.Last() _, found := cache.Last()
if found { if found {
t.Errorf("Found in empty cache") t.Errorf("Found in empty cache")
} }
@ -30,13 +30,12 @@ func TestCache(t *testing.T) {
_, i1 := cache.Store(13, 42, false, false, buf1) _, i1 := cache.Store(13, 42, false, false, buf1)
_, i2 := cache.Store(17, 42, false, false, buf2) _, i2 := cache.Store(17, 42, false, false, buf2)
found, seqno, ts := cache.Last() seqno, found := cache.Last()
if !found { if !found {
t.Errorf("Not found") t.Errorf("Not found")
} }
if seqno != 17 || ts != 42 { if seqno != 17 {
t.Errorf("Expected %v, %v, got %v, %v", t.Errorf("Expected %v, got %v", 17, seqno)
17, 42, seqno, ts)
} }
buf := make([]byte, BufSize) buf := make([]byte, BufSize)
@ -170,84 +169,6 @@ func TestCacheGrowCond(t *testing.T) {
} }
} }
func TestKeyframe(t *testing.T) {
cache := New(16)
packet := make([]byte, 1)
buf := make([]byte, BufSize)
found, _, _ := cache.KeyframeSeqno()
if found {
t.Errorf("Found keyframe in empty cache")
}
cache.Store(7, 57, true, false, packet)
if cache.keyframe.complete {
t.Errorf("Expected false, got true")
}
cache.Store(8, 57, false, true, packet)
if !cache.keyframe.complete {
t.Errorf("Expected true, got false")
}
ts, c, kf := cache.Keyframe()
if ts != 57 || !c || len(kf) != 2 {
t.Errorf("Got %v %v %v, expected %v %v", ts, c, len(kf), 57, 2)
}
found, seqno, ts := cache.KeyframeSeqno()
if !found || seqno != 7 || ts != 57 {
t.Errorf("Got %v %v %v, expected %v %v", found, seqno, ts, 7, 57)
}
for _, i := range kf {
l := cache.Get(i, buf)
if int(l) != len(packet) {
t.Errorf("Couldn't get %v", i)
}
}
for i := 0; i < 32; i++ {
cache.Store(uint16(9+i), uint32(58+i), false, false, packet)
}
ts, c, kf = cache.Keyframe()
if ts != 57 || !c || len(kf) != 2 {
t.Errorf("Got %v %v %v, expected %v %v", ts, c, len(kf), 57, 2)
}
for _, i := range kf {
l := cache.Get(i, buf)
if int(l) != len(packet) {
t.Errorf("Couldn't get %v", i)
}
}
}
func TestKeyframeUnsorted(t *testing.T) {
cache := New(16)
packet := make([]byte, 1)
cache.Store(7, 57, false, false, packet)
cache.Store(9, 57, false, false, packet)
cache.Store(10, 57, false, true, packet)
cache.Store(6, 57, true, false, packet)
_, c, kf := cache.Keyframe()
if len(kf) != 2 || c {
t.Errorf("Got %v %v, expected 2", c, kf)
}
cache.Store(8, 57, false, false, packet)
_, c, kf = cache.Keyframe()
if len(kf) != 5 || !c {
t.Errorf("Got %v %v, expected 5", c, kf)
}
for i, v := range kf {
if v != uint16(i+6) {
t.Errorf("Position %v, expected %v, got %v\n",
i, i+6, v)
}
}
}
func TestBitmap(t *testing.T) { func TestBitmap(t *testing.T) {
value := uint64(0xcdd58f1e035379c0) value := uint64(0xcdd58f1e035379c0)
packet := make([]byte, 1) packet := make([]byte, 1)

View file

@ -206,9 +206,10 @@ func (writer *rtpWriter) add(track conn.DownTrack, add bool, max int) error {
} }
} }
func sendKeyframe(kf []uint16, track conn.DownTrack, cache *packetcache.Cache) { func sendSequence(kf, last uint16, track conn.DownTrack, cache *packetcache.Cache) {
buf := make([]byte, packetcache.BufSize) buf := make([]byte, packetcache.BufSize)
for _, seqno := range kf { seqno := kf
for ((last - seqno) & 0x8000) == 0 {
bytes := cache.Get(seqno, buf) bytes := cache.Get(seqno, buf)
if bytes == 0 { if bytes == 0 {
return return
@ -218,6 +219,7 @@ func sendKeyframe(kf []uint16, track conn.DownTrack, cache *packetcache.Cache) {
if err != nil { if err != nil {
return return
} }
seqno++
} }
} }
@ -253,14 +255,12 @@ func rtpWriterLoop(writer *rtpWriter, track *rtpUpTrack) {
action.track.SetCname(cname) action.track.SetCname(cname)
} }
found, _, lts := track.cache.Last() last, foundLast := track.cache.Last()
kts, _, kf := track.cache.Keyframe() kf, foundKf := track.cache.Keyframe()
if found && len(kf) > 0 { if foundLast && foundKf {
if ((lts-kts)&0x80000000) != 0 || if last-kf < 40 { // modulo 2^16
lts-kts < 2*90000 { go sendSequence(
// we got a recent keyframe kf, last,
go sendKeyframe(
kf,
action.track, action.track,
track.cache, track.cache,
) )
@ -331,11 +331,11 @@ func nackWriter(track *rtpUpTrack) {
// drop any nacks before the last keyframe // drop any nacks before the last keyframe
var cutoff uint16 var cutoff uint16
found, seqno, _ := track.cache.KeyframeSeqno() seqno, found := track.cache.Keyframe()
if found { if found {
cutoff = seqno cutoff = seqno
} else { } else {
last, lastSeqno, _ := track.cache.Last() lastSeqno, last := track.cache.Last()
if !last { if !last {
// NACK on a fresh track? Give up. // NACK on a fresh track? Give up.
return return