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