1#![forbid(unsafe_code)]
8#![allow(clippy::unreadable_literal)]
9#![allow(clippy::items_after_statements)]
10#![allow(clippy::unnecessary_wraps)]
11#![allow(clippy::struct_excessive_bools)]
12#![allow(clippy::identity_op)]
13#![allow(clippy::range_plus_one)]
14#![allow(clippy::needless_range_loop)]
15#![allow(clippy::useless_conversion)]
16#![allow(clippy::redundant_closure_for_method_calls)]
17#![allow(clippy::single_match_else)]
18#![allow(dead_code)]
19#![allow(clippy::doc_markdown)]
20#![allow(clippy::unused_self)]
21#![allow(clippy::trivially_copy_pass_by_ref)]
22#![allow(clippy::cast_possible_truncation)]
23#![allow(clippy::cast_sign_loss)]
24#![allow(clippy::missing_errors_doc)]
25#![allow(clippy::similar_names)]
26#![allow(clippy::cast_precision_loss)]
27#![allow(clippy::cast_lossless)]
28#![allow(clippy::many_single_char_names)]
29#![allow(clippy::manual_div_ceil)]
30#![allow(clippy::too_many_arguments)]
31
32use super::{ChromaSubsampling, PlaneType, ReconstructResult, ReconstructionError, NUM_REF_FRAMES};
33use std::collections::VecDeque;
34
35#[derive(Clone, Debug)]
41pub struct PlaneBuffer {
42 data: Vec<i16>,
44 width: u32,
46 height: u32,
48 stride: usize,
50 bit_depth: u8,
52 plane_type: PlaneType,
54}
55
56impl PlaneBuffer {
57 #[must_use]
59 pub fn new(width: u32, height: u32, bit_depth: u8, plane_type: PlaneType) -> Self {
60 let aligned_width = ((width as usize + 7) / 8) * 8;
62 let stride = aligned_width;
63 let size = stride * height as usize;
64
65 Self {
66 data: vec![0i16; size],
67 width,
68 height,
69 stride,
70 bit_depth,
71 plane_type,
72 }
73 }
74
75 #[must_use]
77 pub fn with_stride(
78 width: u32,
79 height: u32,
80 stride: usize,
81 bit_depth: u8,
82 plane_type: PlaneType,
83 ) -> Self {
84 let size = stride * height as usize;
85
86 Self {
87 data: vec![0i16; size],
88 width,
89 height,
90 stride,
91 bit_depth,
92 plane_type,
93 }
94 }
95
96 #[must_use]
98 pub const fn width(&self) -> u32 {
99 self.width
100 }
101
102 #[must_use]
104 pub const fn height(&self) -> u32 {
105 self.height
106 }
107
108 #[must_use]
110 pub const fn stride(&self) -> usize {
111 self.stride
112 }
113
114 #[must_use]
116 pub const fn bit_depth(&self) -> u8 {
117 self.bit_depth
118 }
119
120 #[must_use]
122 pub const fn plane_type(&self) -> PlaneType {
123 self.plane_type
124 }
125
126 #[must_use]
128 pub fn max_value(&self) -> i16 {
129 (1i16 << self.bit_depth) - 1
130 }
131
132 #[must_use]
134 pub fn get(&self, x: u32, y: u32) -> i16 {
135 if x >= self.width || y >= self.height {
136 return 0;
137 }
138 let idx = y as usize * self.stride + x as usize;
139 self.data.get(idx).copied().unwrap_or(0)
140 }
141
142 pub fn set(&mut self, x: u32, y: u32, value: i16) {
144 if x < self.width && y < self.height {
145 let idx = y as usize * self.stride + x as usize;
146 if idx < self.data.len() {
147 self.data[idx] = value;
148 }
149 }
150 }
151
152 pub fn set_clamped(&mut self, x: u32, y: u32, value: i16) {
154 let max_val = self.max_value();
155 let clamped = value.clamp(0, max_val);
156 self.set(x, y, clamped);
157 }
158
159 #[must_use]
161 pub fn row(&self, y: u32) -> &[i16] {
162 if y >= self.height {
163 return &[];
164 }
165 let start = y as usize * self.stride;
166 let end = start + self.width as usize;
167 if end <= self.data.len() {
168 &self.data[start..end]
169 } else {
170 &[]
171 }
172 }
173
174 pub fn row_mut(&mut self, y: u32) -> &mut [i16] {
176 if y >= self.height {
177 return &mut [];
178 }
179 let start = y as usize * self.stride;
180 let end = start + self.width as usize;
181 if end <= self.data.len() {
182 &mut self.data[start..end]
183 } else {
184 &mut []
185 }
186 }
187
188 #[must_use]
190 pub fn data(&self) -> &[i16] {
191 &self.data
192 }
193
194 pub fn data_mut(&mut self) -> &mut [i16] {
196 &mut self.data
197 }
198
199 pub fn clear(&mut self) {
201 self.data.fill(0);
202 }
203
204 pub fn fill(&mut self, value: i16) {
206 self.data.fill(value);
207 }
208
209 pub fn copy_from(&mut self, other: &PlaneBuffer) -> ReconstructResult<()> {
215 if self.width != other.width || self.height != other.height {
216 return Err(ReconstructionError::InvalidDimensions {
217 width: other.width,
218 height: other.height,
219 });
220 }
221
222 if self.stride == other.stride {
223 self.data.copy_from_slice(&other.data);
224 } else {
225 let copy_width = self.width as usize;
226 for y in 0..self.height {
227 let src_row = other.row(y);
228 let dst_row = self.row_mut(y);
229 dst_row[..copy_width].copy_from_slice(&src_row[..copy_width]);
230 }
231 }
232
233 Ok(())
234 }
235
236 pub fn copy_block_from(
238 &mut self,
239 other: &PlaneBuffer,
240 src_x: u32,
241 src_y: u32,
242 dst_x: u32,
243 dst_y: u32,
244 width: u32,
245 height: u32,
246 ) {
247 for dy in 0..height {
248 for dx in 0..width {
249 let value = other.get(src_x + dx, src_y + dy);
250 self.set(dst_x + dx, dst_y + dy, value);
251 }
252 }
253 }
254
255 #[must_use]
257 pub fn to_u8(&self) -> Vec<u8> {
258 let mut output = Vec::with_capacity(self.width as usize * self.height as usize);
259
260 for y in 0..self.height {
261 let row = self.row(y);
262 for &pixel in row.iter().take(self.width as usize) {
263 let value = if self.bit_depth <= 8 {
264 pixel.clamp(0, 255) as u8
265 } else {
266 let shift = self.bit_depth - 8;
268 ((pixel >> shift).clamp(0, 255)) as u8
269 };
270 output.push(value);
271 }
272 }
273
274 output
275 }
276
277 #[must_use]
279 pub fn sad(&self, other: &PlaneBuffer, block_x: u32, block_y: u32, size: u32) -> u32 {
280 let mut sad: u32 = 0;
281 for dy in 0..size {
282 for dx in 0..size {
283 let a = self.get(block_x + dx, block_y + dy);
284 let b = other.get(block_x + dx, block_y + dy);
285 sad += (a - b).unsigned_abs() as u32;
286 }
287 }
288 sad
289 }
290}
291
292#[derive(Clone, Debug)]
298pub struct FrameBuffer {
299 y_plane: PlaneBuffer,
301 u_plane: Option<PlaneBuffer>,
303 v_plane: Option<PlaneBuffer>,
305 width: u32,
307 height: u32,
309 bit_depth: u8,
311 subsampling: ChromaSubsampling,
313 timestamp: i64,
315 is_keyframe: bool,
317 id: u64,
319}
320
321impl FrameBuffer {
322 #[must_use]
324 pub fn new(width: u32, height: u32, bit_depth: u8, subsampling: ChromaSubsampling) -> Self {
325 static BUFFER_ID: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
326
327 let y_plane = PlaneBuffer::new(width, height, bit_depth, PlaneType::Y);
328
329 let (u_plane, v_plane) = match subsampling {
330 ChromaSubsampling::Mono => (None, None),
331 _ => {
332 let (cw, ch) = subsampling.chroma_size(width, height);
333 (
334 Some(PlaneBuffer::new(cw, ch, bit_depth, PlaneType::U)),
335 Some(PlaneBuffer::new(cw, ch, bit_depth, PlaneType::V)),
336 )
337 }
338 };
339
340 Self {
341 y_plane,
342 u_plane,
343 v_plane,
344 width,
345 height,
346 bit_depth,
347 subsampling,
348 timestamp: 0,
349 is_keyframe: false,
350 id: BUFFER_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
351 }
352 }
353
354 #[must_use]
356 pub const fn width(&self) -> u32 {
357 self.width
358 }
359
360 #[must_use]
362 pub const fn height(&self) -> u32 {
363 self.height
364 }
365
366 #[must_use]
368 pub const fn bit_depth(&self) -> u8 {
369 self.bit_depth
370 }
371
372 #[must_use]
374 pub const fn subsampling(&self) -> ChromaSubsampling {
375 self.subsampling
376 }
377
378 #[must_use]
380 pub const fn id(&self) -> u64 {
381 self.id
382 }
383
384 #[must_use]
386 pub const fn timestamp(&self) -> i64 {
387 self.timestamp
388 }
389
390 pub fn set_timestamp(&mut self, timestamp: i64) {
392 self.timestamp = timestamp;
393 }
394
395 #[must_use]
397 pub const fn is_keyframe(&self) -> bool {
398 self.is_keyframe
399 }
400
401 pub fn set_keyframe(&mut self, is_keyframe: bool) {
403 self.is_keyframe = is_keyframe;
404 }
405
406 #[must_use]
408 pub fn y_plane(&self) -> &PlaneBuffer {
409 &self.y_plane
410 }
411
412 pub fn y_plane_mut(&mut self) -> &mut PlaneBuffer {
414 &mut self.y_plane
415 }
416
417 #[must_use]
419 pub fn u_plane(&self) -> Option<&PlaneBuffer> {
420 self.u_plane.as_ref()
421 }
422
423 pub fn u_plane_mut(&mut self) -> Option<&mut PlaneBuffer> {
425 self.u_plane.as_mut()
426 }
427
428 #[must_use]
430 pub fn v_plane(&self) -> Option<&PlaneBuffer> {
431 self.v_plane.as_ref()
432 }
433
434 pub fn v_plane_mut(&mut self) -> Option<&mut PlaneBuffer> {
436 self.v_plane.as_mut()
437 }
438
439 #[must_use]
441 pub fn plane(&self, plane_type: PlaneType) -> Option<&PlaneBuffer> {
442 match plane_type {
443 PlaneType::Y => Some(&self.y_plane),
444 PlaneType::U => self.u_plane.as_ref(),
445 PlaneType::V => self.v_plane.as_ref(),
446 }
447 }
448
449 pub fn plane_mut(&mut self, plane_type: PlaneType) -> Option<&mut PlaneBuffer> {
451 match plane_type {
452 PlaneType::Y => Some(&mut self.y_plane),
453 PlaneType::U => self.u_plane.as_mut(),
454 PlaneType::V => self.v_plane.as_mut(),
455 }
456 }
457
458 #[must_use]
460 pub const fn num_planes(&self) -> usize {
461 self.subsampling.num_planes()
462 }
463
464 pub fn clear(&mut self) {
466 self.y_plane.clear();
467 if let Some(ref mut u) = self.u_plane {
468 u.clear();
469 }
470 if let Some(ref mut v) = self.v_plane {
471 v.clear();
472 }
473 }
474
475 pub fn copy_from(&mut self, other: &FrameBuffer) -> ReconstructResult<()> {
481 if self.width != other.width
482 || self.height != other.height
483 || self.subsampling != other.subsampling
484 {
485 return Err(ReconstructionError::InvalidDimensions {
486 width: other.width,
487 height: other.height,
488 });
489 }
490
491 self.y_plane.copy_from(&other.y_plane)?;
492
493 if let (Some(ref mut dst), Some(ref src)) = (&mut self.u_plane, &other.u_plane) {
494 dst.copy_from(src)?;
495 }
496
497 if let (Some(ref mut dst), Some(ref src)) = (&mut self.v_plane, &other.v_plane) {
498 dst.copy_from(src)?;
499 }
500
501 Ok(())
502 }
503
504 #[must_use]
506 pub fn size_bytes(&self) -> usize {
507 let y_size = self.y_plane.data().len() * 2; let u_size = self.u_plane.as_ref().map_or(0, |p| p.data().len() * 2);
509 let v_size = self.v_plane.as_ref().map_or(0, |p| p.data().len() * 2);
510 y_size + u_size + v_size
511 }
512}
513
514#[derive(Debug)]
520pub struct ReferenceFrameManager {
521 frames: [Option<FrameBuffer>; NUM_REF_FRAMES],
523 order_hints: [u32; NUM_REF_FRAMES],
525 current_frame: u64,
527}
528
529impl Default for ReferenceFrameManager {
530 fn default() -> Self {
531 Self::new()
532 }
533}
534
535impl ReferenceFrameManager {
536 #[must_use]
538 pub fn new() -> Self {
539 Self {
540 frames: Default::default(),
541 order_hints: [0; NUM_REF_FRAMES],
542 current_frame: 0,
543 }
544 }
545
546 #[must_use]
548 pub fn get(&self, index: usize) -> Option<&FrameBuffer> {
549 self.frames.get(index).and_then(|f| f.as_ref())
550 }
551
552 pub fn store(&mut self, index: usize, frame: FrameBuffer, order_hint: u32) {
554 if index < NUM_REF_FRAMES {
555 self.frames[index] = Some(frame);
556 self.order_hints[index] = order_hint;
557 }
558 }
559
560 pub fn clear_slot(&mut self, index: usize) {
562 if index < NUM_REF_FRAMES {
563 self.frames[index] = None;
564 self.order_hints[index] = 0;
565 }
566 }
567
568 pub fn clear_all(&mut self) {
570 for i in 0..NUM_REF_FRAMES {
571 self.frames[i] = None;
572 self.order_hints[i] = 0;
573 }
574 self.current_frame = 0;
575 }
576
577 #[must_use]
579 pub fn order_hint(&self, index: usize) -> u32 {
580 self.order_hints.get(index).copied().unwrap_or(0)
581 }
582
583 #[must_use]
585 pub fn has_reference(&self, index: usize) -> bool {
586 self.frames.get(index).is_some_and(|f| f.is_some())
587 }
588
589 #[must_use]
591 pub const fn current_frame(&self) -> u64 {
592 self.current_frame
593 }
594
595 pub fn next_frame(&mut self) {
597 self.current_frame += 1;
598 }
599
600 #[must_use]
602 pub fn valid_references(&self) -> Vec<usize> {
603 (0..NUM_REF_FRAMES)
604 .filter(|&i| self.has_reference(i))
605 .collect()
606 }
607}
608
609#[derive(Debug)]
615pub struct BufferPool {
616 available: VecDeque<FrameBuffer>,
618 width: u32,
620 height: u32,
622 bit_depth: u8,
624 subsampling: ChromaSubsampling,
626 max_size: usize,
628}
629
630impl BufferPool {
631 #[must_use]
633 pub fn new(
634 width: u32,
635 height: u32,
636 bit_depth: u8,
637 subsampling: ChromaSubsampling,
638 max_size: usize,
639 ) -> Self {
640 Self {
641 available: VecDeque::with_capacity(max_size),
642 width,
643 height,
644 bit_depth,
645 subsampling,
646 max_size,
647 }
648 }
649
650 pub fn acquire(&mut self) -> ReconstructResult<FrameBuffer> {
658 if let Some(mut buffer) = self.available.pop_front() {
659 buffer.clear();
660 Ok(buffer)
661 } else {
662 Ok(FrameBuffer::new(
663 self.width,
664 self.height,
665 self.bit_depth,
666 self.subsampling,
667 ))
668 }
669 }
670
671 pub fn release(&mut self, buffer: FrameBuffer) {
673 if buffer.width == self.width
675 && buffer.height == self.height
676 && buffer.bit_depth == self.bit_depth
677 && self.available.len() < self.max_size
678 {
679 self.available.push_back(buffer);
680 }
681 }
682
683 #[must_use]
685 pub fn available_count(&self) -> usize {
686 self.available.len()
687 }
688
689 #[must_use]
691 pub fn is_empty(&self) -> bool {
692 self.available.is_empty()
693 }
694
695 pub fn reset(&mut self) {
697 self.available.clear();
698 }
699
700 pub fn reconfigure(
702 &mut self,
703 width: u32,
704 height: u32,
705 bit_depth: u8,
706 subsampling: ChromaSubsampling,
707 ) {
708 self.width = width;
709 self.height = height;
710 self.bit_depth = bit_depth;
711 self.subsampling = subsampling;
712 self.available.clear();
713 }
714}
715
716#[cfg(test)]
721mod tests {
722 use super::*;
723
724 #[test]
725 fn test_plane_buffer_new() {
726 let plane = PlaneBuffer::new(64, 48, 8, PlaneType::Y);
727 assert_eq!(plane.width(), 64);
728 assert_eq!(plane.height(), 48);
729 assert_eq!(plane.bit_depth(), 8);
730 assert_eq!(plane.plane_type(), PlaneType::Y);
731 }
732
733 #[test]
734 fn test_plane_buffer_get_set() {
735 let mut plane = PlaneBuffer::new(64, 48, 8, PlaneType::Y);
736 plane.set(10, 20, 128);
737 assert_eq!(plane.get(10, 20), 128);
738 assert_eq!(plane.get(0, 0), 0);
739 }
740
741 #[test]
742 fn test_plane_buffer_set_clamped() {
743 let mut plane = PlaneBuffer::new(64, 48, 8, PlaneType::Y);
744 plane.set_clamped(10, 20, 300);
745 assert_eq!(plane.get(10, 20), 255);
746
747 plane.set_clamped(10, 20, -50);
748 assert_eq!(plane.get(10, 20), 0);
749 }
750
751 #[test]
752 fn test_plane_buffer_row() {
753 let mut plane = PlaneBuffer::new(64, 48, 8, PlaneType::Y);
754 plane.set(5, 10, 100);
755 let row = plane.row(10);
756 assert_eq!(row[5], 100);
757 }
758
759 #[test]
760 fn test_plane_buffer_max_value() {
761 let plane8 = PlaneBuffer::new(64, 48, 8, PlaneType::Y);
762 assert_eq!(plane8.max_value(), 255);
763
764 let plane10 = PlaneBuffer::new(64, 48, 10, PlaneType::Y);
765 assert_eq!(plane10.max_value(), 1023);
766
767 let plane12 = PlaneBuffer::new(64, 48, 12, PlaneType::Y);
768 assert_eq!(plane12.max_value(), 4095);
769 }
770
771 #[test]
772 fn test_plane_buffer_copy_from() {
773 let mut src = PlaneBuffer::new(64, 48, 8, PlaneType::Y);
774 src.set(10, 20, 128);
775
776 let mut dst = PlaneBuffer::new(64, 48, 8, PlaneType::Y);
777 dst.copy_from(&src).expect("should succeed");
778
779 assert_eq!(dst.get(10, 20), 128);
780 }
781
782 #[test]
783 fn test_plane_buffer_to_u8() {
784 let mut plane = PlaneBuffer::new(4, 4, 8, PlaneType::Y);
785 plane.set(0, 0, 128);
786 plane.set(1, 0, 255);
787
788 let output = plane.to_u8();
789 assert_eq!(output.len(), 16);
790 assert_eq!(output[0], 128);
791 assert_eq!(output[1], 255);
792 }
793
794 #[test]
795 fn test_frame_buffer_new() {
796 let frame = FrameBuffer::new(1920, 1080, 8, ChromaSubsampling::Cs420);
797 assert_eq!(frame.width(), 1920);
798 assert_eq!(frame.height(), 1080);
799 assert_eq!(frame.bit_depth(), 8);
800 assert_eq!(frame.num_planes(), 3);
801 }
802
803 #[test]
804 fn test_frame_buffer_mono() {
805 let frame = FrameBuffer::new(1920, 1080, 8, ChromaSubsampling::Mono);
806 assert_eq!(frame.num_planes(), 1);
807 assert!(frame.u_plane().is_none());
808 assert!(frame.v_plane().is_none());
809 }
810
811 #[test]
812 fn test_frame_buffer_planes() {
813 let mut frame = FrameBuffer::new(64, 48, 8, ChromaSubsampling::Cs420);
814
815 frame.y_plane_mut().set(10, 10, 100);
816 assert_eq!(frame.y_plane().get(10, 10), 100);
817
818 if let Some(u) = frame.u_plane_mut() {
819 u.set(5, 5, 50);
820 }
821 assert_eq!(
822 frame.u_plane().expect("get should return value").get(5, 5),
823 50
824 );
825 }
826
827 #[test]
828 fn test_frame_buffer_copy_from() {
829 let mut src = FrameBuffer::new(64, 48, 8, ChromaSubsampling::Cs420);
830 src.y_plane_mut().set(10, 10, 100);
831
832 let mut dst = FrameBuffer::new(64, 48, 8, ChromaSubsampling::Cs420);
833 dst.copy_from(&src).expect("should succeed");
834
835 assert_eq!(dst.y_plane().get(10, 10), 100);
836 }
837
838 #[test]
839 fn test_reference_frame_manager() {
840 let mut mgr = ReferenceFrameManager::new();
841
842 assert!(!mgr.has_reference(0));
843
844 let frame = FrameBuffer::new(64, 48, 8, ChromaSubsampling::Cs420);
845 mgr.store(0, frame, 1);
846
847 assert!(mgr.has_reference(0));
848 assert_eq!(mgr.order_hint(0), 1);
849
850 let refs = mgr.valid_references();
851 assert_eq!(refs.len(), 1);
852 assert_eq!(refs[0], 0);
853 }
854
855 #[test]
856 fn test_reference_frame_manager_clear() {
857 let mut mgr = ReferenceFrameManager::new();
858
859 let frame = FrameBuffer::new(64, 48, 8, ChromaSubsampling::Cs420);
860 mgr.store(0, frame, 1);
861
862 mgr.clear_all();
863 assert!(!mgr.has_reference(0));
864 }
865
866 #[test]
867 fn test_buffer_pool() {
868 let mut pool = BufferPool::new(64, 48, 8, ChromaSubsampling::Cs420, 4);
869
870 assert!(pool.is_empty());
871
872 let buf1 = pool.acquire().expect("should succeed");
873 assert_eq!(buf1.width(), 64);
874
875 pool.release(buf1);
876 assert_eq!(pool.available_count(), 1);
877
878 let buf2 = pool.acquire().expect("should succeed");
879 assert!(pool.is_empty());
880 assert_eq!(buf2.width(), 64);
881 }
882
883 #[test]
884 fn test_buffer_pool_max_size() {
885 let mut pool = BufferPool::new(64, 48, 8, ChromaSubsampling::Cs420, 2);
886
887 let buf1 = pool.acquire().expect("should succeed");
888 let buf2 = pool.acquire().expect("should succeed");
889 let buf3 = pool.acquire().expect("should succeed");
890
891 pool.release(buf1);
892 pool.release(buf2);
893 pool.release(buf3); assert_eq!(pool.available_count(), 2);
896 }
897
898 #[test]
899 fn test_buffer_pool_reconfigure() {
900 let mut pool = BufferPool::new(64, 48, 8, ChromaSubsampling::Cs420, 4);
901
902 let buf = pool.acquire().expect("should succeed");
903 pool.release(buf);
904
905 pool.reconfigure(128, 96, 10, ChromaSubsampling::Cs422);
906 assert!(pool.is_empty());
907
908 let new_buf = pool.acquire().expect("should succeed");
909 assert_eq!(new_buf.width(), 128);
910 assert_eq!(new_buf.height(), 96);
911 assert_eq!(new_buf.bit_depth(), 10);
912 }
913}