• 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 //! This crate provides tools to help decode and encode various video codecs, leveraging the
6 //! hardware acceleration available on the target.
7 //!
8 //! The [codec] module contains tools to parse encoded video streams like H.264 or VP9 and extract
9 //! the information useful in order to perform e.g. hardware-accelerated decoding.
10 //!
11 //! The [backend] module contains common backend code. A backend is a provider of some way to
12 //! decode or encode a particular codec, like VAAPI.
13 //!
14 //! The [decoder] module contains decoders that can turn an encoded video stream into a sequence of
15 //! decoded frames using the hardware acceleration available on the host.
16 //!
17 //! The [encoder] module contains encoder that can turn a picture sequence into a compressed
18 //! sequence of decodable encoded packets using the hardware acceleration available on the host.
19 //!
20 //! The [utils] module contains some useful code that is shared between different parts of this
21 //! crate and didn't fit any of the modules above.
22 
23 pub mod bitstream_utils;
24 pub mod codec;
25 
26 #[cfg(feature = "backend")]
27 pub mod backend;
28 #[cfg(feature = "backend")]
29 pub mod c2_wrapper;
30 #[cfg(feature = "backend")]
31 pub mod decoder;
32 #[cfg(feature = "v4l2")]
33 pub mod device;
34 #[cfg(feature = "backend")]
35 pub mod encoder;
36 #[cfg(feature = "backend")]
37 pub mod image_processing;
38 #[cfg(feature = "backend")]
39 pub mod utils;
40 #[cfg(feature = "backend")]
41 pub mod video_frame;
42 
43 use std::str::FromStr;
44 
45 #[cfg(feature = "vaapi")]
46 pub use libva;
47 #[cfg(feature = "v4l2")]
48 pub use v4l2r;
49 
50 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
51 pub enum FrameMemoryType {
52     Managed,
53     Prime,
54     User,
55 }
56 
57 impl FromStr for FrameMemoryType {
58     type Err = &'static str;
59 
from_str(s: &str) -> Result<Self, Self::Err>60     fn from_str(s: &str) -> Result<Self, Self::Err> {
61         match s {
62             "managed" => Ok(FrameMemoryType::Managed),
63             "prime" => Ok(FrameMemoryType::Prime),
64             "user" => Ok(FrameMemoryType::User),
65             _ => Err("unrecognized memory type. Valid values: managed, prime, user"),
66         }
67     }
68 }
69 
70 /// Rounding modes for `Resolution`
71 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
72 pub enum ResolutionRoundMode {
73     /// Rounds component-wise to the next even value.
74     Even,
75 }
76 
77 /// A frame resolution in pixels.
78 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
79 pub struct Resolution {
80     pub width: u32,
81     pub height: u32,
82 }
83 
84 impl Resolution {
85     /// Whether `self` can contain `other`.
can_contain(&self, other: Self) -> bool86     pub fn can_contain(&self, other: Self) -> bool {
87         self.width >= other.width && self.height >= other.height
88     }
89 
90     /// Rounds `self` according to `rnd_mode`.
round(mut self, rnd_mode: ResolutionRoundMode) -> Self91     pub fn round(mut self, rnd_mode: ResolutionRoundMode) -> Self {
92         match rnd_mode {
93             ResolutionRoundMode::Even => {
94                 if self.width % 2 != 0 {
95                     self.width += 1;
96                 }
97 
98                 if self.height % 2 != 0 {
99                     self.height += 1;
100                 }
101             }
102         }
103 
104         self
105     }
106 
get_area(&self) -> usize107     pub fn get_area(&self) -> usize {
108         (self.width as usize) * (self.height as usize)
109     }
110 }
111 
112 impl From<(u32, u32)> for Resolution {
from(value: (u32, u32)) -> Self113     fn from(value: (u32, u32)) -> Self {
114         Self { width: value.0, height: value.1 }
115     }
116 }
117 
118 impl From<Resolution> for (u32, u32) {
from(value: Resolution) -> Self119     fn from(value: Resolution) -> Self {
120         (value.width, value.height)
121     }
122 }
123 
124 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
125 pub struct Rect {
126     pub x: u32,
127     pub y: u32,
128     pub width: u32,
129     pub height: u32,
130 }
131 
132 impl From<Rect> for Resolution {
from(value: Rect) -> Self133     fn from(value: Rect) -> Self {
134         Self { width: value.width - value.x, height: value.height - value.y }
135     }
136 }
137 
138 impl From<Resolution> for Rect {
from(value: Resolution) -> Self139     fn from(value: Resolution) -> Self {
140         Self { x: 0, y: 0, width: value.width, height: value.height }
141     }
142 }
143 
144 impl From<((u32, u32), (u32, u32))> for Rect {
from(value: ((u32, u32), (u32, u32))) -> Self145     fn from(value: ((u32, u32), (u32, u32))) -> Self {
146         Self { x: value.0 .0, y: value.0 .1, width: value.1 .0, height: value.1 .1 }
147     }
148 }
149 /// Wrapper around u32 when they are meant to be a fourcc.
150 ///
151 /// Provides conversion and display/debug implementations useful when dealing with fourcc codes.
152 #[derive(Clone, Copy, Default, PartialEq)]
153 pub struct Fourcc(u32);
154 
155 impl From<u32> for Fourcc {
from(fourcc: u32) -> Self156     fn from(fourcc: u32) -> Self {
157         Self(fourcc)
158     }
159 }
160 
161 impl From<Fourcc> for u32 {
from(fourcc: Fourcc) -> Self162     fn from(fourcc: Fourcc) -> Self {
163         fourcc.0
164     }
165 }
166 
167 impl From<&[u8; 4]> for Fourcc {
from(n: &[u8; 4]) -> Self168     fn from(n: &[u8; 4]) -> Self {
169         Self(n[0] as u32 | (n[1] as u32) << 8 | (n[2] as u32) << 16 | (n[3] as u32) << 24)
170     }
171 }
172 
173 impl From<Fourcc> for [u8; 4] {
from(n: Fourcc) -> Self174     fn from(n: Fourcc) -> Self {
175         [n.0 as u8, (n.0 >> 8) as u8, (n.0 >> 16) as u8, (n.0 >> 24) as u8]
176     }
177 }
178 
179 impl std::fmt::Display for Fourcc {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result180     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181         let c: [u8; 4] = (*self).into();
182 
183         f.write_fmt(format_args!(
184             "{}{}{}{}",
185             c[0] as char, c[1] as char, c[2] as char, c[3] as char
186         ))
187     }
188 }
189 
190 impl std::fmt::Debug for Fourcc {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result191     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192         f.write_fmt(format_args!("0x{:08x} ({})", self.0, self))
193     }
194 }
195 
196 /// Formats that buffers can be mapped into for the CPU to read.
197 ///
198 /// The conventions here largely follow these of libyuv.
199 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
200 pub enum DecodedFormat {
201     /// Y, U and V planes, 4:2:0 sampling, 8 bits per sample.
202     I420,
203     /// One Y and one interleaved UV plane, 4:2:0 sampling, 8 bits per sample.
204     NV12,
205     /// Y, U and V planes, 4:2:2 sampling, 8 bits per sample.
206     I422,
207     /// Y, U and V planes, 4:4:4 sampling, 8 bits per sample.
208     I444,
209     /// Y, U and V planes, 4:2:0 sampling, 16 bits per sample, LE. Only the 10 LSBs are used.
210     I010,
211     /// Y, U and V planes, 4:2:0 sampling, 16 bits per sample, LE. Only the 12 LSBs are used.
212     I012,
213     /// Y, U and V planes, 4:2:2 sampling, 16 bits per sample, LE. Only the 10 LSBs are used.
214     I210,
215     /// Y, U and V planes, 4:2:2 sampling, 16 bits per sample, LE. Only the 12 LSBs are used.
216     I212,
217     /// Y, U and V planes, 4:4:4 sampling, 16 bits per sample, LE. Only the 10 LSBs are used.
218     I410,
219     /// Y, U and V planes, 4:4:4 sampling, 16 bits per sample, LE. Only the 12 LSBs are used.
220     I412,
221     /// One Y and one interleaved UV plane, 4:2:0 sampling, 8 bits per sample.
222     /// In a tiled format.
223     MM21,
224 }
225 
226 impl FromStr for DecodedFormat {
227     type Err = &'static str;
228 
from_str(s: &str) -> Result<Self, Self::Err>229     fn from_str(s: &str) -> Result<Self, Self::Err> {
230         match s {
231             "i420" | "I420" => Ok(DecodedFormat::I420),
232             "i422" | "I422" => Ok(DecodedFormat::I422),
233             "i444" | "I444" => Ok(DecodedFormat::I444),
234             "nv12" | "NV12" => Ok(DecodedFormat::NV12),
235             "i010" | "I010" => Ok(DecodedFormat::I010),
236             "i012" | "I012" => Ok(DecodedFormat::I012),
237             "i210" | "I210" => Ok(DecodedFormat::I210),
238             "i212" | "I212" => Ok(DecodedFormat::I212),
239             "i410" | "I410" => Ok(DecodedFormat::I410),
240             "i412" | "I412" => Ok(DecodedFormat::I412),
241             "mm21" | "MM21" => Ok(DecodedFormat::MM21),
242             _ => Err("unrecognized output format. \
243                 Valid values: i420, nv12, i422, i444, i010, i012, i210, i212, i410, i412, mm21"),
244         }
245     }
246 }
247 
248 impl From<Fourcc> for DecodedFormat {
from(fourcc: Fourcc) -> DecodedFormat249     fn from(fourcc: Fourcc) -> DecodedFormat {
250         match fourcc.to_string().as_str() {
251             "I420" => DecodedFormat::I420,
252             "NV12" | "NM12" => DecodedFormat::NV12,
253             "MM21" => DecodedFormat::MM21,
254             _ => todo!("Fourcc {} not yet supported", fourcc),
255         }
256     }
257 }
258 
259 impl From<DecodedFormat> for Fourcc {
from(format: DecodedFormat) -> Fourcc260     fn from(format: DecodedFormat) -> Fourcc {
261         match format {
262             DecodedFormat::I420 => Fourcc::from(b"I420"),
263             DecodedFormat::NV12 => Fourcc::from(b"NV12"),
264             DecodedFormat::MM21 => Fourcc::from(b"MM21"),
265             _ => todo!(),
266         }
267     }
268 }
269 
270 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
271 pub enum EncodedFormat {
272     H264,
273     H265,
274     VP8,
275     VP9,
276     AV1,
277 }
278 
279 impl FromStr for EncodedFormat {
280     type Err = &'static str;
281 
from_str(s: &str) -> Result<Self, Self::Err>282     fn from_str(s: &str) -> Result<Self, Self::Err> {
283         match s {
284             "h264" | "H264" => Ok(EncodedFormat::H264),
285             "h265" | "H265" => Ok(EncodedFormat::H265),
286             "vp8" | "VP8" => Ok(EncodedFormat::VP8),
287             "vp9" | "VP9" => Ok(EncodedFormat::VP9),
288             "av1" | "AV1" => Ok(EncodedFormat::AV1),
289             _ => Err("unrecognized input format. Valid values: h264, h265, vp8, vp9, av1"),
290         }
291     }
292 }
293 
294 impl From<Fourcc> for EncodedFormat {
from(fourcc: Fourcc) -> EncodedFormat295     fn from(fourcc: Fourcc) -> EncodedFormat {
296         match fourcc.to_string().as_str() {
297             "H264" => EncodedFormat::H264,
298             "HEVC" => EncodedFormat::H265,
299             "VP80" => EncodedFormat::VP8,
300             "VP90" => EncodedFormat::VP9,
301             "AV1F" => EncodedFormat::AV1,
302             _ => todo!("Fourcc {} not yet supported", fourcc),
303         }
304     }
305 }
306 
307 impl From<EncodedFormat> for Fourcc {
from(format: EncodedFormat) -> Fourcc308     fn from(format: EncodedFormat) -> Fourcc {
309         match format {
310             EncodedFormat::H264 => Fourcc::from(b"H264"),
311             EncodedFormat::H265 => Fourcc::from(b"HEVC"),
312             EncodedFormat::VP8 => Fourcc::from(b"VP80"),
313             EncodedFormat::VP9 => Fourcc::from(b"VP90"),
314             EncodedFormat::AV1 => Fourcc::from(b"AV1F"),
315         }
316     }
317 }
318 
319 /// Describes the layout of a plane within a frame.
320 #[derive(Debug, Default, Clone, PartialEq)]
321 pub struct PlaneLayout {
322     /// Index of the memory buffer the plane belongs to.
323     pub buffer_index: usize,
324     /// Start offset of the plane within its buffer.
325     pub offset: usize,
326     /// Distance in bytes between two lines of data in this plane.
327     pub stride: usize,
328 }
329 
330 /// Unambiguously describes the layout of a frame.
331 ///
332 /// A frame can be made of one or several memory buffers, each containing one or several planes.
333 /// For a given frame, this structure defines where each plane can be found.
334 #[derive(Debug, Default, Clone, PartialEq)]
335 pub struct FrameLayout {
336     /// `(Fourcc, modifier)` tuple describing the arrangement of the planes.
337     ///
338     /// This member is enough to infer how many planes and buffers the frame has, and which
339     /// buffer each plane belongs into.
340     pub format: (Fourcc, u64),
341     /// Size in pixels of the frame.
342     pub size: Resolution,
343     /// Layout of each individual plane.
344     pub planes: Vec<PlaneLayout>,
345 }
346 
347 /// Build a frame memory descriptor enum that supports multiple descriptor types.
348 ///
349 /// This is useful for the case where the frames' memory backing is not decided at compile-time.
350 /// In this case, this macro can be used to list all the potential types supported at run-time, and
351 /// the selected one can be built as the program is run.
352 ///
353 /// # Example
354 ///
355 ///
356 /// use cros_codecs::multiple_desc_type;
357 /// use cros_codecs::utils::DmabufFrame;
358 ///
359 /// /// Frames' memory can be provided either by the backend, or via PRIME DMABUF handles.
360 /// multiple_desc_type! {
361 ///     enum OwnedOrDmaDescriptor {
362 ///         Owned(()),
363 ///         Dmabuf(DmabufFrame),
364 ///     }
365 /// }
366 ///
367 #[macro_export]
368 macro_rules! multiple_desc_type {
369     (enum $s:ident { $($v:ident($t:ty),)* } ) => {
370         pub enum $s {
371             $($v($t),)*
372         }
373 
374         #[cfg(feature = "vaapi")]
375         impl libva::SurfaceMemoryDescriptor for $s {
376             fn add_attrs(&mut self, attrs: &mut Vec<libva::VASurfaceAttrib>) -> Option<Box<dyn std::any::Any>> {
377                 match self {
378                     $($s::$v(desc) => desc.add_attrs(attrs),)*
379                 }
380             }
381         }
382     }
383 }
384 
385 /// Returns the size required to store a frame of `format` with size `width`x`height`, without any
386 /// padding. This is the minimum size of the destination buffer passed to `nv12_copy` or
387 /// `i420_copy`.
decoded_frame_size(format: DecodedFormat, width: usize, height: usize) -> usize388 pub fn decoded_frame_size(format: DecodedFormat, width: usize, height: usize) -> usize {
389     match format {
390         DecodedFormat::I420 | DecodedFormat::NV12 => {
391             let u_size = width * height;
392             // U and V planes need to be aligned to 2.
393             let uv_size = ((width + 1) / 2) * ((height + 1) / 2) * 2;
394 
395             u_size + uv_size
396         }
397         DecodedFormat::I422 => {
398             let u_size = width * height;
399             // U and V planes need to be aligned to 2.
400             let uv_size = ((width + 1) / 2) * ((height + 1) / 2) * 2 * 2;
401 
402             u_size + uv_size
403         }
404         DecodedFormat::I444 => (width * height) * 3,
405         DecodedFormat::I010 | DecodedFormat::I012 => {
406             decoded_frame_size(DecodedFormat::I420, width, height) * 2
407         }
408         DecodedFormat::I210 | DecodedFormat::I212 => {
409             let u_size = width * height * 2;
410             // U and V planes need to be aligned to 2.
411             let uv_size = ((width + 1) / 2) * ((height + 1) / 2) * 2 * 2;
412 
413             u_size + uv_size
414         }
415         DecodedFormat::I410 | DecodedFormat::I412 => (width * height * 2) * 3,
416         DecodedFormat::MM21 => panic!("Unable to convert to MM21"),
417     }
418 }
419 
420 /// Instructs on whether it should block on the operation(s).
421 #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
422 pub enum BlockingMode {
423     Blocking,
424     #[default]
425     NonBlocking,
426 }
427 
428 #[cfg(test)]
429 mod tests {
430     use super::Fourcc;
431 
432     const NV12_FOURCC: u32 = 0x3231564E;
433 
434     #[test]
fourcc_u32()435     fn fourcc_u32() {
436         let fourcc = Fourcc::from(NV12_FOURCC);
437         let value: u32 = fourcc.into();
438         assert_eq!(value, NV12_FOURCC);
439     }
440 
441     #[test]
fourcc_u8_4()442     fn fourcc_u8_4() {
443         let fourcc = Fourcc::from(NV12_FOURCC);
444         let value: [u8; 4] = fourcc.into();
445         assert_eq!(value, *b"NV12");
446     }
447 
448     #[test]
fourcc_display()449     fn fourcc_display() {
450         let fourcc = Fourcc::from(NV12_FOURCC);
451         assert_eq!(fourcc.to_string(), "NV12");
452     }
453 
454     #[test]
fourcc_debug()455     fn fourcc_debug() {
456         let fourcc = Fourcc::from(NV12_FOURCC);
457         assert_eq!(format!("{:?}", fourcc), "0x3231564e (NV12)");
458     }
459 }
460