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