• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! Utility functions used by several parts of this crate.
6 //!
7 //! This module is for anything that doesn't fit into the other top-level modules. Try not to add
8 //! new code here unless it really doesn't belong anywhere else.
9 
10 use std::marker::Copy;
11 use std::ops::Add;
12 use std::ops::Div;
13 use std::ops::Mul;
14 use std::ops::Sub;
15 use std::os::fd::OwnedFd;
16 
17 use crate::Fourcc;
18 use crate::FrameLayout;
19 use crate::PlaneLayout;
20 use crate::Resolution;
21 
align_up<T>(x: T, alignment: T) -> T where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> + Mul<Output = T> + From<u8> + Copy,22 pub fn align_up<T>(x: T, alignment: T) -> T
23 where
24     T: Add<Output = T> + Sub<Output = T> + Div<Output = T> + Mul<Output = T> + From<u8> + Copy,
25 {
26     ((x + alignment - T::from(1)) / alignment) * alignment
27 }
28 
29 // This is the formula we use to approximate the maximum compressed buffer size for a video frame.
buffer_size_for_area(width: u32, height: u32) -> u3230 pub fn buffer_size_for_area(width: u32, height: u32) -> u32 {
31     let area = width * height;
32     let mut buffer_size: u32 = 1024 * 1024;
33 
34     if area > 720 * 480 {
35         buffer_size *= 2;
36     }
37     if area > 1920 * 1080 {
38         buffer_size *= 2;
39     }
40     buffer_size
41 }
42 
43 /// A structure that holds user-allocated memory for a frame as well as its layout.
44 #[derive(Debug)]
45 pub struct UserPtrFrame {
46     pub buffers: Vec<*mut u8>,
47     pub mem_layout: std::alloc::Layout,
48     pub layout: FrameLayout,
49 }
50 
51 impl UserPtrFrame {
52     /// Allocate enough memory to back a NV12 frame of `size` dimension.
new_nv12(size: Resolution) -> Self53     pub fn new_nv12(size: Resolution) -> Self {
54         /// Add what is needed to a value in order to make it a multiple of some alignment.
55         macro_rules! align {
56             ($n:expr, $r:expr) => {
57                 ($n + ($r - 1)) & !($r - 1)
58             };
59         }
60 
61         // Align according to VAAPI constraints.
62         let width = align!(size.width, 16) as usize;
63         let height = align!(size.height, 4) as usize;
64         let stride = align!(width, 64);
65         let uv_start = height * stride;
66         let uv_size = (height / 2) * stride;
67 
68         Self::alloc(
69             FrameLayout {
70                 format: (Fourcc::from(b"NV12"), 0),
71                 size: Resolution::from((width as u32, height as u32)),
72                 planes: vec![
73                     PlaneLayout { buffer_index: 0, offset: 0, stride },
74                     PlaneLayout { buffer_index: 0, offset: uv_start, stride },
75                 ],
76             },
77             uv_start.max(uv_size),
78         )
79     }
80 
alloc(layout: FrameLayout, buffer_size: usize) -> Self81     pub fn alloc(layout: FrameLayout, buffer_size: usize) -> Self {
82         let buffer_count = layout
83             .planes
84             .iter()
85             .map(|plane| plane.buffer_index)
86             .collect::<std::collections::HashSet<usize>>()
87             .len();
88 
89         // SAFETY: the invariants of `Layout` are respected.
90         let mem_layout =
91             unsafe { std::alloc::Layout::from_size_align_unchecked(buffer_size, 4096) };
92 
93         let buffers = (0..buffer_count)
94             .map(|_| {
95                 // SAFETY: the invariants of `Layout` are respected.
96                 unsafe { std::alloc::alloc(mem_layout) }
97             })
98             .collect();
99 
100         Self { buffers, mem_layout, layout }
101     }
102 }
103 
104 #[derive(Debug)]
105 pub struct DmabufFrame {
106     pub fds: Vec<OwnedFd>,
107     pub layout: FrameLayout,
108 }
109 
110 impl Drop for UserPtrFrame {
drop(&mut self)111     fn drop(&mut self) {
112         for buffer in std::mem::take(&mut self.buffers).into_iter() {
113             // Safe because we allocated the memory using `std::alloc::alloc`.
114             unsafe { std::alloc::dealloc(buffer, self.mem_layout) }
115         }
116     }
117 }
118