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