• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2025 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 use std::sync::Arc;
6 
7 use crate::backend::v4l2::encoder::find_device_with_capture;
8 use crate::backend::v4l2::encoder::MmapingCapture;
9 use crate::c2_wrapper::c2_encoder::C2EncoderBackend;
10 use crate::encoder::stateful::h264::v4l2::V4L2StatefulH264Encoder;
11 use crate::encoder::stateful::vp8::v4l2::V4L2StatefulVP8Encoder;
12 use crate::encoder::stateful::vp9::v4l2::V4L2StatefulVP9Encoder;
13 use crate::encoder::VideoEncoder;
14 use crate::video_frame::V4l2VideoFrame;
15 use crate::video_frame::VideoFrame;
16 use crate::DecodedFormat;
17 use crate::EncodedFormat;
18 use crate::Fourcc;
19 use crate::Resolution;
20 
21 use v4l2r::device::Device;
22 use v4l2r::device::DeviceConfig;
23 
v4l2_format_to_coded_size(format: &v4l2r::Format) -> Resolution24 fn v4l2_format_to_coded_size(format: &v4l2r::Format) -> Resolution {
25     let stride = format.plane_fmt[0].bytesperline;
26     let size = format.plane_fmt[0].sizeimage;
27     Resolution { width: stride, height: size / stride }
28 }
29 
30 #[derive(Clone, Debug)]
31 pub struct C2V4L2EncoderOptions {
32     pub output_fourcc: Fourcc,
33     pub visible_resolution: Resolution,
34 }
35 
36 pub struct C2V4L2Encoder {
37     visible_resolution: Resolution,
38     device: Arc<Device>,
39 }
40 
41 impl C2EncoderBackend for C2V4L2Encoder {
42     type EncoderOptions = C2V4L2EncoderOptions;
43 
new(options: C2V4L2EncoderOptions) -> Result<Self, String>44     fn new(options: C2V4L2EncoderOptions) -> Result<Self, String> {
45         let pixel_format = v4l2r::PixelFormat::from_u32(u32::from(options.output_fourcc));
46         let device = find_device_with_capture(pixel_format)
47             .ok_or("Could not find V4L2 device!".to_string())?;
48         let device = Device::open(&device, DeviceConfig::new().non_blocking_dqbuf())
49             .map_err(|err| format!("Error opening V4L2 device! {:?}", err))?;
50         Ok(Self { visible_resolution: options.visible_resolution, device: Arc::new(device) })
51     }
52 
get_encoder<V: VideoFrame>( &mut self, input_format: DecodedFormat, output_format: EncodedFormat, ) -> Result<(Box<dyn VideoEncoder<V4l2VideoFrame<V>>>, Resolution, Resolution), String>53     fn get_encoder<V: VideoFrame>(
54         &mut self,
55         input_format: DecodedFormat,
56         output_format: EncodedFormat,
57     ) -> Result<(Box<dyn VideoEncoder<V4l2VideoFrame<V>>>, Resolution, Resolution), String> {
58         Ok(match output_format {
59             EncodedFormat::H264 => {
60                 let mut encoder = V4L2StatefulH264Encoder::new(
61                     self.device.clone(),
62                     MmapingCapture,
63                     crate::encoder::h264::EncoderConfig {
64                         resolution: self.visible_resolution.clone(),
65                         ..Default::default()
66                     },
67                     Fourcc::from(input_format),
68                     self.visible_resolution.clone(),
69                     Default::default(),
70                 )
71                 .map_err(|err| format!("Error initializing encoder! {:?}", err))?;
72                 let coded_format = encoder
73                     .backend()
74                     .output_format()
75                     .map_err(|err| format!("Error querying backend format! {:?}", err))?;
76                 (
77                     Box::new(encoder),
78                     self.visible_resolution.clone(),
79                     v4l2_format_to_coded_size(&coded_format),
80                 )
81             }
82             EncodedFormat::VP8 => {
83                 let mut encoder = V4L2StatefulVP8Encoder::new(
84                     self.device.clone(),
85                     MmapingCapture,
86                     crate::encoder::vp8::EncoderConfig {
87                         resolution: self.visible_resolution.clone(),
88                         ..Default::default()
89                     },
90                     Fourcc::from(input_format),
91                     self.visible_resolution.clone(),
92                     Default::default(),
93                 )
94                 .map_err(|err| format!("Error initializing encoder! {:?}", err))?;
95                 let coded_format = encoder
96                     .backend()
97                     .output_format()
98                     .map_err(|err| format!("Error querying backend format! {:?}", err))?;
99                 (
100                     Box::new(encoder),
101                     self.visible_resolution.clone(),
102                     v4l2_format_to_coded_size(&coded_format),
103                 )
104             }
105             EncodedFormat::VP9 => {
106                 let mut encoder = V4L2StatefulVP9Encoder::new(
107                     self.device.clone(),
108                     MmapingCapture,
109                     crate::encoder::vp9::EncoderConfig {
110                         resolution: self.visible_resolution.clone(),
111                         ..Default::default()
112                     },
113                     Fourcc::from(input_format),
114                     self.visible_resolution.clone(),
115                     Default::default(),
116                 )
117                 .map_err(|err| format!("Error initializing encoder! {:?}", err))?;
118                 let coded_format = encoder
119                     .backend()
120                     .output_format()
121                     .map_err(|err| format!("Error querying backend format! {:?}", err))?;
122                 (
123                     Box::new(encoder),
124                     self.visible_resolution.clone(),
125                     v4l2_format_to_coded_size(&coded_format),
126                 )
127             }
128             _ => return Err(format!("Format not supported by V4L2! {:?}", output_format)),
129         })
130     }
131 }
132