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    #[doc(alias = "gst_video_decoder_allocate_output_frame")]
33    fn allocate_output_frame(
34        &self,
35        frame: &mut VideoCodecFrame,
36        params: Option<&gst::BufferPoolAcquireParams>,
37    ) -> Result<gst::FlowSuccess, gst::FlowError> {
38        unsafe {
39            let params_ptr = params.to_glib_none().0 as *mut _;
40            try_from_glib(ffi::gst_video_decoder_allocate_output_frame_with_params(
41                self.as_ref().to_glib_none().0,
42                frame.to_glib_none().0,
43                params_ptr,
44            ))
45        }
46    }
47
48    #[doc(alias = "get_frame")]
49    #[doc(alias = "gst_video_decoder_get_frame")]
50    fn frame(&self, frame_number: i32) -> Option<VideoCodecFrame<'_>> {
51        let frame = unsafe {
52            ffi::gst_video_decoder_get_frame(self.as_ref().to_glib_none().0, frame_number)
53        };
54
55        if frame.is_null() {
56            None
57        } else {
58            unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
59        }
60    }
61
62    #[doc(alias = "get_frames")]
63    #[doc(alias = "gst_video_decoder_get_frames")]
64    fn frames(&self) -> Vec<VideoCodecFrame<'_>> {
65        unsafe {
66            let frames = ffi::gst_video_decoder_get_frames(self.as_ref().to_glib_none().0);
67            let mut iter: *const glib::ffi::GList = frames;
68            let mut vec = Vec::new();
69
70            while !iter.is_null() {
71                let frame_ptr = Ptr::from((*iter).data);
72                /* transfer ownership of the frame */
73                let frame = VideoCodecFrame::new(frame_ptr, self.as_ref());
74                vec.push(frame);
75                iter = (*iter).next;
76            }
77
78            glib::ffi::g_list_free(frames);
79            vec
80        }
81    }
82
83    #[doc(alias = "get_oldest_frame")]
84    #[doc(alias = "gst_video_decoder_get_oldest_frame")]
85    fn oldest_frame(&self) -> Option<VideoCodecFrame<'_>> {
86        let frame =
87            unsafe { ffi::gst_video_decoder_get_oldest_frame(self.as_ref().to_glib_none().0) };
88
89        if frame.is_null() {
90            None
91        } else {
92            unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
93        }
94    }
95
96    #[doc(alias = "get_allocator")]
97    #[doc(alias = "gst_video_decoder_get_allocator")]
98    fn allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams) {
99        unsafe {
100            let mut allocator = ptr::null_mut();
101            let mut params = mem::MaybeUninit::uninit();
102            ffi::gst_video_decoder_get_allocator(
103                self.as_ref().to_glib_none().0,
104                &mut allocator,
105                params.as_mut_ptr(),
106            );
107            (from_glib_full(allocator), params.assume_init().into())
108        }
109    }
110    #[doc(alias = "get_latency")]
111    #[doc(alias = "gst_video_decoder_get_latency")]
112    fn latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>) {
113        let mut min_latency = gst::ffi::GST_CLOCK_TIME_NONE;
114        let mut max_latency = gst::ffi::GST_CLOCK_TIME_NONE;
115
116        unsafe {
117            ffi::gst_video_decoder_get_latency(
118                self.as_ref().to_glib_none().0,
119                &mut min_latency,
120                &mut max_latency,
121            );
122
123            (
124                try_from_glib(min_latency).expect("undefined min_latency"),
125                from_glib(max_latency),
126            )
127        }
128    }
129
130    #[doc(alias = "gst_video_decoder_set_latency")]
131    fn set_latency(
132        &self,
133        min_latency: gst::ClockTime,
134        max_latency: impl Into<Option<gst::ClockTime>>,
135    ) {
136        unsafe {
137            ffi::gst_video_decoder_set_latency(
138                self.as_ref().to_glib_none().0,
139                min_latency.into_glib(),
140                max_latency.into().into_glib(),
141            );
142        }
143    }
144
145    #[doc(alias = "get_output_state")]
146    #[doc(alias = "gst_video_decoder_get_output_state")]
147    fn output_state(&self) -> Option<VideoCodecState<'static, Readable>> {
148        let state =
149            unsafe { ffi::gst_video_decoder_get_output_state(self.as_ref().to_glib_none().0) };
150
151        if state.is_null() {
152            None
153        } else {
154            unsafe { Some(VideoCodecState::<Readable>::new(state)) }
155        }
156    }
157
158    #[doc(alias = "gst_video_decoder_set_output_state")]
159    fn set_output_state(
160        &self,
161        fmt: VideoFormat,
162        width: u32,
163        height: u32,
164        reference: Option<&VideoCodecState<Readable>>,
165    ) -> Result<VideoCodecState<'_, InNegotiation<'_>>, gst::FlowError> {
166        let state = unsafe {
167            let reference = match reference {
168                Some(reference) => reference.as_mut_ptr(),
169                None => ptr::null_mut(),
170            };
171            ffi::gst_video_decoder_set_output_state(
172                self.as_ref().to_glib_none().0,
173                fmt.into_glib(),
174                width,
175                height,
176                reference,
177            )
178        };
179
180        if state.is_null() {
181            Err(gst::FlowError::NotNegotiated)
182        } else {
183            unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
184        }
185    }
186
187    #[cfg(feature = "v1_16")]
188    #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
189    #[doc(alias = "gst_video_decoder_set_interlaced_output_state")]
190    fn set_interlaced_output_state(
191        &self,
192        fmt: VideoFormat,
193        mode: VideoInterlaceMode,
194        width: u32,
195        height: u32,
196        reference: Option<&VideoCodecState<Readable>>,
197    ) -> Result<VideoCodecState<'_, InNegotiation<'_>>, gst::FlowError> {
198        let state = unsafe {
199            let reference = match reference {
200                Some(reference) => reference.as_mut_ptr(),
201                None => ptr::null_mut(),
202            };
203            ffi::gst_video_decoder_set_interlaced_output_state(
204                self.as_ref().to_glib_none().0,
205                fmt.into_glib(),
206                mode.into_glib(),
207                width,
208                height,
209                reference,
210            )
211        };
212
213        if state.is_null() {
214            Err(gst::FlowError::NotNegotiated)
215        } else {
216            unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
217        }
218    }
219
220    #[doc(alias = "gst_video_decoder_negotiate")]
221    fn negotiate<'a>(
222        &'a self,
223        output_state: VideoCodecState<'a, InNegotiation<'a>>,
224    ) -> Result<(), gst::FlowError> {
225        // Consume output_state so user won't be able to modify it anymore
226        let self_ptr = self.to_glib_none().0 as *const gst::ffi::GstElement;
227        assert_eq!(output_state.context.element_as_ptr(), self_ptr);
228
229        let ret = unsafe {
230            from_glib(ffi::gst_video_decoder_negotiate(
231                self.as_ref().to_glib_none().0,
232            ))
233        };
234        if ret {
235            Ok(())
236        } else {
237            Err(gst::FlowError::NotNegotiated)
238        }
239    }
240
241    #[allow(clippy::too_many_arguments)]
242    fn error<T: gst::MessageErrorDomain>(
243        &self,
244        weight: i32,
245        code: T,
246        message: Option<&str>,
247        debug: Option<&str>,
248        file: &str,
249        function: &str,
250        line: u32,
251    ) -> Result<gst::FlowSuccess, gst::FlowError> {
252        unsafe {
253            try_from_glib(_gst_video_decoder_error(
254                self.as_ref().to_glib_none().0,
255                weight,
256                T::domain().into_glib(),
257                code.code(),
258                message.to_glib_full(),
259                debug.to_glib_full(),
260                file.to_glib_none().0,
261                function.to_glib_none().0,
262                line as i32,
263            ))
264        }
265    }
266
267    fn sink_pad(&self) -> &gst::Pad {
268        unsafe {
269            let elt = &*(self.as_ptr() as *const ffi::GstVideoDecoder);
270            &*(&elt.sinkpad as *const *mut gst::ffi::GstPad as *const gst::Pad)
271        }
272    }
273
274    fn src_pad(&self) -> &gst::Pad {
275        unsafe {
276            let elt = &*(self.as_ptr() as *const ffi::GstVideoDecoder);
277            &*(&elt.srcpad as *const *mut gst::ffi::GstPad as *const gst::Pad)
278        }
279    }
280
281    fn input_segment(&self) -> gst::Segment {
282        unsafe {
283            let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _);
284            glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock));
285            let segment = ptr.input_segment;
286            glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock));
287            from_glib_none(&segment as *const gst::ffi::GstSegment)
288        }
289    }
290
291    fn output_segment(&self) -> gst::Segment {
292        unsafe {
293            let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _);
294            glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock));
295            let segment = ptr.output_segment;
296            glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock));
297            from_glib_none(&segment as *const gst::ffi::GstSegment)
298        }
299    }
300}
301
302impl<O: IsA<VideoDecoder>> VideoDecoderExtManual for O {}
303
304impl HasStreamLock for VideoDecoder {
305    fn stream_lock(&self) -> *mut glib::ffi::GRecMutex {
306        let decoder_sys: *const ffi::GstVideoDecoder = self.to_glib_none().0;
307        unsafe { mut_override(&(*decoder_sys).stream_lock) }
308    }
309
310    fn element_as_ptr(&self) -> *const gst::ffi::GstElement {
311        self.as_ptr() as *mut gst::ffi::GstElement
312    }
313}
314
315#[macro_export]
316macro_rules! video_decoder_error(
317    ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
318        use $crate::prelude::VideoDecoderExtManual;
319        $obj.error(
320            $weight,
321            $err,
322            Some(&format!($($msg)*)),
323            Some(&format!($($debug)*)),
324            file!(),
325            $crate::glib::function_name!(),
326            line!(),
327        )
328    }};
329    ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*)) => { {
330        use $crate::prelude::VideoDecoderExtManual;
331        $obj.error(
332            $weight,
333            $err,
334            Some(&format!($($msg)*)),
335            None,
336            file!(),
337            $crate::glib::function_name!(),
338            line!(),
339        )
340    }};
341    ($obj:expr, $weight:expr, $err:expr, [$($debug:tt)*]) => { {
342        use $crate::prelude::VideoDecoderExtManual;
343        $obj.error(
344            $weight,
345            $err,
346            None,
347            Some(&format!($($debug)*)),
348            file!(),
349            $crate::glib::function_name!(),
350            line!(),
351        )
352    }};
353);