1 use std::io::{self, Write};
2 use std::path::Path;
3 use std::sync::atomic::{AtomicBool, Ordering};
4 use std::sync::Arc;
5 use std::time::Instant;
6 use v4l2r_utils::framegen::FrameGenerator;
7
8 use v4l2r::{device::queue::OutputQueueable, memory::MemoryType, Format};
9 use v4l2r::{device::queue::*, memory::MmapHandle};
10 use v4l2r::{
11 device::{
12 queue::generic::{GenericBufferHandles, GenericQBuffer, GenericSupportedMemoryType},
13 AllocatedQueue, Device, DeviceConfig, Stream, TryDequeue,
14 },
15 memory::UserPtrHandle,
16 };
17
18 /// Run a sample encoder on device `device_path`, which must be a `vicodec`
19 /// encoder instance. `lets_quit` will turn to true when Ctrl+C is pressed.
run<F: FnMut(&[u8])>( device_path: &Path, output_mem: MemoryType, capture_mem: MemoryType, lets_quit: Arc<AtomicBool>, stop_after: Option<usize>, mut save_output: F, )20 pub fn run<F: FnMut(&[u8])>(
21 device_path: &Path,
22 output_mem: MemoryType,
23 capture_mem: MemoryType,
24 lets_quit: Arc<AtomicBool>,
25 stop_after: Option<usize>,
26 mut save_output: F,
27 ) {
28 let device = Device::open(device_path, DeviceConfig::new()).expect("Failed to open device");
29 let caps = device.caps();
30 println!(
31 "Opened device: {}\n\tdriver: {}\n\tbus: {}\n\tcapabilities: {}",
32 caps.card, caps.driver, caps.bus_info, caps.capabilities
33 );
34 if caps.card != "vicodec" {
35 panic!(
36 "This device is {}, but this test is designed to work with the vicodec driver.",
37 caps.card
38 );
39 }
40
41 let device = Arc::new(device);
42
43 // Obtain the queues, depending on whether we are using the single or multi planar API.
44 let (mut output_queue, mut capture_queue, use_multi_planar) = if let Ok(output_queue) =
45 Queue::get_output_queue(Arc::clone(&device))
46 {
47 (
48 output_queue,
49 Queue::get_capture_queue(Arc::clone(&device)).expect("Failed to obtain capture queue"),
50 false,
51 )
52 } else if let Ok(output_queue) = Queue::get_output_mplane_queue(Arc::clone(&device)) {
53 (
54 output_queue,
55 Queue::get_capture_mplane_queue(Arc::clone(&device))
56 .expect("Failed to obtain capture queue"),
57 true,
58 )
59 } else {
60 panic!("Both single-planar and multi-planar queues are unusable.");
61 };
62
63 println!(
64 "Multi-planar: {}",
65 if use_multi_planar { "yes" } else { "no" }
66 );
67
68 println!("Output capabilities: {:?}", output_queue.get_capabilities());
69 println!(
70 "Capture capabilities: {:?}",
71 capture_queue.get_capabilities()
72 );
73
74 println!("Output formats:");
75 for fmtdesc in output_queue.format_iter() {
76 println!("\t{}", fmtdesc);
77 }
78
79 println!("Capture formats:");
80 for fmtdesc in capture_queue.format_iter() {
81 println!("\t{}", fmtdesc);
82 }
83
84 // Make sure the CAPTURE queue will produce FWHT.
85 let capture_format: Format = capture_queue
86 .change_format()
87 .expect("Failed to get capture format")
88 .set_pixelformat(b"FWHT")
89 .apply()
90 .expect("Failed to set capture format");
91
92 if capture_format.pixelformat != b"FWHT".into() {
93 panic!("FWHT format not supported on CAPTURE queue.");
94 }
95
96 // Set 640x480 RGB3 format on the OUTPUT queue.
97 let output_format: Format = output_queue
98 .change_format()
99 .expect("Failed to get output format")
100 .set_size(640, 480)
101 .set_pixelformat(b"RGB3")
102 .apply()
103 .expect("Failed to set output format");
104
105 if output_format.pixelformat != b"RGB3".into() {
106 panic!("RGB3 format not supported on OUTPUT queue.");
107 }
108
109 println!("Adjusted output format: {:?}", output_format);
110 let capture_format: Format = capture_queue
111 .get_format()
112 .expect("Failed to get capture format");
113 println!("Adjusted capture format: {:?}", capture_format);
114
115 let output_image_size = output_format.plane_fmt[0].sizeimage as usize;
116
117 match capture_mem {
118 MemoryType::Mmap => (),
119 m => panic!("Unsupported CAPTURE memory type {:?}", m),
120 }
121
122 // Move the queues into their "allocated" state.
123
124 let output_mem = match output_mem {
125 MemoryType::Mmap => GenericSupportedMemoryType::Mmap,
126 MemoryType::UserPtr => GenericSupportedMemoryType::UserPtr,
127 m => panic!("Unsupported OUTPUT memory type {:?}", m),
128 };
129
130 let output_queue = output_queue
131 .request_buffers_generic::<GenericBufferHandles>(output_mem, 2)
132 .expect("Failed to allocate output buffers");
133
134 let capture_queue = capture_queue
135 .request_buffers::<Vec<MmapHandle>>(2)
136 .expect("Failed to allocate output buffers");
137 println!(
138 "Using {} output and {} capture buffers.",
139 output_queue.num_buffers(),
140 capture_queue.num_buffers()
141 );
142
143 // If we use UserPtr OUTPUT buffers, create backing memory.
144 let mut output_frame = match output_mem {
145 GenericSupportedMemoryType::Mmap => None,
146 GenericSupportedMemoryType::UserPtr => Some(vec![0u8; output_image_size]),
147 GenericSupportedMemoryType::DmaBuf => todo!(),
148 };
149
150 output_queue
151 .stream_on()
152 .expect("Failed to start output_queue");
153 capture_queue.stream_on().expect("Failed to start capture");
154
155 let mut frame_gen = FrameGenerator::new(
156 output_format.width as usize,
157 output_format.height as usize,
158 output_format.plane_fmt[0].bytesperline as usize,
159 )
160 .expect("Failed to create frame generator");
161
162 let mut cpt = 0usize;
163 let mut total_size = 0usize;
164 let start_time = Instant::now();
165 // Encode generated frames until Ctrl+c is pressed.
166 while !lets_quit.load(Ordering::SeqCst) {
167 if let Some(max_cpt) = stop_after {
168 if cpt >= max_cpt {
169 break;
170 }
171 }
172
173 // There is no information to set on MMAP capture buffers: just queue
174 // them as soon as we get them.
175 capture_queue
176 .try_get_free_buffer()
177 .expect("Failed to obtain capture buffer")
178 .queue()
179 .expect("Failed to queue capture buffer");
180
181 // USERPTR output buffers, on the other hand, must be set up with
182 // a user buffer and bytes_used.
183 // The queue takes ownership of the buffer until the driver is done
184 // with it.
185 let output_buffer = output_queue
186 .try_get_buffer(0)
187 .expect("Failed to obtain output buffer");
188
189 match output_buffer {
190 GenericQBuffer::Mmap(buf) => {
191 let mut mapping = buf
192 .get_plane_mapping(0)
193 .expect("Failed to get MMAP mapping");
194
195 frame_gen
196 .next_frame(&mut mapping)
197 .expect("Failed to generate frame");
198
199 buf.queue(&[frame_gen.frame_size()])
200 .expect("Failed to queue output buffer");
201 }
202 GenericQBuffer::User(buf) => {
203 let mut output_buffer_data = output_frame
204 .take()
205 .expect("Output buffer not available. This is a bug.");
206
207 frame_gen
208 .next_frame(&mut output_buffer_data)
209 .expect("Failed to generate frame");
210
211 let bytes_used = frame_gen.frame_size();
212 buf.queue_with_handles(
213 GenericBufferHandles::from(vec![UserPtrHandle::from(output_buffer_data)]),
214 &[bytes_used],
215 )
216 .expect("Failed to queue output buffer");
217 }
218 GenericQBuffer::DmaBuf(_) => todo!(),
219 }
220
221 // Now dequeue the work that we just scheduled.
222
223 let mut out_dqbuf = output_queue
224 .try_dequeue()
225 .expect("Failed to dequeue output buffer");
226
227 // unwrap() is safe here as we just dequeued the buffer.
228 match &mut out_dqbuf.take_handles().unwrap() {
229 // For MMAP buffers we can just drop the reference.
230 GenericBufferHandles::Mmap(_) => (),
231 // For UserPtr buffers, make the buffer data available again. It
232 // should have been empty since the buffer was owned by the queue.
233 GenericBufferHandles::User(u) => {
234 assert_eq!(output_frame.replace(u.remove(0).0), None);
235 }
236 GenericBufferHandles::DmaBuf(_) => todo!(),
237 }
238
239 let cap_dqbuf = capture_queue
240 .try_dequeue()
241 .expect("Failed to dequeue capture buffer");
242 let cap_index = cap_dqbuf.data.index() as usize;
243 let bytes_used = *cap_dqbuf.data.get_first_plane().bytesused as usize;
244
245 total_size = total_size.wrapping_add(bytes_used);
246 let elapsed = start_time.elapsed();
247 let fps = cpt as f64 / elapsed.as_millis() as f64 * 1000.0;
248 print!(
249 "\rEncoded buffer {:#5}, {:#2} -> {:#2}), bytes used:{:#6} total encoded size:{:#8} fps: {:#5.2}",
250 cap_dqbuf.data.sequence(),
251 out_dqbuf.data.index(),
252 cap_index,
253 bytes_used,
254 total_size,
255 fps
256 );
257 io::stdout().flush().unwrap();
258
259 let cap_mapping = cap_dqbuf
260 .get_plane_mapping(0)
261 .expect("Failed to map capture buffer");
262 save_output(cap_mapping.as_ref());
263
264 cpt = cpt.wrapping_add(1);
265 }
266
267 capture_queue
268 .stream_off()
269 .expect("Failed to stop output_queue");
270 output_queue
271 .stream_off()
272 .expect("Failed to stop output_queue");
273 }
274