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