1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use crate::utils::HasStreamLock;
4 use crate::video_codec_state::{InNegotiation, Readable, VideoCodecState, VideoCodecStateContext};
5 use crate::VideoCodecFrame;
6 use crate::VideoDecoder;
7 use crate::VideoFormat;
8 #[cfg(any(feature = "v1_16", feature = "dox"))]
9 #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_16")))]
10 use crate::VideoInterlaceMode;
11 use glib::prelude::*;
12 use glib::translate::*;
13 use std::mem;
14 use std::ptr;
15 
16 extern "C" {
_gst_video_decoder_error( dec: *mut ffi::GstVideoDecoder, weight: i32, domain: glib::ffi::GQuark, code: i32, txt: *mut libc::c_char, debug: *mut libc::c_char, file: *const libc::c_char, function: *const libc::c_char, line: i32, ) -> gst::ffi::GstFlowReturn17     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 
30 pub trait VideoDecoderExtManual: 'static {
31     #[cfg(any(feature = "v1_12", feature = "dox"))]
32     #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_12")))]
allocate_output_frame( &self, frame: &mut VideoCodecFrame, params: Option<&gst::BufferPoolAcquireParams>, ) -> Result<gst::FlowSuccess, gst::FlowError>33     fn allocate_output_frame(
34         &self,
35         frame: &mut VideoCodecFrame,
36         params: Option<&gst::BufferPoolAcquireParams>,
37     ) -> Result<gst::FlowSuccess, gst::FlowError>;
38 
39     #[doc(alias = "get_frame")]
frame(&self, frame_number: i32) -> Option<VideoCodecFrame>40     fn frame(&self, frame_number: i32) -> Option<VideoCodecFrame>;
41     #[doc(alias = "get_frames")]
frames(&self) -> Vec<VideoCodecFrame>42     fn frames(&self) -> Vec<VideoCodecFrame>;
43     #[doc(alias = "get_oldest_frame")]
oldest_frame(&self) -> Option<VideoCodecFrame>44     fn oldest_frame(&self) -> Option<VideoCodecFrame>;
45 
46     #[doc(alias = "get_allocator")]
allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams)47     fn allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams);
48 
finish_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>49     fn finish_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>;
release_frame(&self, frame: VideoCodecFrame)50     fn release_frame(&self, frame: VideoCodecFrame);
drop_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>51     fn drop_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>;
52 
53     #[doc(alias = "get_latency")]
latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>)54     fn latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>);
set_latency( &self, min_latency: gst::ClockTime, max_latency: impl Into<Option<gst::ClockTime>>, )55     fn set_latency(
56         &self,
57         min_latency: gst::ClockTime,
58         max_latency: impl Into<Option<gst::ClockTime>>,
59     );
60 
61     #[doc(alias = "get_output_state")]
output_state(&self) -> Option<VideoCodecState<'static, Readable>>62     fn output_state(&self) -> Option<VideoCodecState<'static, Readable>>;
set_output_state( &self, fmt: VideoFormat, width: u32, height: u32, reference: Option<&VideoCodecState<Readable>>, ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>63     fn set_output_state(
64         &self,
65         fmt: VideoFormat,
66         width: u32,
67         height: u32,
68         reference: Option<&VideoCodecState<Readable>>,
69     ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>;
70     #[cfg(any(feature = "v1_16", feature = "dox"))]
71     #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_16")))]
set_interlaced_output_state( &self, fmt: VideoFormat, mode: VideoInterlaceMode, width: u32, height: u32, reference: Option<&VideoCodecState<Readable>>, ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>72     fn set_interlaced_output_state(
73         &self,
74         fmt: VideoFormat,
75         mode: VideoInterlaceMode,
76         width: u32,
77         height: u32,
78         reference: Option<&VideoCodecState<Readable>>,
79     ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>;
80 
negotiate<'a>( &'a self, output_state: VideoCodecState<'a, InNegotiation<'a>>, ) -> Result<(), gst::FlowError>81     fn negotiate<'a>(
82         &'a self,
83         output_state: VideoCodecState<'a, InNegotiation<'a>>,
84     ) -> Result<(), gst::FlowError>;
85 
86     #[allow(clippy::too_many_arguments)]
error<T: gst::MessageErrorDomain>( &self, weight: i32, code: T, message: Option<&str>, debug: Option<&str>, file: &str, function: &str, line: u32, ) -> Result<gst::FlowSuccess, gst::FlowError>87     fn error<T: gst::MessageErrorDomain>(
88         &self,
89         weight: i32,
90         code: T,
91         message: Option<&str>,
92         debug: Option<&str>,
93         file: &str,
94         function: &str,
95         line: u32,
96     ) -> Result<gst::FlowSuccess, gst::FlowError>;
97 }
98 
99 impl<O: IsA<VideoDecoder>> VideoDecoderExtManual for O {
100     #[cfg(any(feature = "v1_12", feature = "dox"))]
101     #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_12")))]
allocate_output_frame( &self, frame: &mut VideoCodecFrame, params: Option<&gst::BufferPoolAcquireParams>, ) -> Result<gst::FlowSuccess, gst::FlowError>102     fn allocate_output_frame(
103         &self,
104         frame: &mut VideoCodecFrame,
105         params: Option<&gst::BufferPoolAcquireParams>,
106     ) -> Result<gst::FlowSuccess, gst::FlowError> {
107         unsafe {
108             let params_ptr = params.to_glib_none().0 as *mut _;
109             try_from_glib(ffi::gst_video_decoder_allocate_output_frame_with_params(
110                 self.as_ref().to_glib_none().0,
111                 frame.to_glib_none().0,
112                 params_ptr,
113             ))
114         }
115     }
116 
117     #[doc(alias = "gst_video_decoder_get_allocator")]
allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams)118     fn allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams) {
119         unsafe {
120             let mut allocator = ptr::null_mut();
121             let mut params = mem::zeroed();
122             ffi::gst_video_decoder_get_allocator(
123                 self.as_ref().to_glib_none().0,
124                 &mut allocator,
125                 &mut params,
126             );
127             (from_glib_full(allocator), params.into())
128         }
129     }
130 
131     #[doc(alias = "gst_video_decoder_finish_frame")]
finish_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>132     fn finish_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError> {
133         unsafe {
134             try_from_glib(ffi::gst_video_decoder_finish_frame(
135                 self.as_ref().to_glib_none().0,
136                 frame.into_ptr(),
137             ))
138         }
139     }
140 
141     #[doc(alias = "gst_video_decoder_release_frame")]
release_frame(&self, frame: VideoCodecFrame)142     fn release_frame(&self, frame: VideoCodecFrame) {
143         unsafe {
144             ffi::gst_video_decoder_release_frame(self.as_ref().to_glib_none().0, frame.into_ptr())
145         }
146     }
147 
148     #[doc(alias = "gst_video_decoder_drop_frame")]
drop_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>149     fn drop_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError> {
150         unsafe {
151             try_from_glib(ffi::gst_video_decoder_drop_frame(
152                 self.as_ref().to_glib_none().0,
153                 frame.into_ptr(),
154             ))
155         }
156     }
157 
158     #[doc(alias = "gst_video_decoder_get_latency")]
latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>)159     fn latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>) {
160         let mut min_latency = gst::ffi::GST_CLOCK_TIME_NONE;
161         let mut max_latency = gst::ffi::GST_CLOCK_TIME_NONE;
162 
163         unsafe {
164             ffi::gst_video_decoder_get_latency(
165                 self.as_ref().to_glib_none().0,
166                 &mut min_latency,
167                 &mut max_latency,
168             );
169 
170             (
171                 try_from_glib(min_latency).expect("undefined min_latency"),
172                 from_glib(max_latency),
173             )
174         }
175     }
176 
177     #[doc(alias = "gst_video_decoder_set_latency")]
set_latency( &self, min_latency: gst::ClockTime, max_latency: impl Into<Option<gst::ClockTime>>, )178     fn set_latency(
179         &self,
180         min_latency: gst::ClockTime,
181         max_latency: impl Into<Option<gst::ClockTime>>,
182     ) {
183         unsafe {
184             ffi::gst_video_decoder_set_latency(
185                 self.as_ref().to_glib_none().0,
186                 min_latency.into_glib(),
187                 max_latency.into().into_glib(),
188             );
189         }
190     }
191 
192     #[doc(alias = "gst_video_decoder_get_frame")]
frame(&self, frame_number: i32) -> Option<VideoCodecFrame>193     fn frame(&self, frame_number: i32) -> Option<VideoCodecFrame> {
194         let frame = unsafe {
195             ffi::gst_video_decoder_get_frame(self.as_ref().to_glib_none().0, frame_number)
196         };
197 
198         if frame.is_null() {
199             None
200         } else {
201             unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
202         }
203     }
204 
205     #[doc(alias = "gst_video_decoder_get_frames")]
frames(&self) -> Vec<VideoCodecFrame>206     fn frames(&self) -> Vec<VideoCodecFrame> {
207         unsafe {
208             let frames = ffi::gst_video_decoder_get_frames(self.as_ref().to_glib_none().0);
209             let mut iter: *const glib::ffi::GList = frames;
210             let mut vec = Vec::new();
211 
212             while !iter.is_null() {
213                 let frame_ptr = Ptr::from((*iter).data);
214                 /* transfer ownership of the frame */
215                 let frame = VideoCodecFrame::new(frame_ptr, self.as_ref());
216                 vec.push(frame);
217                 iter = (*iter).next;
218             }
219 
220             glib::ffi::g_list_free(frames);
221             vec
222         }
223     }
224 
225     #[doc(alias = "gst_video_decoder_get_oldest_frame")]
oldest_frame(&self) -> Option<VideoCodecFrame>226     fn oldest_frame(&self) -> Option<VideoCodecFrame> {
227         let frame =
228             unsafe { ffi::gst_video_decoder_get_oldest_frame(self.as_ref().to_glib_none().0) };
229 
230         if frame.is_null() {
231             None
232         } else {
233             unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
234         }
235     }
236 
237     #[doc(alias = "gst_video_decoder_get_output_state")]
output_state(&self) -> Option<VideoCodecState<'static, Readable>>238     fn output_state(&self) -> Option<VideoCodecState<'static, Readable>> {
239         let state =
240             unsafe { ffi::gst_video_decoder_get_output_state(self.as_ref().to_glib_none().0) };
241 
242         if state.is_null() {
243             None
244         } else {
245             unsafe { Some(VideoCodecState::<Readable>::new(state)) }
246         }
247     }
248 
249     #[doc(alias = "gst_video_decoder_set_output_state")]
set_output_state( &self, fmt: VideoFormat, width: u32, height: u32, reference: Option<&VideoCodecState<Readable>>, ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>250     fn set_output_state(
251         &self,
252         fmt: VideoFormat,
253         width: u32,
254         height: u32,
255         reference: Option<&VideoCodecState<Readable>>,
256     ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError> {
257         let state = unsafe {
258             let reference = match reference {
259                 Some(reference) => reference.as_mut_ptr(),
260                 None => ptr::null_mut(),
261             };
262             ffi::gst_video_decoder_set_output_state(
263                 self.as_ref().to_glib_none().0,
264                 fmt.into_glib(),
265                 width,
266                 height,
267                 reference,
268             )
269         };
270 
271         if state.is_null() {
272             Err(gst::FlowError::NotNegotiated)
273         } else {
274             unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
275         }
276     }
277 
278     #[cfg(any(feature = "v1_16", feature = "dox"))]
279     #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_16")))]
280     #[doc(alias = "gst_video_decoder_set_interlaced_output_state")]
set_interlaced_output_state( &self, fmt: VideoFormat, mode: VideoInterlaceMode, width: u32, height: u32, reference: Option<&VideoCodecState<Readable>>, ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>281     fn set_interlaced_output_state(
282         &self,
283         fmt: VideoFormat,
284         mode: VideoInterlaceMode,
285         width: u32,
286         height: u32,
287         reference: Option<&VideoCodecState<Readable>>,
288     ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError> {
289         let state = unsafe {
290             let reference = match reference {
291                 Some(reference) => reference.as_mut_ptr(),
292                 None => ptr::null_mut(),
293             };
294             ffi::gst_video_decoder_set_interlaced_output_state(
295                 self.as_ref().to_glib_none().0,
296                 fmt.into_glib(),
297                 mode.into_glib(),
298                 width,
299                 height,
300                 reference,
301             )
302         };
303 
304         if state.is_null() {
305             Err(gst::FlowError::NotNegotiated)
306         } else {
307             unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
308         }
309     }
310 
311     #[doc(alias = "gst_video_decoder_negotiate")]
negotiate<'a>( &'a self, output_state: VideoCodecState<'a, InNegotiation<'a>>, ) -> Result<(), gst::FlowError>312     fn negotiate<'a>(
313         &'a self,
314         output_state: VideoCodecState<'a, InNegotiation<'a>>,
315     ) -> Result<(), gst::FlowError> {
316         // Consume output_state so user won't be able to modify it anymore
317         let self_ptr = self.to_glib_none().0 as *const gst::ffi::GstElement;
318         assert_eq!(output_state.context.element_as_ptr(), self_ptr);
319 
320         let ret = unsafe {
321             from_glib(ffi::gst_video_decoder_negotiate(
322                 self.as_ref().to_glib_none().0,
323             ))
324         };
325         if ret {
326             Ok(())
327         } else {
328             Err(gst::FlowError::NotNegotiated)
329         }
330     }
error<T: gst::MessageErrorDomain>( &self, weight: i32, code: T, message: Option<&str>, debug: Option<&str>, file: &str, function: &str, line: u32, ) -> Result<gst::FlowSuccess, gst::FlowError>331     fn error<T: gst::MessageErrorDomain>(
332         &self,
333         weight: i32,
334         code: T,
335         message: Option<&str>,
336         debug: Option<&str>,
337         file: &str,
338         function: &str,
339         line: u32,
340     ) -> Result<gst::FlowSuccess, gst::FlowError> {
341         unsafe {
342             try_from_glib(_gst_video_decoder_error(
343                 self.as_ref().to_glib_none().0,
344                 weight,
345                 T::domain().into_glib(),
346                 code.code(),
347                 message.to_glib_full(),
348                 debug.to_glib_full(),
349                 file.to_glib_none().0,
350                 function.to_glib_none().0,
351                 line as i32,
352             ))
353         }
354     }
355 }
356 
357 impl HasStreamLock for VideoDecoder {
stream_lock(&self) -> *mut glib::ffi::GRecMutex358     fn stream_lock(&self) -> *mut glib::ffi::GRecMutex {
359         let decoder_sys: *const ffi::GstVideoDecoder = self.to_glib_none().0;
360         unsafe { &(*decoder_sys).stream_lock as *const _ as usize as *mut _ }
361     }
362 
element_as_ptr(&self) -> *const gst::ffi::GstElement363     fn element_as_ptr(&self) -> *const gst::ffi::GstElement {
364         let decoder_sys: *const ffi::GstVideoDecoder = self.to_glib_none().0;
365         decoder_sys as *const gst::ffi::GstElement
366     }
367 }
368 
369 #[macro_export]
370 macro_rules! video_decoder_error(
371     ($obj:expr, $weight:expr, $err:expr, ($msg:expr), [$debug:expr]) => { {
372         use $crate::prelude::VideoDecoderExtManual;
373         $obj.error(
374             $weight,
375             $err,
376             Some($msg),
377             Some($debug),
378             file!(),
379             module_path!(),
380             line!(),
381         )
382     }};
383     ($obj:expr, $weight:expr, $err:expr, ($msg:expr)) => { {
384         use $crate::prelude::VideoDecoderExtManual;
385         $obj.error(
386             $weight,
387             $err,
388             Some($msg),
389             None,
390             file!(),
391             module_path!(),
392             line!(),
393         )
394     }};
395     ($obj:expr, $weight:expr, $err:expr, [$debug:expr]) => { {
396         use $crate::prelude::VideoDecoderExtManual;
397         $obj.error(
398             $weight,
399             $err,
400             None,
401             Some($debug),
402             file!(),
403             module_path!(),
404             line!(),
405         )
406     }};
407     ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
408         use $crate::prelude::VideoDecoderExtManual;
409         $obj.error(
410             $weight,
411             $err,
412             Some(&format!($($msg)*)),
413             Some(&format!($($debug)*)),
414             file!(),
415             module_path!(),
416             line!(),
417         )
418     }};
419     ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*)) => { {
420         use $crate::prelude::VideoDecoderExtManual;
421         $obj.error(
422             $weight,
423             $err,
424             Some(&format!($($msg)*)),
425             None,
426             file!(),
427             module_path!(),
428             line!(),
429         )
430     }};
431     ($obj:expr, $weight:expr, $err:expr, [$($debug:tt)*]) => { {
432         use $crate::prelude::VideoDecoderExtManual;
433         $obj.error(
434             $weight,
435             $err,
436             None,
437             Some(&format!($($debug)*)),
438             file!(),
439             module_path!(),
440             line!(),
441         )
442     }};
443 );
444