1 //! Module for creating and controlling V4L2 decoders.
2 //!
3 //! Decoders are created using [`v4l2r_decoder_new`] and remain
4 //! active until being given to [`v4l2r_decoder_destroy`]. They expect
5 //! to be fed encoded buffers in the format specified at creation time using
6 //! [`v4l2r_decoder_decode`].
7 //!
8 //! Decoders communicate with the client using an event callback that is invoked
9 //! on a dedicated thread. This callback signals events of interest, like a
10 //! frame being decoded, or a change in the output format (due to e.g. a dynamic
11 //! resolution change). The output format is initially undefined and a format
12 //! change event will be produced before any frame can be decoded.
13 #![allow(non_camel_case_types)]
14
15 use log::{debug, error, info, warn};
16 use nix::sys::time::{TimeVal, TimeValLike};
17 use std::{
18 ffi::CStr,
19 mem::MaybeUninit,
20 os::raw::{c_char, c_int, c_uint, c_void},
21 path::Path,
22 sync::Arc,
23 };
24 use v4l2r::{
25 bindings,
26 decoder::{
27 stateful::{Decoder, Decoding, DrainError},
28 CompletedInputBuffer, DecoderEvent, DecoderEventCallback, FormatChangedCallback,
29 FormatChangedReply, InputDoneCallback,
30 },
31 device::queue::{direction::Capture, dqbuf::DqBuffer, FormatBuilder, OutputQueueable},
32 memory::DmaBufHandle,
33 PixelFormat, PlaneLayout, Rect,
34 };
35
36 use crate::memory::{
37 v4l2r_video_frame, v4l2r_video_frame_provider, v4l2r_video_frame_provider_queue_frame,
38 DmaBufFd, VideoFrameMemoryType,
39 };
40
41 type DynCbDecoder = Decoder<
42 Decoding<
43 Vec<DmaBufHandle<DmaBufFd>>,
44 Arc<v4l2r_video_frame_provider>,
45 Box<dyn InputDoneCallback<Vec<DmaBufHandle<DmaBufFd>>>>,
46 Box<dyn DecoderEventCallback<Arc<v4l2r_video_frame_provider>>>,
47 Box<dyn FormatChangedCallback<Arc<v4l2r_video_frame_provider>>>,
48 >,
49 >;
50
51 /// A V4L2 decoder instance.
52 pub struct v4l2r_decoder {
53 decoder: DynCbDecoder,
54 // Reference to the video frame provider for our callbacks.
55 provider: Option<Arc<v4l2r_video_frame_provider>>,
56 // Keep the size of input buffers at hand.
57 input_buf_size: u64,
58 }
59
60 /// Callback called when the decoder is done with a buffer submitted using
61 /// [`v4l2r_decoder_decode`].
62 ///
63 /// The first argument is the `cb_data` pointer given
64 /// to [`v4l2r_decoder_new`]. The second argument is the dequeued V4L2 buffer.
65 /// The client can use the `timestamp.tv_sec` member of `buffer` to match this
66 /// buffer with the `bitstream_id` parameter of [`v4l2r_decoder_decode`] and
67 /// understand which buffer has just completed.
68 ///
69 /// This callback is only called during calls to [`v4l2r_decoder_decode`] and
70 /// [`v4l2r_decoder_kick`].
71 pub type v4l2r_decoder_input_done_cb = extern "C" fn(*mut c_void, *const bindings::v4l2_buffer);
72
73 #[repr(C)]
74 pub struct v4l2r_decoder_frame_decoded_event {
75 /// Dequeued V4L2 buffer that has produced the frame. Useful to check for
76 /// flags and errors.
77 buffer: *const bindings::v4l2_buffer,
78 /// One of the frames previously made available to the decoder using
79 /// [`v4l2r_video_frame_provider_queue_frame`].
80 ///
81 /// [`v4l2r_video_frame_provider_queue_frame`]:
82 /// crate::memory::v4l2r_video_frame_provider_queue_frame
83 frame: v4l2r_video_frame,
84 }
85
86 /// Event produced every time the output format of the stream changes.
87 /// This includes when the initial format is determined by the decoder, and any
88 /// subsequent dynamic resolution change in the stream.
89 #[repr(C)]
90 pub struct v4l2r_decoder_format_changed_event {
91 /// New format for decoded frames produced after this event.
92 new_format: *mut bindings::v4l2_format,
93 /// Visible rectangle for decoded frames produced after this event.
94 visible_rect: bindings::v4l2_rect,
95 /// Pointer to the video frame provider the client must use to provide
96 /// frames to decode into.
97 ///
98 /// When the client receives this event, it must stop using the previous
99 /// video frame provider (if any) as soon as possible and destroy it using
100 /// `v4l2r_video_frame_provider_drop`. Any video frame still queued to an
101 /// old provider and that has not been seen in a previous `FrameDecoded`
102 /// event can be considered as returned to the client. Upon receiving this
103 /// event, the client is guaranteed to not receive any frame in the previous
104 /// format, or from the previous provider.
105 ///
106 /// The client is responsible for allocating video frames in the new format
107 /// and start giving them to the new provider using
108 /// [`v4l2r_video_frame_provider_queue_frame`].
109 ///
110 /// [`v4l2r_video_frame_provider_queue_frame`]:
111 /// crate::memory::v4l2r_video_frame_provider_queue_frame
112 new_provider: *const v4l2r_video_frame_provider,
113 /// Minimum number of output buffers required by the decoder to operate
114 /// properly.
115 ///
116 /// The client must allocate at least `min_num_frames` (but no more than
117 /// 32), otherwise the decoder might starve.
118 min_num_frames: c_uint,
119 }
120
121 /// Decoding-related events. These events can be produced at any time between
122 /// calls to [`v4l2r_decoder_new`] and [`v4l2r_decoder_destroy`] and
123 /// are passed to the events callback.
124 #[repr(C)]
125 pub enum v4l2r_decoder_event {
126 // TODO for frames that have a zero-size, just recycle the handles
127 // on-the-spot and pass the relevant event instead!
128 FrameDecoded(v4l2r_decoder_frame_decoded_event),
129 FormatChanged(v4l2r_decoder_format_changed_event),
130 EndOfStream,
131 }
132
133 /// Events callback. This callback is guaranteed to always be called from the
134 /// same thread, i.e. events are completely sequential.
135 pub type v4l2r_decoder_event_cb = extern "C" fn(*mut c_void, *mut v4l2r_decoder_event);
136
set_capture_format_cb( f: FormatBuilder, desired_pixel_format: Option<PixelFormat>, visible_rect: Rect, min_num_buffers: usize, decoder: &mut v4l2r_decoder, event_cb: v4l2r_decoder_event_cb, cb_data: *mut c_void, ) -> anyhow::Result<FormatChangedReply<Arc<v4l2r_video_frame_provider>>>137 fn set_capture_format_cb(
138 f: FormatBuilder,
139 desired_pixel_format: Option<PixelFormat>,
140 visible_rect: Rect,
141 min_num_buffers: usize,
142 decoder: &mut v4l2r_decoder,
143 event_cb: v4l2r_decoder_event_cb,
144 cb_data: *mut c_void,
145 ) -> anyhow::Result<FormatChangedReply<Arc<v4l2r_video_frame_provider>>> {
146 let mut v4l2_format: bindings::v4l2_format = match desired_pixel_format {
147 Some(format) => f.set_pixelformat(format).apply()?,
148 None => f.apply()?,
149 };
150
151 // Create new memory provider on the heap and update our internal pointer.
152 let new_provider = Arc::new(v4l2r_video_frame_provider::new());
153 // Reference for our own callbacks.
154 decoder.provider = Some(Arc::clone(&new_provider));
155
156 // Reference owned by the client. Will be dropped when it calls
157 // `v4l2r_video_frame_provider_drop`.
158 let provider_client_ref = Arc::clone(&new_provider);
159
160 // TODO check return value.
161 event_cb(
162 cb_data,
163 &mut v4l2r_decoder_event::FormatChanged(v4l2r_decoder_format_changed_event {
164 new_format: &mut v4l2_format,
165 visible_rect: visible_rect.into(),
166 new_provider: Arc::into_raw(provider_client_ref),
167 min_num_frames: min_num_buffers as c_uint,
168 }),
169 );
170
171 Ok(FormatChangedReply {
172 provider: new_provider,
173 // TODO: can't the provider report the memory type that it is
174 // actually serving itself?
175 mem_type: VideoFrameMemoryType,
176 // Since we are using DMABUF, always allocate the maximum number of
177 // V4L2 buffers (32) since they are virtually free. This gives more
178 // flexibility for the client as to how many frames it can allocate.
179 num_buffers: bindings::VIDEO_MAX_FRAME as usize,
180 })
181 }
182
frame_decoded_cb( decoder: &mut v4l2r_decoder, mut dqbuf: DqBuffer<Capture, v4l2r_video_frame>, event_cb: v4l2r_decoder_event_cb, cb_data: *mut c_void, )183 fn frame_decoded_cb(
184 decoder: &mut v4l2r_decoder,
185 mut dqbuf: DqBuffer<Capture, v4l2r_video_frame>,
186 event_cb: v4l2r_decoder_event_cb,
187 cb_data: *mut c_void,
188 ) {
189 let frame = dqbuf.take_handles().unwrap();
190 debug!(
191 "Video frame {} ({}) decoded from V4L2 buffer {} (flags: {:?})",
192 frame.id,
193 dqbuf.data.timestamp().tv_sec,
194 dqbuf.data.index(),
195 dqbuf.data.flags(),
196 );
197 let mut v4l2_data = dqbuf.data.clone();
198 // Drop the DQBuffer early so the C callback can reuse the V4L2
199 // buffer if it needs to.
200 drop(dqbuf);
201
202 // Immediately recycle empty frames. We will pass the corresponding
203 // event to the client.
204 if *v4l2_data.get_first_plane().bytesused == 0 {
205 debug!(
206 "Immediately recycling zero-sized frame {} {}",
207 frame.id,
208 v4l2_data.is_last()
209 );
210 // Should be safe as `provider` is initialized in the format
211 // change callback and is thus valid, as well as `frame`.
212 match &decoder.provider {
213 // SAFETY: `provider` is a valid pointer to a frame provider.
214 Some(provider) => unsafe {
215 v4l2r_video_frame_provider_queue_frame(provider.as_ref(), frame);
216 },
217 None => {
218 error!("Frame decoded callback called while no provider set!");
219 }
220 }
221 } else {
222 // TODO check return value?
223 event_cb(
224 cb_data,
225 &mut v4l2r_decoder_event::FrameDecoded(v4l2r_decoder_frame_decoded_event {
226 buffer: v4l2_data.as_mut_ptr() as *const _,
227 frame,
228 }),
229 );
230 }
231 }
232
233 // A void pointer that can be sent across threads. This is usually not allowed
234 // by Rust, but is necessary for us to call back into the V4L2RustDecoder.
235 struct SendablePtr<T>(*mut T);
236 impl<T> Clone for SendablePtr<T> {
clone(&self) -> Self237 fn clone(&self) -> Self {
238 *self
239 }
240 }
241 impl<T> Copy for SendablePtr<T> {}
242 unsafe impl<T> Send for SendablePtr<T> {}
243 unsafe impl<T> Sync for SendablePtr<T> {}
244
245 #[allow(clippy::too_many_arguments)]
v4l2r_decoder_new_safe( path: &Path, input_format_fourcc: u32, num_input_buffers: usize, input_buffer_size: usize, output_format_fourcc: u32, input_done_cb: v4l2r_decoder_input_done_cb, event_cb: v4l2r_decoder_event_cb, cb_data: *mut c_void, ) -> *mut v4l2r_decoder246 fn v4l2r_decoder_new_safe(
247 path: &Path,
248 input_format_fourcc: u32,
249 num_input_buffers: usize,
250 input_buffer_size: usize,
251 output_format_fourcc: u32,
252 input_done_cb: v4l2r_decoder_input_done_cb,
253 event_cb: v4l2r_decoder_event_cb,
254 cb_data: *mut c_void,
255 ) -> *mut v4l2r_decoder {
256 let decoder = match Decoder::open(path) {
257 Ok(decoder) => decoder,
258 Err(e) => {
259 error!("failed to open decoder {}: {:#?}", path.display(), e);
260 return std::ptr::null_mut();
261 }
262 };
263
264 info!(
265 "Opened decoder {} with format {}, {} input buffers of size {}",
266 path.display(),
267 v4l2r::PixelFormat::from(input_format_fourcc),
268 num_input_buffers,
269 input_buffer_size
270 );
271
272 let format_builder = |f: FormatBuilder| {
273 let pixel_format = input_format_fourcc.into();
274 let format = match f
275 .set_pixelformat(pixel_format)
276 .set_planes_layout(vec![PlaneLayout {
277 sizeimage: input_buffer_size as u32,
278 ..Default::default()
279 }])
280 .apply::<v4l2r::Format>()
281 {
282 Ok(format) if format.pixelformat == pixel_format => format,
283 Ok(_) => {
284 return Err(anyhow::anyhow!(
285 "Unrecognized OUTPUT format {:?}",
286 pixel_format
287 ))
288 }
289 Err(e) => return Err(e.into()),
290 };
291 debug!(
292 "Decoder requires input buffer size of: {}",
293 format.plane_fmt[0].sizeimage
294 );
295 Ok(())
296 };
297 let decoder = match decoder.set_output_format(format_builder) {
298 Ok(decoder) => decoder,
299 Err(e) => {
300 error!("Error while setting output format: {}", e);
301 return std::ptr::null_mut();
302 }
303 };
304
305 let output_format = match output_format_fourcc {
306 0 => None,
307 fourcc => Some(PixelFormat::from(fourcc)),
308 };
309
310 let cb_data = SendablePtr(cb_data);
311
312 let decoder =
313 match decoder.allocate_output_buffers::<Vec<DmaBufHandle<DmaBufFd>>>(num_input_buffers) {
314 Ok(decoder) => decoder,
315 Err(e) => {
316 error!("Error while allocating OUTPUT buffers: {}", e);
317 return std::ptr::null_mut();
318 }
319 };
320
321 // Reserve memory on the heap for our decoder and take a pointer that we
322 // can use in our callbacks.
323 let mut decoder_box = Box::new(MaybeUninit::<v4l2r_decoder>::uninit());
324 let decoder_ptr = SendablePtr(decoder_box.as_mut_ptr());
325
326 let event_handler = move |event: DecoderEvent<Arc<v4l2r_video_frame_provider>>| {
327 // Make Rust 2021 happy.
328 let decoder_ptr = decoder_ptr;
329 let cb_data = cb_data;
330
331 // SAFETY: `decoder_ptr` will be initialized with a valid decoder by the time this
332 // callback is called.
333 let decoder = unsafe { decoder_ptr.0.as_mut().unwrap() };
334
335 match event {
336 DecoderEvent::FrameDecoded(dqbuf) => {
337 frame_decoded_cb(decoder, dqbuf, event_cb, cb_data.0)
338 }
339 DecoderEvent::EndOfStream => event_cb(cb_data.0, &mut v4l2r_decoder_event::EndOfStream),
340 };
341 };
342
343 let res = decoder.start(
344 Box::new(
345 move |buf: CompletedInputBuffer<Vec<DmaBufHandle<DmaBufFd>>>| {
346 match buf {
347 CompletedInputBuffer::Dequeued(mut dqbuf) => {
348 debug!("Input buffer {} done", dqbuf.data.index());
349 // TODO check return value?
350 input_done_cb(cb_data.0, dqbuf.data.as_mut_ptr() as *const _);
351 }
352 // Just drop canceled buffers for now - the client will remove
353 // them on its side as well.
354 // TODO add a status parameter to the callback and invoke it?
355 // that way the client does not need to clear its own list...
356 CompletedInputBuffer::Canceled(_) => (),
357 }
358 },
359 ) as Box<dyn InputDoneCallback<Vec<DmaBufHandle<DmaBufFd>>>>,
360 Box::new(event_handler) as Box<dyn DecoderEventCallback<Arc<v4l2r_video_frame_provider>>>,
361 Box::new(
362 move |f: FormatBuilder,
363 visible_rect: Rect,
364 min_num_buffers: usize|
365 -> anyhow::Result<FormatChangedReply<Arc<v4l2r_video_frame_provider>>> {
366 // Make Rust 2021 happy.
367 let decoder_ptr = decoder_ptr;
368 let cb_data = cb_data;
369
370 // SAFETY: `decoder_ptr` will be initialized with a valid decoder by the time this
371 // callback is called.
372 let decoder = unsafe { decoder_ptr.0.as_mut().unwrap() };
373
374 set_capture_format_cb(
375 f,
376 output_format,
377 visible_rect,
378 min_num_buffers,
379 decoder,
380 event_cb,
381 cb_data.0,
382 )
383 },
384 ) as Box<dyn FormatChangedCallback<Arc<v4l2r_video_frame_provider>>>,
385 );
386
387 let decoder = match res {
388 Ok(decoder) => decoder,
389 Err(e) => {
390 error!("Cannot start decoder: {}", e);
391 return std::ptr::null_mut();
392 }
393 };
394
395 let input_format: v4l2r::Format = decoder.get_output_format().unwrap();
396
397 let decoder = v4l2r_decoder {
398 decoder,
399 provider: None,
400 input_buf_size: input_format.plane_fmt[0].sizeimage as u64,
401 };
402
403 // SAFETY: `decoder` is a `v4l2r_decoder`, the same type expected by `decoder_box`.
404 let decoder_box = unsafe {
405 // Replace our uninitialized heap memory with our valid decoder.
406 decoder_box.as_mut_ptr().write(decoder);
407 // Convert the Box<MaybeUninit<v4l2r_decoder>> into Box<v4l2r_decoder>
408 // now that we know the decoder is properly initialized. It would be
409 // better to use Box::assume_init but as of rustc 1.50 this method is
410 // still in nightly only.
411 Box::from_raw(Box::into_raw(decoder_box) as *mut v4l2r_decoder)
412 };
413
414 info!("Decoder {:p}: successfully started", decoder_box.as_ref());
415
416 Box::into_raw(decoder_box)
417 }
418
v4l2r_decoder_decode_safe( decoder: &mut v4l2r_decoder, bitstream_id: i32, fd: c_int, bytes_used: usize, ) -> c_int419 fn v4l2r_decoder_decode_safe(
420 decoder: &mut v4l2r_decoder,
421 bitstream_id: i32,
422 fd: c_int,
423 bytes_used: usize,
424 ) -> c_int {
425 let v4l2_buffer = match decoder.decoder.get_buffer() {
426 Ok(buffer) => buffer,
427 Err(e) => {
428 error!("Error obtaining V4L2 buffer: {}", e);
429 return -1;
430 }
431 };
432 let v4l2_buffer_id = v4l2_buffer.index();
433
434 match v4l2_buffer
435 .set_timestamp(TimeVal::seconds(bitstream_id as i64))
436 .queue_with_handles(
437 vec![DmaBufHandle::from(DmaBufFd::new(
438 fd,
439 decoder.input_buf_size,
440 ))],
441 &[bytes_used],
442 ) {
443 Ok(()) => (),
444 Err(e) => {
445 error!("Error while queueing buffer: {}", e);
446 return -1;
447 }
448 };
449
450 v4l2_buffer_id as c_int
451 }
452
453 /// Create a new decoder for a given encoded format.
454 ///
455 /// * `path` is the path to the V4L2 device that will be used for decoding.
456 /// * `input_format_fourcc` is the FOURCC code of the encoded format we will
457 /// decode, e.g. "H264" or "VP80".
458 /// * `num_input_buffers` is the number of input buffers we wish to use. It
459 /// should correspond to the number of different buffers containing input data
460 /// that will be given to this decoder.
461 /// * `input_buffer_size` is the desired size of input buffers. The decoder may
462 /// adjust this value, so the client should call
463 /// [`v4l2r_decoder_get_input_format`] to confirm the actual expected value.
464 /// * `output_format_fourcc` is the FOURCC code of the desired pixel format for
465 /// output frames (e.g. "NV12"). It can also be 0, in which case the decoder
466 /// will use whichever pixel format is active by default.
467 /// * `input_done_cb` is a pointer to a callback function to be called whenever
468 /// an encoded input buffer is done being processed. This callback is
469 /// guaranteed to be invoked during calls to [`v4l2r_decoder_decode`] or
470 /// [`v4l2r_decoder_kick`], i.e. it will always be called in the current
471 /// thread.
472 /// * `event_cb` is a pointer to a function to be called for handling the
473 /// various events produced by the decoder. See [`v4l2r_decoder_event`] for
474 /// more details on events. This callback is guaranteed to be called from a
475 /// separate, unique thread, therefore the events can be assumed to be
476 /// sequential (i.e. two events cannot be produced at the same time from two
477 /// different threads).
478 /// * `cb_data` is a pointer that will always be passed as the first parameter
479 /// of the `input_done_cb` and `events_cb`.
480 ///
481 /// # Safety
482 /// The passed `path` must be a valid, zero-terminated C string containining the
483 /// path to the device. Expect a crash if passing an invalid string.
484 #[no_mangle]
v4l2r_decoder_new( path: *const c_char, input_format_fourcc: u32, num_input_buffers: usize, input_buffer_size: usize, output_format_fourcc: u32, input_done_cb: v4l2r_decoder_input_done_cb, event_cb: v4l2r_decoder_event_cb, cb_data: *mut c_void, ) -> *mut v4l2r_decoder485 pub unsafe extern "C" fn v4l2r_decoder_new(
486 path: *const c_char,
487 input_format_fourcc: u32,
488 num_input_buffers: usize,
489 input_buffer_size: usize,
490 output_format_fourcc: u32,
491 input_done_cb: v4l2r_decoder_input_done_cb,
492 event_cb: v4l2r_decoder_event_cb,
493 cb_data: *mut c_void,
494 ) -> *mut v4l2r_decoder {
495 let cstr = CStr::from_ptr(path);
496 let rstr = cstr.to_str().unwrap();
497 let path = Path::new(&rstr);
498
499 v4l2r_decoder_new_safe(
500 path,
501 input_format_fourcc,
502 num_input_buffers,
503 input_buffer_size,
504 output_format_fourcc,
505 input_done_cb,
506 event_cb,
507 cb_data,
508 )
509 }
510
511 /// Stop and destroy a decoder.
512 ///
513 /// Stop `decoder` and destroy it. This function DOES take ownership of
514 /// `decoder`, which must absolutely not be used after this call.
515 ///
516 /// It is guaranteed that none of the callbacks passed to [`v4l2r_decoder_new`]
517 /// will be called after this function has returned.
518 ///
519 /// # Safety
520 ///
521 /// `decoder` must be a valid pointer to a decoder returned by
522 /// `v4l2r_decoder_new`. Passing a NULL or invalid pointer will cause a crash.
523 /// `decoder` must not be used again after this function is called.
524 #[no_mangle]
v4l2r_decoder_destroy(decoder: *mut v4l2r_decoder)525 pub unsafe extern "C" fn v4l2r_decoder_destroy(decoder: *mut v4l2r_decoder) {
526 info!("Decoder {:p}: destroying", decoder);
527
528 if decoder.is_null() {
529 warn!("Trying to destroy a NULL decoder");
530 return;
531 }
532
533 let decoder = Box::from_raw(decoder);
534 match decoder.decoder.stop() {
535 Ok(_) => (),
536 Err(e) => error!("Error while stopping decoder: {}", e),
537 }
538 }
539
540 /// Obtain the current input format (i.e. the format set on the *OUTPUT* queue).
541 ///
542 /// Obtain the current input format for `decoder` and write it into `format`.
543 /// This function can be called at any time since a decoder always have a valid
544 /// input format.
545 ///
546 /// Returns 0 in case of success, -1 if an error occured, in which case `format`
547 /// is not overwritten.
548 ///
549 /// # Safety
550 ///
551 /// `decoder` must be a valid pointer to a decoder instance. `format` must point
552 /// to valid memory that can receive a `v4l2_format`
553 #[no_mangle]
v4l2r_decoder_get_input_format( decoder: *const v4l2r_decoder, format: *mut bindings::v4l2_format, ) -> c_int554 pub unsafe extern "C" fn v4l2r_decoder_get_input_format(
555 decoder: *const v4l2r_decoder,
556 format: *mut bindings::v4l2_format,
557 ) -> c_int {
558 assert!(!decoder.is_null());
559 assert!(!format.is_null());
560
561 let decoder = &*decoder;
562 let format = &mut *format;
563
564 *format = match decoder.decoder.get_output_format() {
565 Ok(format) => format,
566 Err(e) => {
567 error!("Error while getting output format: {}", e);
568 return -1;
569 }
570 };
571
572 0
573 }
574
575 /// Decode the encoded data referenced by `fd`.
576 ///
577 /// The decoder does NOT take ownership of `fd` and won't close it.
578 ///
579 /// `bitstream_id` is the identifier of this input buffer. The produced frames
580 /// will carry this identifier in they timestamp.
581 ///
582 /// `bytes_used` is amount of encoded data within that buffer.
583 ///
584 /// The value returned is the index of the V4L2 buffer `fd` has been queued with.
585 /// It can be used to know when `fd` is done being decoded as a `v4l2_buffer` of
586 /// the same index will be passed as argument to the *input done callback* when
587 /// this is the case.
588 ///
589 /// In case of error, -1 is returned.
590 ///
591 /// # Safety
592 ///
593 /// `decoder` must be a valid pointer to a decoder returned by
594 /// [`v4l2r_decoder_new`]. Passing a NULL or invalid pointer will cause a crash.
595 /// `fd` is expected to be a valid DMABUF FD backed by enough memory for the
596 /// expected input buffer size. Failure to provide a valid FD will return in an
597 /// ioctl error (but no crash).
598 #[no_mangle]
v4l2r_decoder_decode( decoder: *mut v4l2r_decoder, bitstream_id: i32, fd: c_int, bytes_used: usize, ) -> c_int599 pub unsafe extern "C" fn v4l2r_decoder_decode(
600 decoder: *mut v4l2r_decoder,
601 bitstream_id: i32,
602 fd: c_int,
603 bytes_used: usize,
604 ) -> c_int {
605 debug!(
606 "Decoder {:p}: decoding bitstream id {}",
607 decoder, bitstream_id
608 );
609 assert!(!decoder.is_null());
610 let decoder = &mut *decoder;
611
612 v4l2r_decoder_decode_safe(decoder, bitstream_id, fd, bytes_used)
613 }
614
615 /// Kick the decoder and see if some input buffers fall as a result.
616 ///
617 /// No, really. Completed input buffers are typically checked when calling
618 /// [`v4l2r_decoder_decode`] (which is also the time when the input done
619 /// callback is invoked), but this mechanism is not foolproof: if the client
620 /// works with a limited set of input buffers and queues them all before an
621 /// output frame can be produced, then the client has no more material to call
622 /// [`v4l2r_decoder_decode`] with and thus no input buffer will ever be
623 /// dequeued, resulting in the decoder being blocked.
624 ///
625 /// This method mitigates this problem by adding a way to check for completed
626 /// input buffers and calling the input done callback without the need for new
627 /// encoded content. It is suggested to call it from the same thread that
628 /// invokes [`v4l2r_decoder_decode`] every time we get a
629 /// [`v4l2r_decoder_frame_decoded_event`]. That way the client can recycle its
630 /// input buffers and the decoding process does not get stuck.
631 ///
632 /// # Safety
633 ///
634 /// `decoder` must be a valid pointer to a decoder returned by
635 /// [`v4l2r_decoder_new`]. Passing a NULL or invalid pointer will cause a crash.
636 #[no_mangle]
v4l2r_decoder_kick(decoder: *const v4l2r_decoder)637 pub unsafe extern "C" fn v4l2r_decoder_kick(decoder: *const v4l2r_decoder) {
638 assert!(!decoder.is_null());
639 let decoder = &*decoder;
640
641 match decoder.decoder.kick() {
642 Ok(()) => (),
643 Err(e) => {
644 error!("Error while kicking decoder: {}", e);
645 }
646 }
647 }
648
649 /// Possible responses for the [`v4l2r_decoder_drain`] commmand.
650 #[repr(C)]
651 #[allow(clippy::upper_case_acronyms)]
652 pub enum v4l2r_decoder_drain_response {
653 /// The drain has already completed as [`v4l2r_decoder_drain`] returned.
654 DRAIN_COMPLETED,
655 /// The drain has started but will be completed when we receive a
656 /// [`v4l2r_decoder_event::EndOfStream`] event.
657 DRAIN_STARTED,
658 /// Drain cannot be done at the moment because not enough input buffers
659 /// have been processed to know the output format.
660 TRY_AGAIN,
661 /// An error has occurred.
662 ERROR,
663 }
664
665 /// # Safety
666 ///
667 /// `decoder` must be a valid pointer to a decoder returned by
668 /// [`v4l2r_decoder_new`]. Passing a NULL or invalid pointer will cause a crash.
669 #[no_mangle]
v4l2r_decoder_drain( decoder: *const v4l2r_decoder, blocking: bool, ) -> v4l2r_decoder_drain_response670 pub unsafe extern "C" fn v4l2r_decoder_drain(
671 decoder: *const v4l2r_decoder,
672 blocking: bool,
673 ) -> v4l2r_decoder_drain_response {
674 assert!(!decoder.is_null());
675 let decoder = &*decoder;
676
677 match decoder.decoder.drain(blocking) {
678 Ok(true) => v4l2r_decoder_drain_response::DRAIN_COMPLETED,
679 Ok(false) => v4l2r_decoder_drain_response::DRAIN_STARTED,
680 Err(DrainError::TryAgain) => v4l2r_decoder_drain_response::TRY_AGAIN,
681 Err(e) => {
682 error!("Error while draining decoder: {}", e);
683 v4l2r_decoder_drain_response::ERROR
684 }
685 }
686 }
687
688 /// # Safety
689 ///
690 /// `decoder` must be a valid pointer to a decoder returned by
691 /// [`v4l2r_decoder_new`]. Passing a NULL or invalid pointer will cause a crash.
692 #[no_mangle]
v4l2r_decoder_flush(decoder: *const v4l2r_decoder)693 pub unsafe extern "C" fn v4l2r_decoder_flush(decoder: *const v4l2r_decoder) {
694 assert!(!decoder.is_null());
695 let decoder = &*decoder;
696
697 match decoder.decoder.flush() {
698 Ok(()) => (),
699 Err(e) => {
700 error!("Error while flushing decoder: {:#?}", e);
701 }
702 }
703 }
704