oximedia_codec/
reference_frames.rs1#![allow(dead_code)]
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum RefFrameType {
11 ShortTerm,
13 LongTerm,
15}
16
17impl RefFrameType {
18 pub fn is_long_term(self) -> bool {
20 self == Self::LongTerm
21 }
22
23 pub fn is_short_term(self) -> bool {
25 self == Self::ShortTerm
26 }
27}
28
29#[derive(Debug, Clone)]
31pub struct RefFrame {
32 pub poc: i32,
34 pub frame_num: u32,
36 pub ref_type: RefFrameType,
38 pub in_use: bool,
40 pub buffer_index: usize,
42}
43
44impl RefFrame {
45 pub fn short_term(poc: i32, frame_num: u32, buffer_index: usize) -> Self {
47 Self {
48 poc,
49 frame_num,
50 ref_type: RefFrameType::ShortTerm,
51 in_use: true,
52 buffer_index,
53 }
54 }
55
56 pub fn long_term(poc: i32, long_term_frame_idx: u32, buffer_index: usize) -> Self {
58 Self {
59 poc,
60 frame_num: long_term_frame_idx,
61 ref_type: RefFrameType::LongTerm,
62 in_use: true,
63 buffer_index,
64 }
65 }
66
67 pub fn is_valid(&self) -> bool {
69 self.in_use
70 }
71
72 pub fn mark_unused(&mut self) {
74 self.in_use = false;
75 }
76}
77
78#[derive(Debug)]
83pub struct RefFrameList {
84 frames: Vec<RefFrame>,
85 max_size: usize,
86}
87
88impl RefFrameList {
89 pub fn new(max_size: usize) -> Self {
91 Self {
92 frames: Vec::with_capacity(max_size),
93 max_size,
94 }
95 }
96
97 pub fn add(&mut self, frame: RefFrame) -> bool {
102 if self.frames.len() < self.max_size {
103 self.frames.push(frame);
104 return true;
105 }
106 if self.remove_oldest() {
108 self.frames.push(frame);
109 true
110 } else {
111 false
112 }
113 }
114
115 pub fn remove_oldest(&mut self) -> bool {
119 let pos = self
120 .frames
121 .iter()
122 .enumerate()
123 .filter(|(_, f)| f.ref_type == RefFrameType::ShortTerm && f.in_use)
124 .min_by_key(|(_, f)| f.frame_num)
125 .map(|(i, _)| i);
126
127 if let Some(idx) = pos {
128 self.frames.remove(idx);
129 true
130 } else {
131 false
132 }
133 }
134
135 pub fn find_closest_poc(&self, target_poc: i32) -> Option<&RefFrame> {
139 self.frames
140 .iter()
141 .filter(|f| f.in_use)
142 .min_by_key(|f| (f.poc - target_poc).unsigned_abs())
143 }
144
145 pub fn len(&self) -> usize {
147 self.frames.iter().filter(|f| f.in_use).count()
148 }
149
150 pub fn is_empty(&self) -> bool {
152 self.len() == 0
153 }
154
155 pub fn iter(&self) -> impl Iterator<Item = &RefFrame> {
157 self.frames.iter().filter(|f| f.in_use)
158 }
159
160 pub fn long_term_count(&self) -> usize {
162 self.frames
163 .iter()
164 .filter(|f| f.in_use && f.ref_type == RefFrameType::LongTerm)
165 .count()
166 }
167
168 pub fn short_term_count(&self) -> usize {
170 self.frames
171 .iter()
172 .filter(|f| f.in_use && f.ref_type == RefFrameType::ShortTerm)
173 .count()
174 }
175
176 pub fn clear(&mut self) {
178 self.frames.clear();
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn test_ref_frame_type_is_long_term() {
188 assert!(RefFrameType::LongTerm.is_long_term());
189 assert!(!RefFrameType::ShortTerm.is_long_term());
190 }
191
192 #[test]
193 fn test_ref_frame_type_is_short_term() {
194 assert!(RefFrameType::ShortTerm.is_short_term());
195 assert!(!RefFrameType::LongTerm.is_short_term());
196 }
197
198 #[test]
199 fn test_ref_frame_short_term_constructor() {
200 let f = RefFrame::short_term(10, 3, 0);
201 assert_eq!(f.poc, 10);
202 assert_eq!(f.frame_num, 3);
203 assert!(f.is_valid());
204 assert_eq!(f.ref_type, RefFrameType::ShortTerm);
205 }
206
207 #[test]
208 fn test_ref_frame_long_term_constructor() {
209 let f = RefFrame::long_term(20, 1, 5);
210 assert_eq!(f.ref_type, RefFrameType::LongTerm);
211 assert_eq!(f.frame_num, 1);
212 assert!(f.is_valid());
213 }
214
215 #[test]
216 fn test_ref_frame_mark_unused() {
217 let mut f = RefFrame::short_term(0, 0, 0);
218 f.mark_unused();
219 assert!(!f.is_valid());
220 }
221
222 #[test]
223 fn test_ref_frame_list_add_within_capacity() {
224 let mut list = RefFrameList::new(4);
225 assert!(list.add(RefFrame::short_term(0, 0, 0)));
226 assert_eq!(list.len(), 1);
227 }
228
229 #[test]
230 fn test_ref_frame_list_is_empty_initially() {
231 let list = RefFrameList::new(4);
232 assert!(list.is_empty());
233 }
234
235 #[test]
236 fn test_ref_frame_list_remove_oldest_evicts_min_frame_num() {
237 let mut list = RefFrameList::new(10);
238 list.add(RefFrame::short_term(4, 4, 0));
239 list.add(RefFrame::short_term(2, 2, 1));
240 list.add(RefFrame::short_term(6, 6, 2));
241 assert!(list.remove_oldest());
242 assert_eq!(list.len(), 2);
244 assert!(list.iter().all(|f| f.frame_num != 2));
245 }
246
247 #[test]
248 fn test_ref_frame_list_add_evicts_oldest_when_full() {
249 let mut list = RefFrameList::new(2);
250 list.add(RefFrame::short_term(0, 0, 0));
251 list.add(RefFrame::short_term(2, 2, 1));
252 let ok = list.add(RefFrame::short_term(4, 4, 2));
254 assert!(ok);
255 assert_eq!(list.len(), 2);
256 }
257
258 #[test]
259 fn test_ref_frame_list_find_closest_poc() {
260 let mut list = RefFrameList::new(4);
261 list.add(RefFrame::short_term(0, 0, 0));
262 list.add(RefFrame::short_term(10, 1, 1));
263 list.add(RefFrame::short_term(20, 2, 2));
264 let closest = list.find_closest_poc(12).expect("should succeed");
265 assert_eq!(closest.poc, 10);
266 }
267
268 #[test]
269 fn test_ref_frame_list_find_closest_poc_empty_returns_none() {
270 let list = RefFrameList::new(4);
271 assert!(list.find_closest_poc(0).is_none());
272 }
273
274 #[test]
275 fn test_ref_frame_list_long_term_count() {
276 let mut list = RefFrameList::new(4);
277 list.add(RefFrame::short_term(0, 0, 0));
278 list.add(RefFrame::long_term(10, 0, 1));
279 assert_eq!(list.long_term_count(), 1);
280 assert_eq!(list.short_term_count(), 1);
281 }
282
283 #[test]
284 fn test_ref_frame_list_clear() {
285 let mut list = RefFrameList::new(4);
286 list.add(RefFrame::short_term(0, 0, 0));
287 list.add(RefFrame::short_term(2, 1, 1));
288 list.clear();
289 assert!(list.is_empty());
290 }
291
292 #[test]
293 fn test_ref_frame_list_iter_only_active() {
294 let mut list = RefFrameList::new(4);
295 let mut f = RefFrame::short_term(0, 0, 0);
296 f.mark_unused();
297 list.frames.push(f);
298 list.add(RefFrame::short_term(2, 1, 1));
299 assert_eq!(list.iter().count(), 1);
300 }
301}