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