1 use nix::fcntl::{open, OFlag};
2 use nix::sys::stat::Mode;
3 use std::collections::BTreeMap;
4 use std::fs::File;
5 use std::io::{self, Write};
6 use std::os::unix::io::FromRawFd;
7 use std::path::Path;
8 use std::sync::atomic::{AtomicBool, Ordering};
9 use std::sync::Arc;
10 use std::time::Instant;
11 use v4l2r_utils::framegen::FrameGenerator;
12
13 use v4l2r::memory::{MemoryType, MmapHandle};
14 use v4l2r::{ioctl::*, memory::UserPtrHandle};
15 use v4l2r::{Format, QueueType::*};
16
17 /// Run a sample encoder on device `device_path`, which must be a `vicodec`
18 /// 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, )19 pub fn run<F: FnMut(&[u8])>(
20 device_path: &Path,
21 output_mem: MemoryType,
22 capture_mem: MemoryType,
23 lets_quit: Arc<AtomicBool>,
24 stop_after: Option<usize>,
25 mut save_output: F,
26 ) {
27 let mut fd = unsafe {
28 File::from_raw_fd(
29 open(device_path, OFlag::O_RDWR | OFlag::O_CLOEXEC, Mode::empty())
30 .unwrap_or_else(|_| panic!("Cannot open {}", device_path.display())),
31 )
32 };
33
34 // Check that we are dealing with vicodec.
35 let caps: Capability = querycap(&fd).expect("Failed to get device capacities");
36 println!(
37 "Opened device: {}\n\tdriver: {}\n\tbus: {}\n\tcapabilities: {}",
38 caps.card, caps.driver, caps.bus_info, caps.capabilities
39 );
40
41 if caps.driver != "vicodec" {
42 panic!(
43 "This device is {}, but this test is designed to work with the vicodec driver.",
44 caps.driver
45 );
46 }
47
48 // Check whether the driver uses the single or multi-planar API by
49 // requesting 0 MMAP buffers on the OUTPUT queue. The working queue will
50 // return a success.
51 let (output_queue_type, _capture_queue_type, use_multi_planar) =
52 if reqbufs::<()>(&fd, VideoOutput, MemoryType::Mmap, 0).is_ok() {
53 (VideoOutput, VideoCapture, false)
54 } else if reqbufs::<()>(&fd, VideoOutputMplane, MemoryType::Mmap, 0).is_ok() {
55 (VideoOutputMplane, VideoCaptureMplane, true)
56 } else {
57 panic!("Both single-planar and multi-planar queues are unusable.");
58 };
59 println!(
60 "Multi-planar: {}",
61 if use_multi_planar { "yes" } else { "no" }
62 );
63
64 let (output_queue, capture_queue) = match use_multi_planar {
65 false => (VideoOutput, VideoCapture),
66 true => (VideoOutputMplane, VideoCaptureMplane),
67 };
68
69 // List the output formats.
70 let out_formats = FormatIterator::new(&fd, output_queue)
71 .map(|f| (f.pixelformat, f))
72 .collect::<BTreeMap<_, _>>();
73 println!("Output formats:");
74 for (_, fmtdesc) in out_formats.iter() {
75 println!("\t{}", fmtdesc);
76 }
77
78 // List the capture formats.
79 let cap_formats = FormatIterator::new(&fd, capture_queue)
80 .map(|f| (f.pixelformat, f))
81 .collect::<BTreeMap<_, _>>();
82 println!("Capture formats:");
83 for (_, fmtdesc) in cap_formats.iter() {
84 println!("\t{}", fmtdesc);
85 }
86
87 // We will encode from RGB3 to FWHT.
88 if !out_formats.contains_key(&b"RGB3".into()) {
89 panic!("RGB3 format not supported on OUTPUT queue.");
90 }
91
92 if !cap_formats.contains_key(&b"FWHT".into()) {
93 panic!("FWHT format not supported on CAPTURE queue.");
94 }
95
96 let mut capture_format: Format =
97 g_fmt(&fd, capture_queue).expect("Failed getting capture format");
98 // Let's just make sure the encoding format on the CAPTURE queue is FWHT.
99 capture_format.pixelformat = b"FWHT".into();
100 println!("Setting capture format: {:?}", capture_format);
101 let _capture_format: Format =
102 s_fmt(&mut fd, (capture_queue, &capture_format)).expect("Failed setting capture format");
103
104 // We will be happy with 640x480 resolution.
105 let output_format = Format {
106 width: 640,
107 height: 480,
108 pixelformat: b"RGB3".into(),
109 ..Default::default()
110 };
111
112 println!("Setting output format: {:?}", output_format);
113 let output_format: Format =
114 s_fmt(&mut fd, (output_queue, &output_format)).expect("Failed setting output format");
115
116 let capture_format: Format = g_fmt(&fd, capture_queue).expect("Failed getting capture format");
117 println!("Adjusted output format: {:?}", output_format);
118 println!("Adjusted capture format: {:?}", capture_format);
119
120 match output_mem {
121 MemoryType::Mmap => (),
122 MemoryType::UserPtr => (),
123 m => panic!("Unsupported OUTPUT memory type {:?}", m),
124 }
125
126 match capture_mem {
127 MemoryType::Mmap => (),
128 m => panic!("Unsupported CAPTURE memory type {:?}", m),
129 }
130
131 // We could run this with as little as one buffer, but let's cycle between
132 // two for the sake of it.
133 // For simplicity the OUTPUT buffers will use user memory.
134 let num_output_buffers: usize =
135 reqbufs(&fd, output_queue, output_mem, 2).expect("Failed to allocate output buffers");
136 let num_capture_buffers: usize =
137 reqbufs(&fd, capture_queue, capture_mem, 2).expect("Failed to allocate capture buffers");
138 println!(
139 "Using {} output and {} capture buffers.",
140 num_output_buffers, num_capture_buffers
141 );
142
143 let mut capture_mappings = Vec::new();
144 for i in 0..num_capture_buffers {
145 let query_buf: QueryBuffer =
146 querybuf(&fd, capture_queue, i).expect("Failed to query buffer");
147 println!(
148 "Capture buffer {} at offset 0x{:0x}, length 0x{:0x}",
149 i, query_buf.planes[0].mem_offset, query_buf.planes[0].length
150 );
151 capture_mappings.push(
152 mmap(
153 &fd,
154 query_buf.planes[0].mem_offset,
155 query_buf.planes[0].length,
156 )
157 .expect("Failed to map buffer"),
158 );
159 }
160
161 let output_image_size = output_format.plane_fmt[0].sizeimage as usize;
162 let mut output_buffers: Vec<UserPtrHandle<Vec<u8>>> = match output_mem {
163 MemoryType::Mmap => Default::default(),
164 MemoryType::UserPtr => std::iter::repeat(vec![0u8; output_image_size])
165 .take(num_output_buffers)
166 .map(UserPtrHandle::from)
167 .collect(),
168 _ => unreachable!(),
169 };
170
171 // Start streaming.
172 streamon(&fd, output_queue).expect("Failed to start output queue");
173 streamon(&fd, capture_queue).expect("Failed to start capture queue");
174
175 let mut frame_gen = FrameGenerator::new(
176 output_format.width as usize,
177 output_format.height as usize,
178 output_format.plane_fmt[0].bytesperline as usize,
179 )
180 .expect("Failed to create frame generator");
181
182 let mut cpt = 0usize;
183 let mut total_size = 0usize;
184 let start_time = Instant::now();
185 // Encode generated frames until Ctrl+c is pressed.
186 while !lets_quit.load(Ordering::SeqCst) {
187 if let Some(max_cpt) = stop_after {
188 if cpt >= max_cpt {
189 break;
190 }
191 }
192
193 let output_buffer_index = cpt % num_output_buffers;
194 let capture_buffer_index = cpt % num_output_buffers;
195
196 // Generate the frame data and buffer to queue.
197 match output_mem {
198 MemoryType::Mmap => {
199 let buffer_info: QueryBuffer =
200 querybuf(&fd, output_queue_type, output_buffer_index)
201 .expect("Failed to query output buffer");
202 let plane = &buffer_info.planes[0];
203 let mut mapping =
204 mmap(&fd, plane.mem_offset, plane.length).expect("Failed to map output buffer");
205
206 frame_gen
207 .next_frame(&mut mapping)
208 .expect("Failed to generate frame");
209
210 let mut out_qbuf =
211 QBuffer::<MmapHandle>::new(output_queue, output_buffer_index as u32);
212 out_qbuf.planes = vec![QBufPlane::new(frame_gen.frame_size())];
213
214 qbuf::<_, ()>(&fd, out_qbuf)
215 }
216 MemoryType::UserPtr => {
217 let output_buffer = &mut output_buffers[output_buffer_index];
218
219 frame_gen
220 .next_frame(&mut output_buffer.0)
221 .expect("Failed to generate frame");
222
223 let mut out_qbuf = QBuffer::<UserPtrHandle<Vec<u8>>>::new(
224 output_queue,
225 output_buffer_index as u32,
226 );
227 out_qbuf.planes = vec![QBufPlane::new_from_handle(
228 output_buffer,
229 output_buffer.0.len(),
230 )];
231
232 qbuf::<_, ()>(&fd, out_qbuf)
233 }
234 _ => unreachable!(),
235 }
236 .expect("Error queueing output buffer");
237
238 let mut cap_qbuf = QBuffer::<MmapHandle>::new(capture_queue, capture_buffer_index as u32);
239 cap_qbuf.planes = vec![QBufPlane::new(0)];
240
241 qbuf::<_, ()>(&fd, cap_qbuf).expect("Error queueing capture buffer");
242
243 // Now dequeue the work that we just scheduled.
244
245 // We can disregard the OUTPUT buffer since it does not contain any
246 // useful data for us.
247 dqbuf::<()>(&fd, output_queue).expect("Failed to dequeue output buffer");
248
249 // The CAPTURE buffer, on the other hand, we want to examine more closely.
250 let cap_dqbuf: V4l2Buffer =
251 dqbuf(&fd, capture_queue).expect("Failed to dequeue capture buffer");
252 let bytes_used = *cap_dqbuf.get_first_plane().bytesused as usize;
253
254 total_size = total_size.wrapping_add(bytes_used);
255 let elapsed = start_time.elapsed();
256 let fps = cpt as f64 / elapsed.as_millis() as f64 * 1000.0;
257 print!(
258 "\rEncoded buffer {:#5}, index: {:#2}), bytes used:{:#6} total encoded size:{:#8} fps: {:#5.2}",
259 cap_dqbuf.sequence(), cap_dqbuf.index(), bytes_used, total_size, fps
260 );
261 io::stdout().flush().unwrap();
262
263 save_output(&capture_mappings[cap_dqbuf.index() as usize].as_ref()[0..bytes_used]);
264
265 cpt = cpt.wrapping_add(1);
266 }
267
268 // Stop streaming.
269 streamoff(&fd, capture_queue).expect("Failed to stop capture queue");
270 streamoff(&fd, output_queue).expect("Failed to stop output queue");
271
272 // Clear the mappings
273 drop(capture_mappings);
274
275 // Free the buffers.
276 reqbufs::<()>(&fd, capture_queue, MemoryType::Mmap, 0)
277 .expect("Failed to release capture buffers");
278 reqbufs::<()>(&fd, output_queue, MemoryType::UserPtr, 0)
279 .expect("Failed to release output buffers");
280
281 // The fd will be closed as the File instance gets out of scope.
282 }
283