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