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