Skip to main content

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