1use std::collections::VecDeque;
5
6pub const REFERENCE_FRAMES: u32 = 8;
9
10pub const ANCHORS: usize = 2;
13
14const ANCHOR_EVERY: u64 = 12;
17
18const ANCHOR_ALONE_EVERY: u64 = 48;
21
22const SETTLE_SLACK: u64 = 4;
29
30const SETTLE_RECENT: usize = 2;
39
40const PENDING_PERIODS: u64 = 4;
44
45const HOLD_LAG: u64 = ANCHOR_ALONE_EVERY / 2;
51const HOLD_MAX: u64 = 8 * ANCHOR_ALONE_EVERY;
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub enum ReferenceReport {
56 Lost(u16),
58 Held(u16),
60 Sent(u16),
62}
63
64#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
66pub enum Reference {
67 #[default]
69 Untracked,
70 None,
72 Frame(u16),
74}
75
76impl Reference {
77 pub fn frame_id(self) -> i32 {
80 match self {
81 Reference::Untracked => -2,
82 Reference::None => -1,
83 Reference::Frame(id) => id as i32,
84 }
85 }
86}
87
88#[derive(Debug, PartialEq, Eq)]
90pub enum Invalidation {
91 Ignored,
93 Forget(u64),
95 KeyFrame,
98}
99
100pub struct ReferenceWindow {
128 frames: VecDeque<(u16, u64, bool)>,
129 capacity: usize,
130 lends: bool,
131 anchors: Vec<Option<(u16, u64, bool)>>,
132 recent: VecDeque<(u16, u64, bool)>,
133 next_pts: u64,
134 age: KeyAge,
135 key_pts: u64,
136 frame_num_range: u64,
137 acknowledged: bool,
138 common: VecDeque<u64>,
139 sent: VecDeque<u64>,
140}
141
142#[derive(Default)]
147struct KeyAge {
148 newest: u16,
149 since_key: u64,
150}
151
152impl KeyAge {
153 fn record(&mut self, frame_id: u16, key: bool) {
154 self.since_key = if key {
155 0
156 } else {
157 self.since_key + frame_id.wrapping_sub(self.newest) as u64
158 };
159 self.newest = frame_id;
160 }
161
162 fn behind(&self, frame_id: u16) -> Option<u64> {
165 let behind = self.newest.wrapping_sub(frame_id) as u64;
166 (behind < 0x8000 && behind <= self.since_key).then_some(behind)
167 }
168}
169
170impl ReferenceWindow {
171 pub fn new(capacity: u32) -> Self {
172 Self {
173 frames: VecDeque::new(),
174 capacity: capacity.max(1) as usize,
175 lends: false,
176 anchors: Vec::new(),
177 recent: VecDeque::new(),
178 next_pts: 0,
179 age: KeyAge::default(),
180 key_pts: 0,
181 frame_num_range: 0,
182 acknowledged: false,
183 common: VecDeque::new(),
184 sent: VecDeque::new(),
185 }
186 }
187
188 pub fn with_anchors(capacity: u32, count: usize) -> Self {
191 let mut w = Self::new(capacity);
192 w.anchors = vec![None; count.clamp(1, ANCHORS)];
193 w.set_capacity(capacity);
194 w
195 }
196
197 pub fn lend_free_anchors(&mut self) {
200 self.lends = true;
201 }
202
203 fn recent_capacity(&self) -> usize {
206 let free = self
207 .anchors
208 .iter()
209 .filter(|a| a.is_none_or(|a| a.2))
210 .count();
211 self.capacity + if self.lends { free } else { 0 }
212 }
213
214 pub fn anchored(&self) -> bool {
216 !self.anchors.is_empty()
217 }
218
219 pub fn anchor_count(&self) -> usize {
221 self.anchors.len()
222 }
223
224 pub fn plan_anchor(&self, key: bool) -> Option<u8> {
231 if self.anchors.is_empty() {
232 return None;
233 }
234 if key || !self.has_reference() || self.anchors.iter().all(Option::is_none) {
235 return Some(0);
236 }
237 let wraps = self.wraps_next();
238 if !(self.next_pts - self.key_pts).is_multiple_of(self.anchor_period()) && !wraps {
239 return None;
240 }
241 if self.anchors.len() == 1 && self.acknowledged && !wraps && self.reaches_back() {
242 return None;
243 }
244 if self.anchors.len() == 1
245 && self.acknowledged
246 && !wraps
247 && let Some((_, pts, false)) = self.anchors[0]
248 && self.is_common(pts)
249 {
250 let held = self
251 .common
252 .back()
253 .map_or(self.key_pts, |&c| c.max(self.key_pts));
254 let sent = self.sent.back().map_or(held, |&s| s.max(held));
255 if sent - held > HOLD_LAG && self.next_pts - pts < HOLD_MAX {
256 return None;
257 }
258 }
259 let rank = |a: &Option<(u16, u64, bool)>| {
260 a.map_or((0, 0), |(_, pts, lost)| (u8::from(!lost), pts))
261 };
262 let pinned = self.pinned_anchor();
263 let pending = |a: &Option<(u16, u64, bool)>| {
264 a.is_some_and(|(_, pts, lost)| {
265 !lost
266 && self.is_shared(pts)
267 && !self.is_common(pts)
268 && self.next_pts - pts < PENDING_PERIODS * self.anchor_period()
269 })
270 };
271 (0..self.anchors.len())
272 .filter(|&i| self.anchors.len() == 1 || Some(i) != pinned)
273 .filter(|&i| wraps || !pending(&self.anchors[i]))
274 .min_by_key(|&i| rank(&self.anchors[i]))
275 .map(|i| i as u8)
276 }
277
278 fn reaches_back(&self) -> bool {
284 self.newest_valid()
285 .is_some_and(|(_, pts)| !self.is_shared(pts))
286 && !self.frames.iter().any(|f| !f.2 && self.is_shared(f.1))
287 && self
288 .anchor_frames()
289 .filter(|a| !a.2)
290 .map(|a| a.1)
291 .max()
292 .is_some_and(|pts| self.next_pts - pts < HOLD_MAX)
293 }
294
295 fn anchor_period(&self) -> u64 {
297 if self.anchors.len() == 1 {
298 ANCHOR_ALONE_EVERY
299 } else {
300 ANCHOR_EVERY
301 }
302 }
303
304 fn wraps_next(&self) -> bool {
306 self.acknowledging()
307 && self.frame_num_range > 0
308 && (self.next_pts - self.key_pts).is_multiple_of(self.frame_num_range)
309 }
310
311 pub fn set_acknowledged(&mut self) {
313 self.acknowledged = true;
314 }
315
316 pub fn acknowledge(&mut self, frame_id: u16, held: bool) -> bool {
319 self.acknowledged = true;
320 let Some(&(_, pts, lost)) = self.recent.iter().rev().find(|f| f.0 == frame_id) else {
321 return false;
322 };
323 if lost || pts < self.key_pts {
324 return false;
325 }
326 let noted = if held {
327 &mut self.common
328 } else {
329 &mut self.sent
330 };
331 if let Err(at) = noted.binary_search(&pts) {
332 noted.insert(at, pts);
333 }
334 while noted.len() > RECENT_FRAMES {
335 noted.pop_front();
336 }
337 true
338 }
339
340 pub fn acknowledging(&self) -> bool {
342 self.acknowledged
343 }
344
345 fn is_common(&self, pts: u64) -> bool {
349 pts == self.key_pts
350 || (self.acknowledged && self.kept(pts))
351 || self.common.binary_search(&pts).is_ok()
352 }
353
354 fn kept(&self, pts: u64) -> bool {
358 self.frame_num_range > 0
359 && pts > self.key_pts
360 && (pts - self.key_pts).is_multiple_of(self.frame_num_range)
361 }
362
363 fn is_shared(&self, pts: u64) -> bool {
365 self.is_common(pts) || self.sent.binary_search(&pts).is_ok()
366 }
367
368 pub fn predicts_from_shared(&self) -> bool {
371 self.newest_valid()
372 .is_some_and(|(_, pts)| self.is_shared(pts))
373 }
374
375 fn pinned_anchor(&self) -> Option<usize> {
377 if !self.acknowledged {
378 return None;
379 }
380 self.anchors
381 .iter()
382 .enumerate()
383 .filter_map(|(i, a)| a.filter(|f| !f.2 && self.is_common(f.1)).map(|f| (i, f.1)))
384 .max_by_key(|&(_, pts)| pts)
385 .map(|(i, _)| i)
386 }
387
388 pub fn settle(&mut self) -> Option<Invalidation> {
394 if !self.acknowledging() {
395 return None;
396 }
397 let wraps = self.wraps_next();
400 let usable = |w: &Self, pts: u64| {
401 if wraps {
402 w.is_common(pts)
403 } else {
404 w.is_shared(pts)
405 }
406 };
407 let (_, newest) = self.newest_valid()?;
408 if usable(self, newest) {
409 return None;
410 }
411 let shared = self
412 .held()
413 .filter(|f| !f.2 && usable(self, f.1))
414 .map(|f| f.1)
415 .max()?;
416 if !wraps && self.next_pts - shared > self.anchor_period() + SETTLE_SLACK {
417 return None;
418 }
419 if self.anchors.len() > 1
420 && !wraps
421 && !self
422 .frames
423 .iter()
424 .rev()
425 .filter(|f| !f.2)
426 .take(SETTLE_RECENT)
427 .any(|f| f.1 == shared)
428 {
429 return None;
430 }
431 let &(first, _, _) = self.recent.iter().find(|f| f.1 > shared && !f.2)?;
432 Some(self.invalidate(first))
433 }
434
435 pub fn forget_stale(&mut self) -> Option<Invalidation> {
445 if self.frame_num_range == 0 || self.anchors.is_empty() {
446 return None;
447 }
448 let (_, newest) = self.newest_valid()?;
449 let recent = self.frames.iter().any(|f| f.1 == newest && !f.2);
450 if !recent || self.next_pts - newest <= self.capacity as u64 {
451 return None;
452 }
453 let target = self
454 .anchor_frames()
455 .filter(|a| !a.2 && (!self.acknowledged || self.is_shared(a.1)))
456 .map(|a| a.1)
457 .max();
458 let first = match target {
459 Some(anchor) => self.recent.iter().find(|f| f.1 > anchor && !f.2)?.0,
460 None => self.frames.iter().find(|f| !f.2)?.0,
461 };
462 Some(self.invalidate(first))
463 }
464
465 pub fn predicting_anchor(&self) -> Option<u8> {
468 let (_, pts) = self.newest_valid()?;
469 if self.frames.iter().any(|f| f.1 == pts && !f.2) {
470 return None;
471 }
472 self.anchors
473 .iter()
474 .position(|a| a.is_some_and(|a| a.1 == pts && !a.2))
475 .map(|i| i as u8)
476 }
477
478 pub fn anchor_slot(&self, pts: u64) -> Option<u8> {
481 self.anchors
482 .iter()
483 .position(|a| a.is_some_and(|a| a.1 == pts))
484 .map(|i| i as u8)
485 }
486
487 pub fn set_frame_num_range(&mut self, range: u32) {
490 self.frame_num_range = range as u64;
491 }
492
493 pub fn reset(&mut self) {
495 self.frames.clear();
496 self.anchors.iter_mut().for_each(|a| *a = None);
497 self.recent.clear();
498 self.common.clear();
499 self.sent.clear();
500 }
501
502 pub fn set_capacity(&mut self, capacity: u32) {
505 self.capacity = capacity.saturating_sub(self.anchors.len() as u32).max(1) as usize;
506 while self.frames.len() > self.recent_capacity() {
507 self.frames.pop_front();
508 }
509 }
510
511 pub fn next_pts(&self) -> u64 {
513 self.next_pts
514 }
515
516 fn anchor_frames(&self) -> impl Iterator<Item = (u16, u64, bool)> + '_ {
518 self.anchors.iter().flatten().copied()
519 }
520
521 pub fn has_reference(&self) -> bool {
523 self.frames
524 .iter()
525 .copied()
526 .chain(self.anchor_frames())
527 .any(|f| !f.2)
528 }
529
530 pub fn newest_valid(&self) -> Option<(u16, u64)> {
533 let held = self.frames.iter().copied().chain(self.anchor_frames());
534 held.filter(|f| !f.2)
535 .max_by_key(|f| f.1)
536 .map(|f| (f.0, f.1))
537 }
538
539 pub fn held(&self) -> impl Iterator<Item = (u16, u64, bool)> + '_ {
542 let mut anchors: Vec<_> = self.anchor_frames().collect();
544 anchors.sort_by_key(|f| std::cmp::Reverse(f.1));
545 let mut frames = self.frames.iter().copied().peekable();
546 std::iter::from_fn(move || {
547 if anchors
548 .last()
549 .is_some_and(|a| frames.peek().is_none_or(|f| a.1 < f.1))
550 {
551 anchors.pop()
552 } else {
553 frames.next()
554 }
555 })
556 }
557
558 pub fn key_pts(&self) -> u64 {
560 self.key_pts
561 }
562
563 pub fn record(&mut self, frame_id: u16, key: bool) -> Reference {
565 self.record_marked(frame_id, key, None)
566 }
567
568 pub fn record_marked(&mut self, frame_id: u16, key: bool, anchor: Option<u8>) -> Reference {
571 let pts = self.next_pts;
572 self.next_pts += 1;
573 self.age.record(frame_id, key);
574 let reference = if key {
575 self.frames.clear();
576 self.anchors.iter_mut().for_each(|a| *a = None);
577 self.common.clear();
578 self.sent.clear();
579 self.key_pts = pts;
580 Reference::None
581 } else {
582 self.newest_valid()
583 .map_or(Reference::None, |(id, _)| Reference::Frame(id))
584 };
585 match anchor.and_then(|slot| self.anchors.get_mut(slot as usize)) {
586 Some(slot) => *slot = Some((frame_id, pts, false)),
587 None => self.frames.push_back((frame_id, pts, false)),
588 }
589 while self.frames.len() > self.recent_capacity() {
590 self.frames.pop_front();
591 }
592 self.recent.push_back((frame_id, pts, false));
593 if self.recent.len() > RECENT_FRAMES {
594 self.recent.pop_front();
595 }
596 reference
597 }
598
599 pub fn retract(&mut self, forget: impl FnOnce(u64) -> bool) -> bool {
605 let Some(pts) = self.next_pts.checked_sub(1) else {
606 return false;
607 };
608 let older = self
609 .frames
610 .iter()
611 .copied()
612 .chain(self.anchor_frames())
613 .any(|f| !f.2 && f.1 < pts);
614 let wraps =
615 self.frame_num_range > 0 && (pts - self.key_pts).is_multiple_of(self.frame_num_range);
616 if !older || wraps || !forget(pts) {
617 return false;
618 }
619 let held = self
620 .frames
621 .iter_mut()
622 .chain(self.anchors.iter_mut().flatten());
623 for f in held.chain(self.recent.iter_mut()).filter(|f| f.1 == pts) {
624 f.2 = true;
625 }
626 true
627 }
628
629 pub fn invalidate(&mut self, frame_id: u16) -> Invalidation {
634 if self
635 .recent
636 .iter()
637 .rev()
638 .find(|f| f.0 == frame_id)
639 .is_some_and(|f| f.2)
640 {
641 return Invalidation::Ignored;
642 }
643 let action = if self.anchored() {
644 self.invalidate_anchored(frame_id)
645 } else {
646 self.invalidate_recent(frame_id)
647 };
648 let cut = match action {
649 Invalidation::Forget(pts) => pts,
650 Invalidation::KeyFrame => self.key_pts,
651 Invalidation::Ignored => return action,
652 };
653 for f in self.recent.iter_mut().filter(|f| f.1 >= cut) {
654 f.2 = true;
655 }
656 action
657 }
658
659 fn invalidate_recent(&mut self, frame_id: u16) -> Invalidation {
661 let Some(&(oldest, _, _)) = self.frames.front() else {
662 return Invalidation::Ignored;
663 };
664 match self.frames.iter().rposition(|f| f.0 == frame_id) {
666 Some(at) => {
667 let pts = self.frames[at].1;
668 let wraps = self.frame_num_range > 0
669 && self
670 .frames
671 .iter()
672 .skip(at)
673 .any(|f| (f.1 - self.key_pts).is_multiple_of(self.frame_num_range));
674 for f in self.frames.iter_mut().skip(if wraps { 0 } else { at }) {
675 f.2 = true;
676 }
677 if wraps {
678 Invalidation::KeyFrame
679 } else {
680 Invalidation::Forget(pts)
681 }
682 }
683 None if self
684 .age
685 .behind(frame_id)
686 .is_some_and(|b| b > self.age.newest.wrapping_sub(oldest) as u64) =>
687 {
688 for f in self.frames.iter_mut() {
689 f.2 = true;
690 }
691 Invalidation::KeyFrame
692 }
693 None => Invalidation::Ignored,
694 }
695 }
696
697 fn invalidate_anchored(&mut self, frame_id: u16) -> Invalidation {
700 let remembered = self
701 .recent
702 .iter()
703 .rev()
704 .find(|r| r.0 == frame_id)
705 .map(|r| r.1);
706 let lost_pts = match remembered {
707 Some(pts) if pts >= self.key_pts => pts,
708 Some(_) => return Invalidation::Ignored,
709 None => {
710 let Some(&(oldest, _, _)) = self.recent.front() else {
713 return Invalidation::Ignored;
714 };
715 if !self
716 .age
717 .behind(frame_id)
718 .is_some_and(|b| b > self.age.newest.wrapping_sub(oldest) as u64)
719 {
720 return Invalidation::Ignored;
721 }
722 self.key_pts
723 }
724 };
725 let newest = self.next_pts.saturating_sub(1);
726 let range = self.frame_num_range;
728 let wraps =
729 range > 0 && (lost_pts - self.key_pts).div_ceil(range) * range <= newest - self.key_pts;
730 let cut = if wraps { 0 } else { lost_pts };
731 for f in self.frames.iter_mut().filter(|f| f.1 >= cut) {
732 f.2 = true;
733 }
734 for a in self.anchors.iter_mut().flatten().filter(|a| a.1 >= cut) {
735 a.2 = true;
736 }
737 if wraps || !self.has_reference() {
738 Invalidation::KeyFrame
739 } else {
740 Invalidation::Forget(lost_pts)
741 }
742 }
743}
744
745pub struct ReferenceSlots {
759 slots: [Option<(u16, u64, bool)>; 8],
760 count: usize,
761 recent: VecDeque<(u16, u64)>,
762 next_pts: u64,
763 age: KeyAge,
764 key_pts: u64,
765 acknowledged: bool,
766 common: VecDeque<u64>,
767 sent: VecDeque<u64>,
768}
769
770const RECENT_FRAMES: usize = 512;
774
775const ANCHOR_PERIOD: u64 = 24;
777
778const RING: u64 = 4;
780
781#[derive(Clone, Copy, Debug, PartialEq, Eq)]
784pub struct SlotRefresh(pub u8);
785
786impl SlotRefresh {
787 pub const LAST: u8 = 1;
788 pub const GOLDEN: u8 = 2;
789 pub const ALTREF: u8 = 4;
790 pub const ALL: u8 = 7;
791
792 pub fn refreshes(self, slot: u8) -> bool {
793 self.0 & slot != 0
794 }
795}
796
797#[derive(Clone, Copy, Debug, PartialEq, Eq)]
799pub struct SlotPlan {
800 pub predict_from: u8,
802 pub refresh: SlotRefresh,
803}
804
805impl SlotPlan {
806 pub const KEY: Self = Self {
808 predict_from: 0,
809 refresh: SlotRefresh(SlotRefresh::ALL),
810 };
811}
812
813impl Default for ReferenceSlots {
814 fn default() -> Self {
815 Self::new()
816 }
817}
818
819impl ReferenceSlots {
820 pub fn new() -> Self {
822 Self::with(3)
823 }
824
825 pub fn vp9() -> Self {
827 Self::with(8)
828 }
829
830 fn with(count: usize) -> Self {
831 Self {
832 slots: [None; 8],
833 count,
834 recent: VecDeque::new(),
835 next_pts: 0,
836 age: KeyAge::default(),
837 key_pts: 0,
838 acknowledged: false,
839 common: VecDeque::new(),
840 sent: VecDeque::new(),
841 }
842 }
843
844 pub fn next_pts(&self) -> u64 {
846 self.next_pts
847 }
848
849 pub fn acknowledge(&mut self, frame_id: u16, held: bool) -> bool {
854 self.acknowledged = true;
855 let Some(&(_, pts)) = self.recent.iter().rev().find(|f| f.0 == frame_id) else {
856 return false;
857 };
858 if pts < self.key_pts {
859 return false;
860 }
861 let noted = if held {
862 &mut self.common
863 } else {
864 &mut self.sent
865 };
866 if let Err(at) = noted.binary_search(&pts) {
867 noted.insert(at, pts);
868 }
869 while noted.len() > RECENT_FRAMES {
870 noted.pop_front();
871 }
872 true
873 }
874
875 fn is_common(&self, pts: u64) -> bool {
876 pts == self.key_pts || self.common.binary_search(&pts).is_ok()
877 }
878
879 fn is_shared(&self, pts: u64) -> bool {
880 self.is_common(pts) || self.sent.binary_search(&pts).is_ok()
881 }
882
883 fn anchor_slots(&self) -> std::ops::Range<usize> {
885 if self.count > 3 {
886 RING as usize..self.count
887 } else {
888 1..3
889 }
890 }
891
892 fn anchor_every(&self) -> u64 {
894 if self.count > 3 {
895 RING
896 } else {
897 ANCHOR_PERIOD / 2
898 }
899 }
900
901 fn anchor_target(&self) -> Option<usize> {
906 let pinned = self
907 .anchor_slots()
908 .filter_map(|i| {
909 self.slots[i]
910 .filter(|f| !f.2 && self.is_common(f.1))
911 .map(|f| (i, f.1))
912 })
913 .max_by_key(|&(_, pts)| pts)
914 .map(|(i, _)| i);
915 self.anchor_slots()
916 .filter(|&i| Some(i) != pinned)
917 .filter(|&i| {
918 !self.slots[i].is_some_and(|(_, pts, lost)| {
919 !lost
920 && self.is_shared(pts)
921 && !self.is_common(pts)
922 && self.next_pts - pts < PENDING_PERIODS * self.anchor_every()
923 })
924 })
925 .min_by_key(|&i| self.slots[i].map_or((0, 0), |(_, pts, lost)| (u8::from(!lost), pts)))
926 }
927
928 pub fn shared_anchor(&self, plan: SlotPlan) -> bool {
933 plan.predict_from != 0
934 && (self.next_pts - self.key_pts).is_multiple_of(self.anchor_every())
935 && self.anchor_slots().any(|i| plan.refresh.refreshes(1 << i))
936 && self
937 .slot(plan.predict_from)
938 .is_some_and(|(_, pts, lost)| !lost && self.is_shared(pts))
939 }
940
941 pub fn has_reference(&self) -> bool {
943 self.slots[..self.count]
944 .iter()
945 .any(|s| s.is_some_and(|(_, _, lost)| !lost))
946 }
947
948 pub fn slot(&self, slot: u8) -> Option<(u16, u64, bool)> {
950 self.slots[slot.trailing_zeros() as usize]
951 }
952
953 pub fn plan(&self, key: bool) -> SlotPlan {
956 if key || !self.has_reference() {
957 return SlotPlan {
958 predict_from: 0,
959 refresh: SlotRefresh(((1u16 << self.count) - 1) as u8),
960 };
961 }
962 let mut newest = 0;
963 for i in 0..self.count {
964 if let Some((_, pts, false)) = self.slots[i]
965 && self.slots[newest].is_none_or(|(_, held, lost)| lost || pts > held)
966 {
967 newest = i;
968 }
969 }
970 let predict_from = 1 << newest;
971 let since_key = self.next_pts - self.key_pts;
972 if self.acknowledged {
973 let recent = if self.count > 3 {
976 1 << (since_key % RING)
977 } else {
978 SlotRefresh::LAST
979 };
980 let anchor = since_key.is_multiple_of(self.anchor_every())
981 || self.anchor_slots().contains(&newest);
982 let target = if anchor { self.anchor_target() } else { None };
983 return SlotPlan {
984 predict_from,
985 refresh: SlotRefresh(recent | target.map_or(0, |i| 1 << i)),
986 };
987 }
988 let refresh = if self.count > 3 {
989 1 << (since_key % RING)
990 | if since_key.is_multiple_of(RING) {
991 1 << (RING + since_key / RING % RING)
992 } else {
993 0
994 }
995 } else if predict_from != SlotRefresh::LAST {
996 SlotRefresh::ALL
997 } else {
998 SlotRefresh::LAST
999 | if since_key.is_multiple_of(ANCHOR_PERIOD) {
1000 SlotRefresh::GOLDEN
1001 } else {
1002 0
1003 }
1004 | if since_key % ANCHOR_PERIOD == ANCHOR_PERIOD / 2 {
1005 SlotRefresh::ALTREF
1006 } else {
1007 0
1008 }
1009 };
1010 SlotPlan {
1011 predict_from,
1012 refresh: SlotRefresh(refresh),
1013 }
1014 }
1015
1016 pub fn record(&mut self, frame_id: u16, plan: SlotPlan) -> Reference {
1018 let pts = self.next_pts;
1019 self.next_pts += 1;
1020 self.age.record(frame_id, plan.predict_from == 0);
1021 let reference = match plan.predict_from {
1022 0 => {
1023 self.key_pts = pts;
1024 self.common.clear();
1025 self.sent.clear();
1026 Reference::None
1027 }
1028 from => self.slots[from.trailing_zeros() as usize]
1029 .map_or(Reference::None, |(id, _, _)| Reference::Frame(id)),
1030 };
1031 for (i, slot) in self.slots[..self.count].iter_mut().enumerate() {
1032 if plan.predict_from == 0 || plan.refresh.refreshes(1 << i) {
1033 *slot = Some((frame_id, pts, false));
1034 }
1035 }
1036 self.recent.push_back((frame_id, pts));
1037 if self.recent.len() > RECENT_FRAMES {
1038 self.recent.pop_front();
1039 }
1040 reference
1041 }
1042
1043 pub fn invalidate(&mut self, frame_id: u16) -> Invalidation {
1045 let lost_pts = match self.recent.iter().find(|r| r.0 == frame_id) {
1046 Some(&(_, pts)) if pts >= self.key_pts => pts,
1047 Some(_) => return Invalidation::Ignored,
1048 None => {
1049 let Some(&(oldest, _)) = self.recent.front() else {
1053 return Invalidation::Ignored;
1054 };
1055 if !self
1056 .age
1057 .behind(frame_id)
1058 .is_some_and(|b| b > self.age.newest.wrapping_sub(oldest) as u64)
1059 {
1060 return Invalidation::Ignored;
1061 }
1062 0
1063 }
1064 };
1065 for slot in self.slots[..self.count].iter_mut().flatten() {
1066 if slot.1 >= lost_pts {
1067 slot.2 = true;
1068 }
1069 }
1070 if self.has_reference() {
1071 Invalidation::Forget(lost_pts)
1072 } else {
1073 Invalidation::KeyFrame
1074 }
1075 }
1076}
1077
1078#[cfg(test)]
1079mod tests {
1080 use super::*;
1081
1082 #[test]
1083 fn a_frame_predicts_from_the_newest_one_the_client_still_has() {
1084 let mut w = ReferenceWindow::new(4);
1085 assert!(
1086 !w.has_reference(),
1087 "an empty window has nothing to predict from"
1088 );
1089 assert_eq!(w.record(10, true), Reference::None);
1090 assert_eq!(w.record(11, false), Reference::Frame(10));
1091 assert_eq!(w.record(12, false), Reference::Frame(11));
1092 assert_eq!(w.invalidate(11), Invalidation::Forget(1));
1093 assert!(w.has_reference(), "frame 10 is still there to predict from");
1094 assert_eq!(w.record(13, false), Reference::Frame(10));
1095 assert_eq!(w.record(14, false), Reference::Frame(13));
1096 assert_eq!(w.next_pts(), 5);
1097 }
1098
1099 #[test]
1100 fn losing_every_reference_asks_for_a_key_frame() {
1101 let mut w = ReferenceWindow::new(3);
1102 w.record(0, true);
1103 for id in 1..6u16 {
1104 w.record(id, false);
1105 }
1106 assert_eq!(w.invalidate(2), Invalidation::KeyFrame);
1109 assert!(!w.has_reference());
1110 assert_eq!(w.record(6, true), Reference::None);
1111 assert!(w.has_reference());
1112 assert_eq!(w.invalidate(6), Invalidation::Forget(6));
1114 assert!(!w.has_reference());
1115 }
1116
1117 #[test]
1118 fn a_frame_older_than_the_key_frame_is_ignored() {
1119 let mut w = ReferenceWindow::new(4);
1120 w.record(100, true);
1121 w.record(101, false);
1122 assert_eq!(w.invalidate(99), Invalidation::Ignored);
1123 assert_eq!(
1124 w.invalidate(105),
1125 Invalidation::Ignored,
1126 "a frame never sent is nothing to forget"
1127 );
1128 assert!(w.has_reference());
1129 }
1130
1131 #[test]
1132 fn frame_ids_wrap_and_timestamps_do_not() {
1133 let mut w = ReferenceWindow::new(4);
1134 w.record(65534, true);
1135 w.record(65535, false);
1136 w.record(0, false);
1137 assert_eq!(w.record(1, false), Reference::Frame(0));
1138 assert_eq!(w.invalidate(65535), Invalidation::Forget(1));
1139 assert_eq!(w.record(2, false), Reference::Frame(65534));
1140 assert_eq!(
1141 w.invalidate(65533),
1142 Invalidation::Ignored,
1143 "before the key frame"
1144 );
1145 w.set_capacity(2);
1146 assert_eq!(
1147 w.invalidate(65534),
1148 Invalidation::KeyFrame,
1149 "left the window, and everything held predicts through it"
1150 );
1151 }
1152
1153 #[test]
1154 fn a_loss_covering_the_frame_num_wrap_costs_a_key_frame() {
1155 let mut w = ReferenceWindow::new(8);
1156 w.set_frame_num_range(16);
1157 w.record(0, true);
1158 for id in 1..=17u16 {
1159 w.record(id, false);
1160 }
1161 assert_eq!(w.invalidate(17), Invalidation::Forget(17));
1163 assert_eq!(w.record(18, false), Reference::Frame(16));
1164 assert_eq!(
1165 w.invalidate(15),
1166 Invalidation::KeyFrame,
1167 "15, 16, and 18 go, and 16 is the wrap"
1168 );
1169 assert!(!w.has_reference());
1170 assert_eq!(w.record(19, true), Reference::None);
1171 assert_eq!(w.record(20, false), Reference::Frame(19));
1172 assert_eq!(
1173 w.invalidate(20),
1174 Invalidation::Forget(20),
1175 "the count restarts at the key frame"
1176 );
1177 let mut w = ReferenceWindow::new(8);
1178 w.record(0, true);
1179 for id in 1..=17u16 {
1180 w.record(id, false);
1181 }
1182 assert_eq!(
1183 w.invalidate(16),
1184 Invalidation::Forget(16),
1185 "a codec without the counter predicts past it"
1186 );
1187 }
1188
1189 #[test]
1190 fn a_frame_coded_again_predicts_past_the_first_attempt() {
1191 let mut w = ReferenceWindow::new(4);
1192 assert!(!w.retract(|_| true), "nothing recorded");
1193 w.record(10, true);
1194 assert!(
1195 !w.retract(|_| panic!("a key frame is coded again as a key frame")),
1196 "nothing older than a key frame"
1197 );
1198 w.record(11, false);
1199 w.record(12, false);
1200 assert!(!w.retract(|_| false), "the encoder refused");
1201 assert_eq!(w.record(13, false), Reference::Frame(12));
1202 let mut told = None;
1203 assert!(w.retract(|pts| told.replace(pts).is_none()));
1204 assert_eq!(told, Some(3));
1205 assert_eq!(
1206 w.record(13, false),
1207 Reference::Frame(12),
1208 "the frame sent in its place predicts from the one before"
1209 );
1210 assert_eq!(w.record(14, false), Reference::Frame(13));
1211 assert_eq!(
1212 w.invalidate(13),
1213 Invalidation::Forget(4),
1214 "a loss of 13 is the frame sent"
1215 );
1216 assert_eq!(w.record(15, false), Reference::Frame(12));
1217
1218 let mut w = ReferenceWindow::with_anchors(5, 2);
1219 let a = w.plan_anchor(true);
1220 w.record_marked(0, true, a);
1221 for id in 1..12u16 {
1222 let a = w.plan_anchor(false);
1223 w.record_marked(id, false, a);
1224 }
1225 let a = w.plan_anchor(false);
1226 assert_eq!(a, Some(1), "frame 12 is an anchor");
1227 w.record_marked(12, false, a);
1228 assert!(w.retract(|pts| pts == 12));
1229 assert_eq!(w.record_marked(12, false, a), Reference::Frame(11));
1230 assert_eq!(w.record(13, false), Reference::Frame(12));
1231 assert_eq!(w.invalidate(12), Invalidation::Forget(13));
1232 assert_eq!(w.record(14, false), Reference::Frame(11));
1233
1234 let mut w = ReferenceWindow::new(8);
1235 w.set_frame_num_range(16);
1236 w.record(0, true);
1237 for id in 1..=15u16 {
1238 w.record(id, false);
1239 }
1240 assert!(w.retract(|_| true));
1241 w.record(15, false);
1242 assert!(
1243 !w.retract(|_| panic!("frame_num 0 has to reach the decoder")),
1244 "the frame sent in place of 15 carries frame_num 0"
1245 );
1246 }
1247
1248 #[test]
1249 fn three_buffers_anchor_older_frames() {
1250 let mut s = ReferenceSlots::new();
1251 assert!(!s.has_reference());
1252 let key = s.plan(true);
1253 assert_eq!(key.predict_from, 0);
1254 assert_eq!(s.record(0, key), Reference::None);
1255 for id in 1..=30u16 {
1256 let plan = s.plan(false);
1257 assert_eq!(plan.predict_from, SlotRefresh::LAST, "frame {id}");
1258 assert_eq!(s.record(id, plan), Reference::Frame(id - 1));
1259 }
1260 assert_eq!(s.invalidate(25), Invalidation::Forget(25));
1262 let plan = s.plan(false);
1263 assert_eq!(plan.predict_from, SlotRefresh::GOLDEN);
1264 assert_eq!(
1265 plan.refresh,
1266 SlotRefresh(SlotRefresh::ALL),
1267 "a recovery frame re-anchors every buffer"
1268 );
1269 assert_eq!(s.record(31, plan), Reference::Frame(24));
1270 assert_eq!(s.record(32, s.plan(false)), Reference::Frame(31));
1271 assert_eq!(s.invalidate(31), Invalidation::KeyFrame);
1273 assert!(!s.has_reference());
1274 assert_eq!(s.record(33, s.plan(false)), Reference::None);
1275 assert_eq!(
1276 s.invalidate(3),
1277 Invalidation::Ignored,
1278 "before the key frame"
1279 );
1280 assert_eq!(s.next_pts(), 34);
1281 }
1282
1283 #[test]
1284 fn golden_and_altref_follow_their_periods() {
1285 let mut s = ReferenceSlots::new();
1286 s.record(0, s.plan(true));
1287 let mut refreshes = Vec::new();
1288 for id in 1..=48u16 {
1289 let plan = s.plan(false);
1290 refreshes.push(plan.refresh.0);
1291 s.record(id, plan);
1292 }
1293 for (i, &r) in refreshes.iter().enumerate() {
1294 let frame = i + 1;
1295 let want = SlotRefresh::LAST
1296 | if frame % 24 == 0 {
1297 SlotRefresh::GOLDEN
1298 } else {
1299 0
1300 }
1301 | if frame % 24 == 12 {
1302 SlotRefresh::ALTREF
1303 } else {
1304 0
1305 };
1306 assert_eq!(r, want, "frame {frame}");
1307 }
1308 assert_eq!(s.invalidate(37), Invalidation::Forget(37));
1311 assert_eq!(s.plan(false).predict_from, SlotRefresh::ALTREF);
1312 assert_eq!(s.record(49, s.plan(false)), Reference::Frame(36));
1313 assert_eq!(
1314 s.invalidate(100),
1315 Invalidation::Ignored,
1316 "a frame never sent is nothing to forget"
1317 );
1318 }
1319
1320 #[test]
1321 fn eight_buffers_keep_four_recent_frames_and_every_fourth() {
1322 let mut s = ReferenceSlots::vp9();
1323 let key = s.plan(true);
1324 assert_eq!(
1325 key.refresh,
1326 SlotRefresh(0xff),
1327 "a key frame refreshes all eight"
1328 );
1329 s.record(0, key);
1330 for id in 1..=19u16 {
1331 let plan = s.plan(false);
1332 let n = id as u8;
1333 let want = 1 << (n % 4)
1334 | if n.is_multiple_of(4) {
1335 1 << (4 + n / 4 % 4)
1336 } else {
1337 0
1338 };
1339 assert_eq!(plan.refresh.0, want, "frame {id}");
1340 assert_eq!(s.record(id, plan), Reference::Frame(id - 1));
1341 }
1342 let held: Vec<u16> = (0..8).map(|i| s.slot(1 << i).unwrap().0).collect();
1343 assert_eq!(held, [16, 17, 18, 19, 16, 4, 8, 12]);
1344 assert_eq!(s.invalidate(9), Invalidation::Forget(9));
1346 let plan = s.plan(false);
1347 assert_eq!(plan.predict_from, 1 << 6);
1348 assert_eq!(s.record(20, plan), Reference::Frame(8));
1349 assert_eq!(s.record(21, s.plan(false)), Reference::Frame(20));
1350 }
1351
1352 #[test]
1353 fn acknowledged_slots_keep_an_anchor_until_every_consumer_holds_it() {
1354 let mut w = ReferenceSlots::new();
1357 w.record(0, w.plan(true));
1358 assert!(w.acknowledge(0, true));
1359 let mut marks = Vec::new();
1360 for id in 1..=72u16 {
1361 let plan = w.plan(false);
1362 if plan.refresh.0 & (SlotRefresh::GOLDEN | SlotRefresh::ALTREF) != 0 {
1363 marks.push((id, plan.refresh.0, w.shared_anchor(plan)));
1364 }
1365 w.record(id, plan);
1366 assert!(w.acknowledge(id, false));
1367 }
1368 let golden = SlotRefresh::LAST | SlotRefresh::GOLDEN;
1369 assert_eq!(marks, [(12, golden, true), (60, golden, true)]);
1370 assert!(w.acknowledge(60, true));
1372 let plan = w.plan(false);
1373 assert_eq!(plan.refresh.0, SlotRefresh::LAST);
1374 for id in 73..=84u16 {
1375 let plan = w.plan(false);
1376 if id == 84 {
1377 assert_eq!(plan.refresh.0, SlotRefresh::LAST | SlotRefresh::ALTREF);
1378 }
1379 w.record(id, plan);
1380 }
1381 w.invalidate(80);
1384 let plan = w.plan(false);
1385 assert_eq!(plan.predict_from, SlotRefresh::GOLDEN);
1386 assert_eq!(plan.refresh.0, SlotRefresh::LAST | SlotRefresh::ALTREF);
1387 assert!(!w.shared_anchor(plan));
1388 }
1389
1390 #[test]
1393 fn a_loss_up_to_twelve_frames_deep_finds_an_anchor() {
1394 for make in [
1395 ReferenceSlots::new as fn() -> ReferenceSlots,
1396 ReferenceSlots::vp9,
1397 ] {
1398 for sent in 1..=60u16 {
1399 for depth in 1..=sent.min(12) {
1400 let mut s = make();
1401 s.record(0, s.plan(true));
1402 for id in 1..=sent {
1403 let plan = s.plan(false);
1404 s.record(id, plan);
1405 }
1406 let lost = sent + 1 - depth;
1407 assert!(
1408 matches!(s.invalidate(lost), Invalidation::Forget(_)),
1409 "{} buffers, frame {lost} of {sent} lost",
1410 s.count
1411 );
1412 let plan = s.plan(false);
1413 assert!(
1414 s.slot(plan.predict_from)
1415 .is_some_and(|(id, _, lost_too)| id < lost && !lost_too)
1416 );
1417 }
1418 }
1419 }
1420 }
1421
1422 #[test]
1423 fn the_set_held_leaves_out_what_a_client_lost() {
1424 let held = |w: &ReferenceWindow| w.held().filter(|f| !f.2).map(|f| f.1).collect::<Vec<_>>();
1425 let mut w = ReferenceWindow::new(4);
1426 assert!(
1427 held(&w).is_empty(),
1428 "nothing is held before the first frame"
1429 );
1430 w.record(10, true);
1431 w.record(11, false);
1432 w.record(12, false);
1433 assert_eq!(held(&w), [0, 1, 2]);
1434 assert_eq!(w.invalidate(11), Invalidation::Forget(1));
1435 assert_eq!(held(&w), [0], "11 and every frame after it are out");
1436 assert_eq!(w.record(13, false), Reference::Frame(10));
1438 assert_eq!(held(&w), [0, 3]);
1439 w.record(14, false);
1441 assert_eq!(
1442 held(&w),
1443 [3, 4],
1444 "10 left the window of four, behind the two lost ones"
1445 );
1446 assert_eq!(w.invalidate(10), Invalidation::KeyFrame);
1447 assert!(held(&w).is_empty(), "the next frame has to be a key frame");
1448 w.record(15, true);
1449 assert_eq!(held(&w), [5]);
1450 }
1451
1452 #[test]
1456 fn a_loss_long_after_the_key_frame_is_still_answered() {
1457 let mut w = ReferenceWindow::new(8);
1458 let mut s = ReferenceSlots::new();
1459 let id = |n: u32| (n * 3) as u16;
1460 w.record(id(0), true);
1461 s.record(id(0), SlotPlan::KEY);
1462 for n in 1..=40_000u32 {
1463 w.record(id(n), false);
1464 let plan = s.plan(false);
1465 s.record(id(n), plan);
1466 }
1467 assert_eq!(w.invalidate(id(39_998)), Invalidation::Forget(39_998));
1468 assert_eq!(s.invalidate(id(39_998)), Invalidation::Forget(39_998));
1469 assert_eq!(
1470 w.invalidate(id(39_900)),
1471 Invalidation::KeyFrame,
1472 "sent since the key, and older than the window"
1473 );
1474 assert_eq!(
1475 w.invalidate(id(39_999) + 1),
1476 Invalidation::Ignored,
1477 "a frame the capture skipped was never sent"
1478 );
1479 let mut w = ReferenceWindow::new(8);
1480 w.record(id(0), false);
1481 for n in 1..=40_000u32 {
1482 w.record(id(n), n == 39_990);
1483 }
1484 assert_eq!(
1485 w.invalidate(id(39_989)),
1486 Invalidation::Ignored,
1487 "before the key frame"
1488 );
1489 assert_eq!(w.invalidate(id(39_995)), Invalidation::Forget(39_995));
1490 }
1491
1492 fn anchored(n: u16) -> ReferenceWindow {
1495 let mut w = ReferenceWindow::with_anchors(4, 2);
1496 for id in 0..=n {
1497 let key = id == 0;
1498 let slot = w.plan_anchor(key);
1499 w.record_marked(id, key, slot);
1500 }
1501 w
1502 }
1503
1504 #[test]
1505 fn anchors_are_marked_every_twelfth_frame_into_the_older_one() {
1506 let mut w = ReferenceWindow::with_anchors(4, 2);
1507 assert_eq!(
1508 w.plan_anchor(true),
1509 Some(0),
1510 "the key frame is the first anchor"
1511 );
1512 assert_eq!(w.record_marked(0, true, Some(0)), Reference::None);
1513 let mut marks = Vec::new();
1514 for id in 1..=48u16 {
1515 let slot = w.plan_anchor(false);
1516 if let Some(slot) = slot {
1517 marks.push((id, slot));
1518 }
1519 assert_eq!(
1520 w.record_marked(id, false, slot),
1521 Reference::Frame(id - 1),
1522 "frame {id}"
1523 );
1524 }
1525 assert_eq!(marks, [(12, 1), (24, 0), (36, 1), (48, 0)]);
1526 assert_eq!(w.held().map(|f| f.0).collect::<Vec<_>>(), [36, 46, 47, 48]);
1528 }
1529
1530 #[test]
1531 fn one_anchor_takes_every_forty_eighth_frame() {
1532 let mut w = ReferenceWindow::with_anchors(4, 1);
1533 w.record_marked(0, true, w.plan_anchor(true));
1534 let mut marks = Vec::new();
1535 for id in 1..=100u16 {
1536 let slot = w.plan_anchor(false);
1537 if let Some(slot) = slot {
1538 marks.push((id, slot));
1539 }
1540 w.record_marked(id, false, slot);
1541 }
1542 assert_eq!(marks, [(48, 0), (96, 0)]);
1543 assert_eq!(w.held().map(|f| f.0).collect::<Vec<_>>(), [96, 98, 99, 100]);
1545 assert_eq!(w.invalidate(97), Invalidation::Forget(97));
1546 assert_eq!(
1547 w.record_marked(101, false, w.plan_anchor(false)),
1548 Reference::Frame(96)
1549 );
1550 assert_eq!(w.invalidate(95), Invalidation::KeyFrame);
1551 }
1552
1553 #[test]
1554 fn a_loss_older_than_every_recent_frame_is_predicted_past_from_an_anchor() {
1555 let mut w = anchored(20);
1557 assert_eq!(w.invalidate(16), Invalidation::Forget(16));
1558 assert_eq!(
1559 w.record_marked(21, false, w.plan_anchor(false)),
1560 Reference::Frame(12)
1561 );
1562 assert_eq!(
1563 w.record_marked(22, false, w.plan_anchor(false)),
1564 Reference::Frame(21)
1565 );
1566 let mut w = anchored(20);
1568 assert_eq!(w.invalidate(10), Invalidation::Forget(10));
1569 assert_eq!(
1570 w.record_marked(21, false, w.plan_anchor(false)),
1571 Reference::Frame(0)
1572 );
1573 let mut w = anchored(20);
1575 assert_eq!(w.invalidate(12), Invalidation::Forget(12));
1576 assert_eq!(w.newest_valid(), Some((0, 0)));
1577 let mut w = anchored(20);
1579 assert_eq!(w.invalidate(0), Invalidation::KeyFrame);
1580 assert!(!w.has_reference());
1581 assert_eq!(
1582 w.plan_anchor(false),
1583 Some(0),
1584 "the next frame is a key frame and the first anchor"
1585 );
1586 }
1587
1588 #[test]
1589 fn a_lost_anchor_is_the_one_marked_next() {
1590 let mut w = anchored(30);
1592 assert_eq!(w.invalidate(24), Invalidation::Forget(24));
1593 assert_eq!(
1594 w.record_marked(31, false, w.plan_anchor(false)),
1595 Reference::Frame(12)
1596 );
1597 for id in 32..=35u16 {
1598 w.record_marked(id, false, w.plan_anchor(false));
1599 }
1600 assert_eq!(w.plan_anchor(false), Some(0));
1602 }
1603
1604 #[test]
1605 fn the_wrap_rule_and_unsent_frames_hold_with_anchors() {
1606 let mut w = ReferenceWindow::with_anchors(4, 2);
1607 w.set_frame_num_range(16);
1608 for id in 0..=17u16 {
1609 let key = id == 0;
1610 let slot = w.plan_anchor(key);
1611 w.record_marked(id, key, slot);
1612 }
1613 assert_eq!(w.invalidate(17), Invalidation::Forget(17));
1615 assert_eq!(
1616 w.invalidate(15),
1617 Invalidation::KeyFrame,
1618 "15 to 17 go, and 16 is the wrap"
1619 );
1620 let mut w = anchored(20);
1621 assert_eq!(
1622 w.invalidate(40),
1623 Invalidation::Ignored,
1624 "a frame never sent is nothing to forget"
1625 );
1626 w.record_marked(21, true, Some(0));
1627 assert_eq!(
1628 w.invalidate(20),
1629 Invalidation::Ignored,
1630 "before the key frame"
1631 );
1632 assert_eq!(
1633 w.invalidate(21),
1634 Invalidation::KeyFrame,
1635 "the key frame was all there was"
1636 );
1637 }
1638
1639 #[test]
1640 fn a_key_frame_the_session_forces_itself_is_marked() {
1641 let mut w = anchored(20);
1642 w.reset();
1644 assert!(!w.has_reference(), "the next frame has to be a key frame");
1645 assert_eq!(w.plan_anchor(false), Some(0));
1646 assert_eq!(w.invalidate(19), Invalidation::Ignored, "nothing is held");
1647 let mut w = anchored(20);
1649 w.record_marked(21, true, None);
1650 assert_eq!(w.plan_anchor(false), Some(0));
1651 w.record_marked(22, false, Some(0));
1652 assert_eq!(w.plan_anchor(false), None);
1653 }
1654
1655 #[test]
1656 fn anchors_take_their_share_of_the_buffer() {
1657 let mut w = ReferenceWindow::with_anchors(8, 2);
1658 for id in 0..=30u16 {
1659 let key = id == 0;
1660 let slot = w.plan_anchor(key);
1661 w.record_marked(id, key, slot);
1662 }
1663 assert_eq!(w.held().count(), 8, "six recent frames and two anchors");
1664 w.set_capacity(4);
1665 assert_eq!(w.held().count(), 4, "two recent frames and two anchors");
1666 assert!(!ReferenceWindow::new(4).anchored() && w.anchored());
1667 }
1668
1669 #[test]
1670 fn the_wire_form_names_the_frame() {
1671 assert_eq!(Reference::Untracked.frame_id(), -2);
1672 assert_eq!(Reference::None.frame_id(), -1);
1673 assert_eq!(Reference::Frame(7).frame_id(), 7);
1674 }
1675
1676 #[test]
1678 fn covered_losses_preserve_recovered_references() {
1679 for (anchors, lost, last, recovered, later, fresh, earlier) in [
1680 (0, 6u16, 7u16, 14u16, 7u16, 13u16, 5u16),
1681 (1, 80, 87, 98, 81, 97, 40),
1682 (2, 26, 31, 50, 27, 49, 20),
1683 ] {
1684 for report in [later, fresh, earlier] {
1685 let mut w = if anchors == 0 {
1686 ReferenceWindow::new(4)
1687 } else {
1688 ReferenceWindow::with_anchors(8, anchors)
1689 };
1690 for id in 0..=last {
1691 let key = id == 0;
1692 w.record_marked(id, key, w.plan_anchor(key));
1693 }
1694 assert!(matches!(w.invalidate(lost), Invalidation::Forget(_)));
1695 for id in last + 1..=recovered {
1696 w.record_marked(id, false, w.plan_anchor(false));
1697 }
1698 let valid = w.newest_valid();
1699 let action = w.invalidate(report);
1700 if report == later {
1701 assert_eq!(action, Invalidation::Ignored, "{anchors} anchors");
1702 assert_eq!(w.newest_valid(), valid);
1703 assert_eq!(
1704 w.record_marked(recovered + 1, false, w.plan_anchor(false)),
1705 Reference::Frame(recovered)
1706 );
1707 } else {
1708 assert_ne!(action, Invalidation::Ignored, "loss {report} is new");
1709 }
1710 }
1711 }
1712 }
1713
1714 #[test]
1716 fn covered_loss_intervals_do_not_hide_intervening_losses() {
1717 let mut w = ReferenceWindow::new(4);
1718 for id in 0..=7 {
1719 w.record(id, id == 0);
1720 }
1721 assert_eq!(w.invalidate(6), Invalidation::Forget(6));
1722 for id in 8..=13 {
1723 w.record(id, false);
1724 }
1725 assert_eq!(w.invalidate(12), Invalidation::Forget(12));
1726 for id in 14..=18 {
1727 w.record(id, false);
1728 }
1729 for id in [6, 7, 12, 13] {
1730 assert_eq!(w.invalidate(id), Invalidation::Ignored);
1731 assert_eq!(w.newest_valid(), Some((18, 18)));
1732 }
1733 assert_eq!(w.invalidate(10), Invalidation::KeyFrame);
1734 assert_eq!(w.invalidate(13), Invalidation::Ignored);
1735 assert!(!w.has_reference(), "a required key frame stays required");
1736 }
1737
1738 #[test]
1740 fn covered_loss_history_handles_sparse_wrapping_ids_and_expiry() {
1741 let id = |n: u32| (65520 + n * 3) as u16;
1742 let mut w = ReferenceWindow::with_anchors(4, 1);
1743 for n in 0..=87 {
1744 w.record_marked(id(n), n == 0, w.plan_anchor(n == 0));
1745 }
1746 assert_eq!(w.invalidate(id(80)), Invalidation::Forget(80));
1747 for n in 88..=98 {
1748 w.record_marked(id(n), false, w.plan_anchor(false));
1749 }
1750 assert_eq!(w.invalidate(id(81)), Invalidation::Ignored);
1751 assert_eq!(w.newest_valid(), Some((id(98), 98)));
1752 assert_eq!(w.invalidate(id(81) + 1), Invalidation::Ignored);
1753 for n in 99..=(98 + RECENT_FRAMES as u32) {
1754 w.record_marked(id(n), false, w.plan_anchor(false));
1755 }
1756 assert_eq!(w.invalidate(id(81)), Invalidation::KeyFrame);
1757 }
1758
1759 #[test]
1761 fn covered_loss_history_does_not_outlive_a_reused_frame_id() {
1762 for reset in [false, true] {
1763 let mut w = ReferenceWindow::new(4);
1764 for id in 0..=7 {
1765 w.record(id, id == 0);
1766 }
1767 assert_eq!(w.invalidate(6), Invalidation::Forget(6));
1768 w.record(8, false);
1769 if reset {
1770 w.reset();
1771 }
1772 w.record(6, true);
1773 assert_eq!(w.invalidate(6), Invalidation::Forget(9));
1774 assert!(!w.has_reference());
1775 }
1776 }
1777
1778 #[test]
1780 fn covered_loss_keeps_the_h264_wrap_guard() {
1781 let mut w = ReferenceWindow::with_anchors(8, 1);
1782 w.set_frame_num_range(16);
1783 for id in 0..=14 {
1784 w.record_marked(id, id == 0, w.plan_anchor(id == 0));
1785 }
1786 assert_eq!(w.invalidate(13), Invalidation::Forget(13));
1787 for id in 15..=17 {
1788 w.record_marked(id, false, w.plan_anchor(false));
1789 }
1790 w.set_capacity(4);
1791 assert_eq!(w.invalidate(14), Invalidation::Ignored);
1792 assert_eq!(w.newest_valid(), Some((17, 17)));
1793 assert_eq!(w.invalidate(15), Invalidation::KeyFrame);
1794 assert!(!w.has_reference());
1795 }
1796
1797 fn feed(
1799 w: &mut ReferenceWindow,
1800 ids: std::ops::RangeInclusive<u16>,
1801 ) -> Vec<(u16, Option<u8>, Reference)> {
1802 ids.map(|id| {
1803 let key = id == 0;
1804 let slot = w.plan_anchor(key);
1805 if slot.is_some() && !key {
1806 w.settle();
1807 }
1808 (id, slot, w.record_marked(id, key, slot))
1809 })
1810 .collect()
1811 }
1812
1813 #[test]
1814 fn an_acknowledged_anchor_is_pinned_while_the_schedule_marks_the_other() {
1815 let mut w = ReferenceWindow::with_anchors(4, 2);
1816 feed(&mut w, 0..=0);
1817 assert!(w.acknowledge(0, true));
1818 let marks: Vec<(u16, u8)> = feed(&mut w, 1..=48)
1819 .into_iter()
1820 .filter_map(|(id, slot, _)| slot.map(|s| (id, s)))
1821 .collect();
1822 assert_eq!(
1823 marks,
1824 [(12, 1), (24, 1), (36, 1), (48, 1)],
1825 "the key frame stays in slot 0"
1826 );
1827 assert!(w.acknowledge(48, true));
1828 assert_eq!(
1829 feed(&mut w, 49..=60).last().map(|f| f.1),
1830 Some(Some(0)),
1831 "48 pinned, the schedule takes slot 0 back"
1832 );
1833 assert!(!w.acknowledge(1000, true), "a frame never sent is not held");
1834 }
1835
1836 #[test]
1837 fn an_anchor_predicts_from_the_newest_frame_every_consumer_was_sent() {
1838 let mut w = ReferenceWindow::with_anchors(8, 2);
1839 feed(&mut w, 0..=11);
1840 for id in 0..=10u16 {
1841 assert!(w.acknowledge(id, true));
1842 }
1843 assert_eq!(w.plan_anchor(false), Some(1));
1844 assert_eq!(
1845 w.settle(),
1846 Some(Invalidation::Forget(11)),
1847 "11 is forgotten"
1848 );
1849 assert!(w.predicts_from_shared());
1850 assert_eq!(w.record_marked(12, false, Some(1)), Reference::Frame(10));
1851 assert_eq!(
1852 w.record(13, false),
1853 Reference::Frame(12),
1854 "the stream goes on from the anchor"
1855 );
1856
1857 let mut w = ReferenceWindow::with_anchors(8, 2);
1860 feed(&mut w, 0..=11);
1861 for id in 0..=9u16 {
1862 assert!(w.acknowledge(id, true));
1863 }
1864 assert_eq!(w.settle(), None, "9 is three frames back");
1865 assert_eq!(w.record_marked(12, false, Some(1)), Reference::Frame(11));
1866
1867 let mut w = ReferenceWindow::with_anchors(4, 2);
1869 feed(&mut w, 0..=11);
1870 assert!(w.acknowledge(0, true));
1871 assert_eq!(w.settle(), None);
1872 assert_eq!(w.record_marked(12, false, Some(1)), Reference::Frame(11));
1873
1874 let mut w = ReferenceWindow::with_anchors(8, 1);
1877 feed(&mut w, 0..=47);
1878 for id in 0..=30u16 {
1879 assert!(w.acknowledge(id, true));
1880 }
1881 assert_eq!(w.plan_anchor(false), None);
1882 assert_eq!(w.record_marked(48, false, None), Reference::Frame(47));
1883
1884 let mut w = ReferenceWindow::with_anchors(4, 2);
1887 feed(&mut w, 0..=11);
1888 assert!(w.acknowledge(0, true));
1889 assert!(w.acknowledge(11, false));
1890 assert_eq!(w.settle(), None);
1891 assert!(w.predicts_from_shared());
1892 let mut w = ReferenceWindow::with_anchors(4, 2);
1893 feed(&mut w, 0..=11);
1894 assert_eq!(
1895 w.settle(),
1896 None,
1897 "unacknowledged, an anchor is settled by nothing"
1898 );
1899 }
1900
1901 #[test]
1902 fn only_an_anchor_every_consumer_holds_is_pinned() {
1903 let mut w = ReferenceWindow::with_anchors(4, 2);
1906 feed(&mut w, 0..=0);
1907 assert!(w.acknowledge(0, true));
1908 for id in 1..=24u16 {
1909 feed(&mut w, id..=id);
1910 assert!(w.acknowledge(id, false));
1911 }
1912 let anchors: Vec<u16> = w.anchor_frames().map(|a| a.0).collect();
1913 assert!(anchors.contains(&0) && anchors.contains(&12), "{anchors:?}");
1914 assert!(w.acknowledge(12, true));
1915 assert_eq!(
1916 feed(&mut w, 25..=36).last().map(|f| f.1),
1917 Some(Some(0)),
1918 "12 pinned"
1919 );
1920 let mut marks = Vec::new();
1922 for id in 25..=96u16 {
1923 if id > 36 {
1924 marks.extend(
1925 feed(&mut w, id..=id)
1926 .into_iter()
1927 .filter_map(|f| f.1.map(|s| (id, s))),
1928 );
1929 }
1930 assert!(w.acknowledge(id, false));
1931 }
1932 assert_eq!(marks, [(84, 0)]);
1933 }
1934
1935 #[test]
1936 fn a_lone_anchor_every_consumer_holds_stays_while_one_lags() {
1937 let mut w = ReferenceWindow::with_anchors(8, 1);
1941 let mut marks = Vec::new();
1942 for id in 0..=480u16 {
1943 marks.extend(
1944 feed(&mut w, id..=id)
1945 .into_iter()
1946 .filter_map(|f| f.1.map(|s| (id, s))),
1947 );
1948 assert!(w.acknowledge(id, id <= 60));
1949 }
1950 assert_eq!(
1951 marks,
1952 [(0, 0), (48, 0), (432, 0)],
1953 "past HOLD_MAX it is marked over, the anchor after it kept as one sent is"
1954 );
1955 }
1956
1957 #[test]
1958 fn a_lone_anchor_is_not_marked_from_the_one_it_marks_over() {
1959 for (late, want) in [
1963 (9u16, vec![(0, 0), (384, 0)]),
1964 (0, vec![(0, 0), (48, 0), (96, 0)]),
1965 ] {
1966 let mut w = ReferenceWindow::with_anchors(8, 1);
1967 let mut marks = Vec::new();
1968 for id in 0..=(if late > 0 { 480 } else { 100 }) {
1969 marks.extend(
1970 feed(&mut w, id..=id)
1971 .into_iter()
1972 .filter_map(|f| f.1.map(|s| (id, s))),
1973 );
1974 if id >= late {
1975 assert!(w.acknowledge(id - late, true));
1976 }
1977 }
1978 assert_eq!(marks, want, "held {late} frames late");
1979 }
1980 }
1981
1982 #[test]
1983 fn a_consumer_further_behind_than_an_anchor_period_is_predicted_past_on_its_report() {
1984 let mut w = ReferenceWindow::with_anchors(4, 2);
1985 for id in 0..=60u16 {
1986 feed(&mut w, id..=id);
1987 assert!(w.acknowledge(id, true));
1988 }
1989 let anchors: Vec<(u16, Reference)> = feed(&mut w, 61..=120)
1990 .into_iter()
1991 .filter(|f| f.1.is_some())
1992 .map(|f| (f.0, f.2))
1993 .collect();
1994 assert_eq!(
1995 anchors,
1996 [
1997 (72, Reference::Frame(71)),
1998 (84, Reference::Frame(83)),
1999 (96, Reference::Frame(95)),
2000 (108, Reference::Frame(107)),
2001 (120, Reference::Frame(119)),
2002 ],
2003 "a consumer holds nothing past 60: of two anchors, each predicts from the frame before"
2004 );
2005 assert_eq!(w.invalidate(121), Invalidation::Ignored, "never sent");
2006 assert!(matches!(w.invalidate(61), Invalidation::Forget(_)));
2007 assert_eq!(
2008 w.predicting_anchor(),
2009 Some(1),
2010 "60, pinned in slot 1, named"
2011 );
2012 assert_eq!(w.record(121, false), Reference::Frame(60));
2013
2014 let mut w = ReferenceWindow::with_anchors(4, 2);
2015 feed(&mut w, 0..=120);
2016 assert_eq!(
2017 w.invalidate(61),
2018 Invalidation::KeyFrame,
2019 "unacknowledged, both anchors are past 61"
2020 );
2021 }
2022
2023 #[test]
2024 fn a_recent_frame_further_back_than_the_buffer_is_not_predicted_from_after_a_gap() {
2025 let mut w = ReferenceWindow::with_anchors(8, 1);
2029 w.set_frame_num_range(256);
2030 w.set_acknowledged();
2031 for id in 0..=47u16 {
2032 feed(&mut w, id..=id);
2033 assert!(w.acknowledge(id, true));
2034 }
2035 assert_eq!(feed(&mut w, 48..=53)[0].1, Some(0), "48 is the anchor");
2036 assert_eq!(w.invalidate(48), Invalidation::Forget(48));
2037 assert_eq!(w.forget_stale(), None);
2038 assert_eq!(w.record(54, false), Reference::Frame(47));
2039
2040 let mut w = ReferenceWindow::with_anchors(8, 1);
2043 w.set_frame_num_range(256);
2044 w.set_acknowledged();
2045 for id in 0..=47u16 {
2046 feed(&mut w, id..=id);
2047 assert!(w.acknowledge(id, true));
2048 }
2049 feed(&mut w, 48..=54);
2050 assert_eq!(w.invalidate(48), Invalidation::Forget(48));
2051 assert_eq!(w.newest_valid(), Some((47, 47)));
2052 assert_eq!(w.forget_stale(), Some(Invalidation::KeyFrame));
2053
2054 let mut w = ReferenceWindow::with_anchors(8, 2);
2055 w.set_acknowledged();
2056 feed(&mut w, 0..=12);
2057 assert_eq!(w.forget_stale(), None, "only H.264 counts frame_num gaps");
2058 }
2059
2060 #[test]
2061 fn the_frame_where_frame_num_wraps_is_an_anchor_once_acknowledged() {
2062 let mut w = ReferenceWindow::with_anchors(8, 1);
2063 w.set_frame_num_range(16);
2064 feed(&mut w, 0..=15);
2065 assert_eq!(w.plan_anchor(false), None, "16 is off the schedule");
2066 assert!(w.acknowledge(15, true));
2067 assert!(w.plan_anchor(false).is_some(), "frame_num wraps at 16");
2068
2069 let mut w = ReferenceWindow::with_anchors(8, 1);
2071 w.set_frame_num_range(64);
2072 for id in 0..=48u16 {
2073 feed(&mut w, id..=id);
2074 assert!(w.acknowledge(id, true));
2075 }
2076 let at: Vec<(u16, Reference)> = feed(&mut w, 49..=64)
2077 .into_iter()
2078 .filter(|f| f.1.is_some())
2079 .map(|f| (f.0, f.2))
2080 .collect();
2081 assert_eq!(
2082 at.last(),
2083 Some(&(64, Reference::Frame(48))),
2084 "the wrap reaches back to 48, the anchor every consumer holds"
2085 );
2086
2087 let mut w = ReferenceWindow::with_anchors(8, 1);
2089 w.set_frame_num_range(16);
2090 w.set_acknowledged();
2091 for id in 0..=15u16 {
2092 feed(&mut w, id..=id);
2093 assert!(w.acknowledge(id, id <= 13));
2094 }
2095 assert!(w.plan_anchor(false).is_some());
2096 assert_eq!(w.settle(), Some(Invalidation::Forget(14)));
2097 assert_eq!(w.record_marked(16, false, Some(0)), Reference::Frame(13));
2098 }
2099}