• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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