gstreamer_video/
video_decoder.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{mem, ptr};
4
5use glib::{prelude::*, translate::*};
6
7#[cfg(feature = "v1_16")]
8#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
9use crate::VideoInterlaceMode;
10use crate::{
11    ffi,
12    utils::HasStreamLock,
13    video_codec_state::{InNegotiation, Readable, VideoCodecState, VideoCodecStateContext},
14    VideoCodecFrame, VideoDecoder, VideoFormat,
15};
16
17extern "C" {
18    fn _gst_video_decoder_error(
19        dec: *mut ffi::GstVideoDecoder,
20        weight: i32,
21        domain: glib::ffi::GQuark,
22        code: i32,
23        txt: *mut libc::c_char,
24        debug: *mut libc::c_char,
25        file: *const libc::c_char,
26        function: *const libc::c_char,
27        line: i32,
28    ) -> gst::ffi::GstFlowReturn;
29}
30
31pub trait VideoDecoderExtManual: IsA<VideoDecoder> + 'static {
32    /// Helper function that allocates a buffer to hold a video frame for `self`'s
33    /// current [`VideoCodecState`][crate::VideoCodecState]. Subclass should already have configured video
34    /// state and set src pad caps.
35    ///
36    /// The buffer allocated here is owned by the frame and you should only
37    /// keep references to the frame, not the buffer.
38    /// ## `frame`
39    /// a [`VideoCodecFrame`][crate::VideoCodecFrame]
40    ///
41    /// # Returns
42    ///
43    /// [`gst::FlowReturn::Ok`][crate::gst::FlowReturn::Ok] if an output buffer could be allocated
44    #[doc(alias = "gst_video_decoder_allocate_output_frame")]
45    fn allocate_output_frame(
46        &self,
47        frame: &mut VideoCodecFrame,
48        params: Option<&gst::BufferPoolAcquireParams>,
49    ) -> Result<gst::FlowSuccess, gst::FlowError> {
50        unsafe {
51            let params_ptr = params.to_glib_none().0 as *mut _;
52            try_from_glib(ffi::gst_video_decoder_allocate_output_frame_with_params(
53                self.as_ref().to_glib_none().0,
54                frame.to_glib_none().0,
55                params_ptr,
56            ))
57        }
58    }
59
60    /// Get a pending unfinished [`VideoCodecFrame`][crate::VideoCodecFrame]
61    /// ## `frame_number`
62    /// system_frame_number of a frame
63    ///
64    /// # Returns
65    ///
66    /// pending unfinished [`VideoCodecFrame`][crate::VideoCodecFrame] identified by `frame_number`.
67    #[doc(alias = "get_frame")]
68    #[doc(alias = "gst_video_decoder_get_frame")]
69    fn frame(&self, frame_number: i32) -> Option<VideoCodecFrame> {
70        let frame = unsafe {
71            ffi::gst_video_decoder_get_frame(self.as_ref().to_glib_none().0, frame_number)
72        };
73
74        if frame.is_null() {
75            None
76        } else {
77            unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
78        }
79    }
80
81    /// Get all pending unfinished [`VideoCodecFrame`][crate::VideoCodecFrame]
82    ///
83    /// # Returns
84    ///
85    /// pending unfinished [`VideoCodecFrame`][crate::VideoCodecFrame].
86    #[doc(alias = "get_frames")]
87    #[doc(alias = "gst_video_decoder_get_frames")]
88    fn frames(&self) -> Vec<VideoCodecFrame> {
89        unsafe {
90            let frames = ffi::gst_video_decoder_get_frames(self.as_ref().to_glib_none().0);
91            let mut iter: *const glib::ffi::GList = frames;
92            let mut vec = Vec::new();
93
94            while !iter.is_null() {
95                let frame_ptr = Ptr::from((*iter).data);
96                /* transfer ownership of the frame */
97                let frame = VideoCodecFrame::new(frame_ptr, self.as_ref());
98                vec.push(frame);
99                iter = (*iter).next;
100            }
101
102            glib::ffi::g_list_free(frames);
103            vec
104        }
105    }
106
107    /// Get the oldest pending unfinished [`VideoCodecFrame`][crate::VideoCodecFrame]
108    ///
109    /// # Returns
110    ///
111    /// oldest pending unfinished [`VideoCodecFrame`][crate::VideoCodecFrame].
112    #[doc(alias = "get_oldest_frame")]
113    #[doc(alias = "gst_video_decoder_get_oldest_frame")]
114    fn oldest_frame(&self) -> Option<VideoCodecFrame> {
115        let frame =
116            unsafe { ffi::gst_video_decoder_get_oldest_frame(self.as_ref().to_glib_none().0) };
117
118        if frame.is_null() {
119            None
120        } else {
121            unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
122        }
123    }
124
125    /// Lets [`VideoDecoder`][crate::VideoDecoder] sub-classes to know the memory `allocator`
126    /// used by the base class and its `params`.
127    ///
128    /// Unref the `allocator` after use it.
129    ///
130    /// # Returns
131    ///
132    ///
133    /// ## `allocator`
134    /// the [`gst::Allocator`][crate::gst::Allocator]
135    /// used
136    ///
137    /// ## `params`
138    /// the
139    /// [`gst::AllocationParams`][crate::gst::AllocationParams] of `allocator`
140    #[doc(alias = "get_allocator")]
141    #[doc(alias = "gst_video_decoder_get_allocator")]
142    fn allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams) {
143        unsafe {
144            let mut allocator = ptr::null_mut();
145            let mut params = mem::MaybeUninit::uninit();
146            ffi::gst_video_decoder_get_allocator(
147                self.as_ref().to_glib_none().0,
148                &mut allocator,
149                params.as_mut_ptr(),
150            );
151            (from_glib_full(allocator), params.assume_init().into())
152        }
153    }
154    /// Query the configured decoder latency. Results will be returned via
155    /// `min_latency` and `max_latency`.
156    ///
157    /// # Returns
158    ///
159    ///
160    /// ## `min_latency`
161    /// address of variable in which to store the
162    ///  configured minimum latency, or [`None`]
163    ///
164    /// ## `max_latency`
165    /// address of variable in which to store the
166    ///  configured mximum latency, or [`None`]
167    #[doc(alias = "get_latency")]
168    #[doc(alias = "gst_video_decoder_get_latency")]
169    fn latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>) {
170        let mut min_latency = gst::ffi::GST_CLOCK_TIME_NONE;
171        let mut max_latency = gst::ffi::GST_CLOCK_TIME_NONE;
172
173        unsafe {
174            ffi::gst_video_decoder_get_latency(
175                self.as_ref().to_glib_none().0,
176                &mut min_latency,
177                &mut max_latency,
178            );
179
180            (
181                try_from_glib(min_latency).expect("undefined min_latency"),
182                from_glib(max_latency),
183            )
184        }
185    }
186
187    /// Lets [`VideoDecoder`][crate::VideoDecoder] sub-classes tell the baseclass what the decoder latency
188    /// is. If the provided values changed from previously provided ones, this will
189    /// also post a LATENCY message on the bus so the pipeline can reconfigure its
190    /// global latency.
191    /// ## `min_latency`
192    /// minimum latency
193    /// ## `max_latency`
194    /// maximum latency
195    #[doc(alias = "gst_video_decoder_set_latency")]
196    fn set_latency(
197        &self,
198        min_latency: gst::ClockTime,
199        max_latency: impl Into<Option<gst::ClockTime>>,
200    ) {
201        unsafe {
202            ffi::gst_video_decoder_set_latency(
203                self.as_ref().to_glib_none().0,
204                min_latency.into_glib(),
205                max_latency.into().into_glib(),
206            );
207        }
208    }
209
210    /// Get the [`VideoCodecState`][crate::VideoCodecState] currently describing the output stream.
211    ///
212    /// # Returns
213    ///
214    /// [`VideoCodecState`][crate::VideoCodecState] describing format of video data.
215    #[doc(alias = "get_output_state")]
216    #[doc(alias = "gst_video_decoder_get_output_state")]
217    fn output_state(&self) -> Option<VideoCodecState<'static, Readable>> {
218        let state =
219            unsafe { ffi::gst_video_decoder_get_output_state(self.as_ref().to_glib_none().0) };
220
221        if state.is_null() {
222            None
223        } else {
224            unsafe { Some(VideoCodecState::<Readable>::new(state)) }
225        }
226    }
227
228    /// Creates a new [`VideoCodecState`][crate::VideoCodecState] with the specified `fmt`, `width` and `height`
229    /// as the output state for the decoder.
230    /// Any previously set output state on `self` will be replaced by the newly
231    /// created one.
232    ///
233    /// If the subclass wishes to copy over existing fields (like pixel aspec ratio,
234    /// or framerate) from an existing [`VideoCodecState`][crate::VideoCodecState], it can be provided as a
235    /// `reference`.
236    ///
237    /// If the subclass wishes to override some fields from the output state (like
238    /// pixel-aspect-ratio or framerate) it can do so on the returned [`VideoCodecState`][crate::VideoCodecState].
239    ///
240    /// The new output state will only take effect (set on pads and buffers) starting
241    /// from the next call to [`VideoDecoderExt::finish_frame()`][crate::prelude::VideoDecoderExt::finish_frame()].
242    /// ## `fmt`
243    /// a [`VideoFormat`][crate::VideoFormat]
244    /// ## `width`
245    /// The width in pixels
246    /// ## `height`
247    /// The height in pixels
248    /// ## `reference`
249    /// An optional reference [`VideoCodecState`][crate::VideoCodecState]
250    ///
251    /// # Returns
252    ///
253    /// the newly configured output state.
254    #[doc(alias = "gst_video_decoder_set_output_state")]
255    fn set_output_state(
256        &self,
257        fmt: VideoFormat,
258        width: u32,
259        height: u32,
260        reference: Option<&VideoCodecState<Readable>>,
261    ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError> {
262        let state = unsafe {
263            let reference = match reference {
264                Some(reference) => reference.as_mut_ptr(),
265                None => ptr::null_mut(),
266            };
267            ffi::gst_video_decoder_set_output_state(
268                self.as_ref().to_glib_none().0,
269                fmt.into_glib(),
270                width,
271                height,
272                reference,
273            )
274        };
275
276        if state.is_null() {
277            Err(gst::FlowError::NotNegotiated)
278        } else {
279            unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
280        }
281    }
282
283    /// Same as [`set_output_state()`][Self::set_output_state()] but also allows you to also set
284    /// the interlacing mode.
285    /// ## `fmt`
286    /// a [`VideoFormat`][crate::VideoFormat]
287    /// ## `interlace_mode`
288    /// A [`VideoInterlaceMode`][crate::VideoInterlaceMode]
289    /// ## `width`
290    /// The width in pixels
291    /// ## `height`
292    /// The height in pixels
293    /// ## `reference`
294    /// An optional reference [`VideoCodecState`][crate::VideoCodecState]
295    ///
296    /// # Returns
297    ///
298    /// the newly configured output state.
299    #[cfg(feature = "v1_16")]
300    #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
301    #[doc(alias = "gst_video_decoder_set_interlaced_output_state")]
302    fn set_interlaced_output_state(
303        &self,
304        fmt: VideoFormat,
305        mode: VideoInterlaceMode,
306        width: u32,
307        height: u32,
308        reference: Option<&VideoCodecState<Readable>>,
309    ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError> {
310        let state = unsafe {
311            let reference = match reference {
312                Some(reference) => reference.as_mut_ptr(),
313                None => ptr::null_mut(),
314            };
315            ffi::gst_video_decoder_set_interlaced_output_state(
316                self.as_ref().to_glib_none().0,
317                fmt.into_glib(),
318                mode.into_glib(),
319                width,
320                height,
321                reference,
322            )
323        };
324
325        if state.is_null() {
326            Err(gst::FlowError::NotNegotiated)
327        } else {
328            unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
329        }
330    }
331
332    /// Negotiate with downstream elements to currently configured [`VideoCodecState`][crate::VideoCodecState].
333    /// Unmark GST_PAD_FLAG_NEED_RECONFIGURE in any case. But mark it again if
334    /// negotiate fails.
335    ///
336    /// # Returns
337    ///
338    /// [`true`] if the negotiation succeeded, else [`false`].
339    #[doc(alias = "gst_video_decoder_negotiate")]
340    fn negotiate<'a>(
341        &'a self,
342        output_state: VideoCodecState<'a, InNegotiation<'a>>,
343    ) -> Result<(), gst::FlowError> {
344        // Consume output_state so user won't be able to modify it anymore
345        let self_ptr = self.to_glib_none().0 as *const gst::ffi::GstElement;
346        assert_eq!(output_state.context.element_as_ptr(), self_ptr);
347
348        let ret = unsafe {
349            from_glib(ffi::gst_video_decoder_negotiate(
350                self.as_ref().to_glib_none().0,
351            ))
352        };
353        if ret {
354            Ok(())
355        } else {
356            Err(gst::FlowError::NotNegotiated)
357        }
358    }
359
360    #[allow(clippy::too_many_arguments)]
361    fn error<T: gst::MessageErrorDomain>(
362        &self,
363        weight: i32,
364        code: T,
365        message: Option<&str>,
366        debug: Option<&str>,
367        file: &str,
368        function: &str,
369        line: u32,
370    ) -> Result<gst::FlowSuccess, gst::FlowError> {
371        unsafe {
372            try_from_glib(_gst_video_decoder_error(
373                self.as_ref().to_glib_none().0,
374                weight,
375                T::domain().into_glib(),
376                code.code(),
377                message.to_glib_full(),
378                debug.to_glib_full(),
379                file.to_glib_none().0,
380                function.to_glib_none().0,
381                line as i32,
382            ))
383        }
384    }
385
386    fn sink_pad(&self) -> &gst::Pad {
387        unsafe {
388            let elt = &*(self.as_ptr() as *const ffi::GstVideoDecoder);
389            &*(&elt.sinkpad as *const *mut gst::ffi::GstPad as *const gst::Pad)
390        }
391    }
392
393    fn src_pad(&self) -> &gst::Pad {
394        unsafe {
395            let elt = &*(self.as_ptr() as *const ffi::GstVideoDecoder);
396            &*(&elt.srcpad as *const *mut gst::ffi::GstPad as *const gst::Pad)
397        }
398    }
399
400    fn input_segment(&self) -> gst::Segment {
401        unsafe {
402            let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _);
403            glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock));
404            let segment = ptr.input_segment;
405            glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock));
406            from_glib_none(&segment as *const gst::ffi::GstSegment)
407        }
408    }
409
410    fn output_segment(&self) -> gst::Segment {
411        unsafe {
412            let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _);
413            glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock));
414            let segment = ptr.output_segment;
415            glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock));
416            from_glib_none(&segment as *const gst::ffi::GstSegment)
417        }
418    }
419}
420
421impl<O: IsA<VideoDecoder>> VideoDecoderExtManual for O {}
422
423impl HasStreamLock for VideoDecoder {
424    fn stream_lock(&self) -> *mut glib::ffi::GRecMutex {
425        let decoder_sys: *const ffi::GstVideoDecoder = self.to_glib_none().0;
426        unsafe { mut_override(&(*decoder_sys).stream_lock) }
427    }
428
429    fn element_as_ptr(&self) -> *const gst::ffi::GstElement {
430        self.as_ptr() as *mut gst::ffi::GstElement
431    }
432}
433
434#[macro_export]
435macro_rules! video_decoder_error(
436    ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
437        use $crate::prelude::VideoDecoderExtManual;
438        $obj.error(
439            $weight,
440            $err,
441            Some(&format!($($msg)*)),
442            Some(&format!($($debug)*)),
443            file!(),
444            $crate::glib::function_name!(),
445            line!(),
446        )
447    }};
448    ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*)) => { {
449        use $crate::prelude::VideoDecoderExtManual;
450        $obj.error(
451            $weight,
452            $err,
453            Some(&format!($($msg)*)),
454            None,
455            file!(),
456            $crate::glib::function_name!(),
457            line!(),
458        )
459    }};
460    ($obj:expr, $weight:expr, $err:expr, [$($debug:tt)*]) => { {
461        use $crate::prelude::VideoDecoderExtManual;
462        $obj.error(
463            $weight,
464            $err,
465            None,
466            Some(&format!($($debug)*)),
467            file!(),
468            $crate::glib::function_name!(),
469            line!(),
470        )
471    }};
472);