1use 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")]
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    #[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    #[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                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    #[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    #[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    #[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    #[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    #[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    #[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    #[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    #[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        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);