From 52ac105d6462ff4ddff263c149f8791bcf8b5d27 Mon Sep 17 00:00:00 2001 From: cloudwebrtc Date: Mon, 29 Jun 2026 10:35:30 +0800 Subject: [PATCH] rename GOP to video frame cache group. --- pkg/sfu/buffer/buffer_base.go | 34 +++++++++++++------------- pkg/sfu/buffer/videoframecache_test.go | 4 +-- pkg/sfu/receiver.go | 4 +-- pkg/sfu/receiver_base.go | 8 +++--- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/pkg/sfu/buffer/buffer_base.go b/pkg/sfu/buffer/buffer_base.go index ee759820a..6e5ae9fec 100644 --- a/pkg/sfu/buffer/buffer_base.go +++ b/pkg/sfu/buffer/buffer_base.go @@ -210,9 +210,9 @@ type BufferBase struct { videoFrameCacheEnabled bool videoFrameCacheMaxDuration time.Duration // optional bound on key-frame interval (0 = bucket-bounded only) videoFrameCacheHasKeyFrame bool - videoFrameCacheKeyFrameESN uint64 // ext sequence number of the current GOP's first key-frame packet - videoFrameCacheKeyFrameETS uint64 // ext timestamp of the current GOP's key frame - videoFrameCacheLatestTS uint64 // maximum ext timestamp seen in the current GOP (resets on a new key frame) + videoFrameCacheKeyFrameESN uint64 // ext sequence number of the current video frame cache group's first key-frame packet + videoFrameCacheKeyFrameETS uint64 // ext timestamp of the current video frame cache group's key frame + videoFrameCacheLatestTS uint64 // maximum ext timestamp seen in the current video frame cache group (resets on a new key frame) isPaused bool frameRateCalculator [DefaultMaxLayerSpatial + 1]FrameRateCalculator @@ -555,7 +555,7 @@ func (b *BufferBase) restartStreamLocked(reason string, isDetected bool) { b.StopKeyFrameSeeder() b.stopRTPStats("stream-restart") b.flushExtPacketsLocked() - // the marked GOP references the pre-restart sequence-number base / evicted bucket contents + // the marked video frame cache group references the pre-restart sequence-number base / evicted bucket contents b.videoFrameCacheHasKeyFrame = false // restart @@ -664,7 +664,7 @@ func (b *BufferBase) ReadExtended(buf []byte) (*ExtPacket, error) { // packets are copied - only the key-frame boundary is tracked. maxDuration bounds the served // key-frame interval AND drives the retransmit bucket to retain that much history (see // maybeGrowBucket), so the key frame is not evicted before it can be read; <= 0 keeps the default -// ~1s retransmit window (and bounds the GOP to it). No-op for audio buffers. +// ~1s retransmit window (and bounds the video frame cache group to it). No-op for audio buffers. func (b *BufferBase) EnableVideoFrameCache(maxDuration time.Duration) { b.Lock() defer b.Unlock() @@ -674,15 +674,15 @@ func (b *BufferBase) EnableVideoFrameCache(maxDuration time.Duration) { b.logger.Debugw("video frame cache enabled on buffer", "maxDuration", maxDuration) } -// markVideoFrameCacheLocked records the key-frame boundary of the current GOP and tracks its span. Caller holds +// markVideoFrameCacheLocked records the key-frame boundary of the current video frame cache group and tracks its span. Caller holds // the lock. func (b *BufferBase) markVideoFrameCacheLocked(ep *ExtPacket) { if ep == nil || ep.Packet == nil || len(ep.Packet.Payload) == 0 { return } if ep.IsKeyFrame && (!b.videoFrameCacheHasKeyFrame || ep.ExtTimestamp != b.videoFrameCacheKeyFrameETS) { - // a new key frame starts a new GOP; remember its first packet's sequence number and reset the - // span to the key frame so a stale packet from the previous GOP cannot stretch it + // a new key frame can be used to decoders to reset; remember its first packet's sequence number and reset the + // span to the key frame so a stale packet from the previous video frame cache group cannot stretch it b.videoFrameCacheKeyFrameESN = ep.ExtSequenceNumber b.videoFrameCacheKeyFrameETS = ep.ExtTimestamp b.videoFrameCacheLatestTS = ep.ExtTimestamp @@ -690,21 +690,21 @@ func (b *BufferBase) markVideoFrameCacheLocked(ep *ExtPacket) { b.logger.Debugw("video frame cache: marked key frame", "keyFrameSN", b.videoFrameCacheKeyFrameESN, "keyFrameTS", b.videoFrameCacheKeyFrameETS) return } - // track the maximum timestamp seen in the current GOP (not the last-written one) so an + // track the maximum timestamp seen in the current video frame cache group (not the last-written one) so an // out-of-order, older packet arriving last cannot shrink the measured span and let GetVideoFrameCache serve // more than videoFrameCacheMaxDuration. The head packet's timestamp is always <= videoFrameCacheLatestTS, so the - // duration gate in GetVideoFrameCache strictly bounds the served GOP. + // duration gate in GetVideoFrameCache strictly bounds the served video frame cache group. if ep.ExtTimestamp > b.videoFrameCacheLatestTS { b.videoFrameCacheLatestTS = ep.ExtTimestamp } } // GetVideoFrameCache reads the packets of the current group-of-pictures (from the most recent key frame up to -// the latest packet) back from the retransmit bucket, so a newly attached relay / down track can be +// the latest packet) back from the retransmit bucket, so a newly attached down track can be // bootstrapped without requesting a fresh key frame (PLI). Returns (nil, false) when the cache is // disabled, no key frame has been marked, the key-frame interval exceeds the configured bound, or -// the key frame is no longer retained in the bucket (the GOP length is ultimately bounded by the -// bucket capacity). Lost packets within the GOP are skipped. +// the key frame is no longer retained in the bucket (the video frame cache group length is ultimately bounded by the +// bucket capacity). Lost packets within the video frame cache group are skipped. // // The packets are returned as ExtPackets reconstructed from the bucket bytes so they can be replayed // through the normal forward path (WriteRTP): ExtSequenceNumber comes from the bucket key and @@ -746,7 +746,7 @@ func (b *BufferBase) GetVideoFrameCache() ([]*ExtPacket, bool) { } pkts := b.reconstructPacketsLocked(b.videoFrameCacheKeyFrameESN, headESN) - // the key frame itself must be present (its first packet), otherwise the GOP cannot be served + // the key frame itself must be present (its first packet), otherwise the video frame cache group cannot be served if len(pkts) == 0 || pkts[0].ExtSequenceNumber != b.videoFrameCacheKeyFrameESN { var firstSN uint64 if len(pkts) > 0 { @@ -789,7 +789,7 @@ func (b *BufferBase) GetPacketsAfter(afterESN uint64) ([]*ExtPacket, bool) { // reconstructPacketsLocked builds self-contained ExtPackets for the sequence-number range // [fromSN, headESN] from the retransmit bucket. Lost packets are skipped. ExtTimestamp is -// reconstructed relative to the marked key frame (a GOP spans well under one 32-bit timestamp wrap) +// reconstructed relative to the marked key frame (a video frame cache group spans well under one 32-bit timestamp wrap) // and IsKeyFrame flags packets at the key-frame timestamp. The dependency descriptor is not // reconstructed. Caller holds the lock. func (b *BufferBase) reconstructPacketsLocked(fromSN, headESN uint64) []*ExtPacket { @@ -1412,7 +1412,7 @@ func (b *BufferBase) flushExtPacketsLocked() { // // Normally the target is ~1s of packets (the NACK / retransmit window), bounded by maxPkts. When // videoFrameCacheSizing is set (the video frame cache is enabled with a positive duration), the bucket must retain -// the whole GOP duration plus ~0.5s margin so the key frame is not evicted before it is at most +// the whole video frame cache group duration plus ~0.5s margin so the key frame is not evicted before it is at most // videoFrameCacheMaxDuration old; the cap is raised to fit since the default maxPkts is only ~1s worth. func bucketGrowTarget(pps, maxPkts int, videoFrameCacheSizing bool, videoFrameCacheMaxDuration time.Duration) (targetPkts, effectiveMaxPkts int) { targetPkts = pps @@ -1444,7 +1444,7 @@ func (b *BufferBase) maybeGrowBucket(now int64) { maxPkts = b.params.MaxAudioPkts } - // when the video frame cache is enabled the bucket must retain the whole configured GOP + // when the video frame cache is enabled the bucket must retain the whole configured video frame cache group // duration (the key frame must survive until GetVideoFrameCache reads it), which is more than the normal // ~1s retransmit window. In that case the target / cap are computed below from pps; otherwise // keep the original fast path. diff --git a/pkg/sfu/buffer/videoframecache_test.go b/pkg/sfu/buffer/videoframecache_test.go index f247604b0..0c3271085 100644 --- a/pkg/sfu/buffer/videoframecache_test.go +++ b/pkg/sfu/buffer/videoframecache_test.go @@ -77,7 +77,7 @@ func TestVideoFrameCacheReadsFromBucket(t *testing.T) { b.markVideoFrameCacheLocked(videoFrameCacheMarkPkt(103, 4000, false)) b.markVideoFrameCacheLocked(videoFrameCacheMarkPkt(104, 5000, false)) - // GOP is [key frame .. head] = 101..104 + // video frame cache group is [key frame .. head] = 101..104 pkts, ok := b.GetVideoFrameCache() require.True(t, ok) require.Len(t, pkts, 4) @@ -179,7 +179,7 @@ func TestVideoFrameCacheSpanUsesMaxTimestamp(t *testing.T) { b.markVideoFrameCacheLocked(videoFrameCacheMarkPkt(102, 1100, false)) require.Equal(t, uint64(1200), b.videoFrameCacheLatestTS) - // a new key frame resets the span to itself (a stale packet cannot stretch the new GOP) + // a new key frame resets the span to itself (a stale packet cannot stretch the new video frame cache group) b.markVideoFrameCacheLocked(videoFrameCacheMarkPkt(103, 5000, true)) require.Equal(t, uint64(5000), b.videoFrameCacheLatestTS) b.markVideoFrameCacheLocked(videoFrameCacheMarkPkt(104, 4000, false)) // stale, older than the new key frame diff --git a/pkg/sfu/receiver.go b/pkg/sfu/receiver.go index 3bdb518ba..72e11ae57 100644 --- a/pkg/sfu/receiver.go +++ b/pkg/sfu/receiver.go @@ -93,12 +93,12 @@ func WithForwardStats(forwardStats *ForwardStats) ReceiverOpts { } } -// DefaultVideoFrameCacheMaxDuration bounds the cached GOP (and sizes the retransmit bucket) when the video +// DefaultVideoFrameCacheMaxDuration bounds the cached video frame cache group (and sizes the retransmit bucket) when the video // frame cache is enabled via WithVideoFrameCache. const DefaultVideoFrameCacheMaxDuration = 1 * time.Second // WithVideoFrameCache enables the video frame cache on the receiver so a newly added down track is -// bootstrapped by replaying the cached GOP instead of triggering a PLI. maxDuration bounds the +// bootstrapped by replaying the cached video frame cache group instead of triggering a PLI. maxDuration bounds the // cached video frame (<= 0 uses DefaultVideoFrameCacheMaxDuration). No-op for audio receivers. func WithVideoFrameCache(maxDuration time.Duration) ReceiverOpts { return func(w *WebRTCReceiver) *WebRTCReceiver { diff --git a/pkg/sfu/receiver_base.go b/pkg/sfu/receiver_base.go index e02033f7c..2b4a6f958 100644 --- a/pkg/sfu/receiver_base.go +++ b/pkg/sfu/receiver_base.go @@ -623,15 +623,15 @@ func (r *ReceiverBase) EnableVideoFrameCache(maxDuration time.Duration) { // pathological case where live keeps outrunning the replay). const videoFrameCacheReplayMaxCatchupRounds = 8 -// replayVideoFrameCache bootstraps a freshly added down track by replaying the publisher's cached GOP, then the +// replayVideoFrameCache bootstraps a freshly added down track by replaying the publisher's cached video frame cache group, then the // packets accumulated since, until it catches up to the live forwarding point. Packets are paced at // half the (estimated) video frame interval so the replay runs at ~2x real time and converges on // live. It writes directly to the track (which is not yet in the live broadcast), so there is no // interleaving with live packets. // -// It replays the highest spatial layer that currently has a cached GOP: a subscriber requesting full +// It replays the highest spatial layer that currently has a cached video frame cache group: a subscriber requesting full // quality has its forwarder targeting the top layer, and lower layers may not even be flowing (e.g. -// paused by dynacast), so layer 0 often has no GOP. +// paused by dynacast), so layer 0 often has no video frame cache group. func (r *ReceiverBase) replayVideoFrameCache(track TrackSender) { var ( buff buffer.BufferProvider @@ -650,7 +650,7 @@ func (r *ReceiverBase) replayVideoFrameCache(track TrackSender) { } if layer == buffer.InvalidLayerSpatial { - // no usable GOP cached on any layer - the down track falls back to requesting a key frame (PLI) + // no usable video frame cache group cached on any layer - the down track falls back to requesting a key frame (PLI) missCount := r.videoFrameCacheMissCount.Inc() r.params.Logger.Debugw( "subscriber bootstrap: video frame cache miss, falling back to PLI",