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
31mod sealed {
32 pub trait Sealed {}
33 impl<T: super::IsA<super::VideoDecoder>> Sealed for T {}
34}
35
36pub trait VideoDecoderExtManual: sealed::Sealed + IsA<VideoDecoder> + 'static {
37 #[doc(alias = "gst_video_decoder_allocate_output_frame")]
50 fn allocate_output_frame(
51 &self,
52 frame: &mut VideoCodecFrame,
53 params: Option<&gst::BufferPoolAcquireParams>,
54 ) -> Result<gst::FlowSuccess, gst::FlowError> {
55 unsafe {
56 let params_ptr = params.to_glib_none().0 as *mut _;
57 try_from_glib(ffi::gst_video_decoder_allocate_output_frame_with_params(
58 self.as_ref().to_glib_none().0,
59 frame.to_glib_none().0,
60 params_ptr,
61 ))
62 }
63 }
64
65 #[doc(alias = "get_frame")]
73 #[doc(alias = "gst_video_decoder_get_frame")]
74 fn frame(&self, frame_number: i32) -> Option<VideoCodecFrame> {
75 let frame = unsafe {
76 ffi::gst_video_decoder_get_frame(self.as_ref().to_glib_none().0, frame_number)
77 };
78
79 if frame.is_null() {
80 None
81 } else {
82 unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
83 }
84 }
85
86 #[doc(alias = "get_frames")]
92 #[doc(alias = "gst_video_decoder_get_frames")]
93 fn frames(&self) -> Vec<VideoCodecFrame> {
94 unsafe {
95 let frames = ffi::gst_video_decoder_get_frames(self.as_ref().to_glib_none().0);
96 let mut iter: *const glib::ffi::GList = frames;
97 let mut vec = Vec::new();
98
99 while !iter.is_null() {
100 let frame_ptr = Ptr::from((*iter).data);
101 let frame = VideoCodecFrame::new(frame_ptr, self.as_ref());
103 vec.push(frame);
104 iter = (*iter).next;
105 }
106
107 glib::ffi::g_list_free(frames);
108 vec
109 }
110 }
111
112 #[doc(alias = "get_oldest_frame")]
118 #[doc(alias = "gst_video_decoder_get_oldest_frame")]
119 fn oldest_frame(&self) -> Option<VideoCodecFrame> {
120 let frame =
121 unsafe { ffi::gst_video_decoder_get_oldest_frame(self.as_ref().to_glib_none().0) };
122
123 if frame.is_null() {
124 None
125 } else {
126 unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
127 }
128 }
129
130 #[doc(alias = "get_allocator")]
146 #[doc(alias = "gst_video_decoder_get_allocator")]
147 fn allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams) {
148 unsafe {
149 let mut allocator = ptr::null_mut();
150 let mut params = mem::MaybeUninit::uninit();
151 ffi::gst_video_decoder_get_allocator(
152 self.as_ref().to_glib_none().0,
153 &mut allocator,
154 params.as_mut_ptr(),
155 );
156 (from_glib_full(allocator), params.assume_init().into())
157 }
158 }
159 #[doc(alias = "get_latency")]
173 #[doc(alias = "gst_video_decoder_get_latency")]
174 fn latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>) {
175 let mut min_latency = gst::ffi::GST_CLOCK_TIME_NONE;
176 let mut max_latency = gst::ffi::GST_CLOCK_TIME_NONE;
177
178 unsafe {
179 ffi::gst_video_decoder_get_latency(
180 self.as_ref().to_glib_none().0,
181 &mut min_latency,
182 &mut max_latency,
183 );
184
185 (
186 try_from_glib(min_latency).expect("undefined min_latency"),
187 from_glib(max_latency),
188 )
189 }
190 }
191
192 #[doc(alias = "gst_video_decoder_set_latency")]
201 fn set_latency(
202 &self,
203 min_latency: gst::ClockTime,
204 max_latency: impl Into<Option<gst::ClockTime>>,
205 ) {
206 unsafe {
207 ffi::gst_video_decoder_set_latency(
208 self.as_ref().to_glib_none().0,
209 min_latency.into_glib(),
210 max_latency.into().into_glib(),
211 );
212 }
213 }
214
215 #[doc(alias = "get_output_state")]
221 #[doc(alias = "gst_video_decoder_get_output_state")]
222 fn output_state(&self) -> Option<VideoCodecState<'static, Readable>> {
223 let state =
224 unsafe { ffi::gst_video_decoder_get_output_state(self.as_ref().to_glib_none().0) };
225
226 if state.is_null() {
227 None
228 } else {
229 unsafe { Some(VideoCodecState::<Readable>::new(state)) }
230 }
231 }
232
233 #[doc(alias = "gst_video_decoder_set_output_state")]
260 fn set_output_state(
261 &self,
262 fmt: VideoFormat,
263 width: u32,
264 height: u32,
265 reference: Option<&VideoCodecState<Readable>>,
266 ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError> {
267 let state = unsafe {
268 let reference = match reference {
269 Some(reference) => reference.as_mut_ptr(),
270 None => ptr::null_mut(),
271 };
272 ffi::gst_video_decoder_set_output_state(
273 self.as_ref().to_glib_none().0,
274 fmt.into_glib(),
275 width,
276 height,
277 reference,
278 )
279 };
280
281 if state.is_null() {
282 Err(gst::FlowError::NotNegotiated)
283 } else {
284 unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
285 }
286 }
287
288 #[cfg(feature = "v1_16")]
305 #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
306 #[doc(alias = "gst_video_decoder_set_interlaced_output_state")]
307 fn set_interlaced_output_state(
308 &self,
309 fmt: VideoFormat,
310 mode: VideoInterlaceMode,
311 width: u32,
312 height: u32,
313 reference: Option<&VideoCodecState<Readable>>,
314 ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError> {
315 let state = unsafe {
316 let reference = match reference {
317 Some(reference) => reference.as_mut_ptr(),
318 None => ptr::null_mut(),
319 };
320 ffi::gst_video_decoder_set_interlaced_output_state(
321 self.as_ref().to_glib_none().0,
322 fmt.into_glib(),
323 mode.into_glib(),
324 width,
325 height,
326 reference,
327 )
328 };
329
330 if state.is_null() {
331 Err(gst::FlowError::NotNegotiated)
332 } else {
333 unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
334 }
335 }
336
337 #[doc(alias = "gst_video_decoder_negotiate")]
345 fn negotiate<'a>(
346 &'a self,
347 output_state: VideoCodecState<'a, InNegotiation<'a>>,
348 ) -> Result<(), gst::FlowError> {
349 let self_ptr = self.to_glib_none().0 as *const gst::ffi::GstElement;
351 assert_eq!(output_state.context.element_as_ptr(), self_ptr);
352
353 let ret = unsafe {
354 from_glib(ffi::gst_video_decoder_negotiate(
355 self.as_ref().to_glib_none().0,
356 ))
357 };
358 if ret {
359 Ok(())
360 } else {
361 Err(gst::FlowError::NotNegotiated)
362 }
363 }
364
365 #[allow(clippy::too_many_arguments)]
366 fn error<T: gst::MessageErrorDomain>(
367 &self,
368 weight: i32,
369 code: T,
370 message: Option<&str>,
371 debug: Option<&str>,
372 file: &str,
373 function: &str,
374 line: u32,
375 ) -> Result<gst::FlowSuccess, gst::FlowError> {
376 unsafe {
377 try_from_glib(_gst_video_decoder_error(
378 self.as_ref().to_glib_none().0,
379 weight,
380 T::domain().into_glib(),
381 code.code(),
382 message.to_glib_full(),
383 debug.to_glib_full(),
384 file.to_glib_none().0,
385 function.to_glib_none().0,
386 line as i32,
387 ))
388 }
389 }
390
391 fn sink_pad(&self) -> &gst::Pad {
392 unsafe {
393 let elt = &*(self.as_ptr() as *const ffi::GstVideoDecoder);
394 &*(&elt.sinkpad as *const *mut gst::ffi::GstPad as *const gst::Pad)
395 }
396 }
397
398 fn src_pad(&self) -> &gst::Pad {
399 unsafe {
400 let elt = &*(self.as_ptr() as *const ffi::GstVideoDecoder);
401 &*(&elt.srcpad as *const *mut gst::ffi::GstPad as *const gst::Pad)
402 }
403 }
404
405 fn input_segment(&self) -> gst::Segment {
406 unsafe {
407 let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _);
408 glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock));
409 let segment = ptr.input_segment;
410 glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock));
411 from_glib_none(&segment as *const gst::ffi::GstSegment)
412 }
413 }
414
415 fn output_segment(&self) -> gst::Segment {
416 unsafe {
417 let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _);
418 glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock));
419 let segment = ptr.output_segment;
420 glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock));
421 from_glib_none(&segment as *const gst::ffi::GstSegment)
422 }
423 }
424}
425
426impl<O: IsA<VideoDecoder>> VideoDecoderExtManual for O {}
427
428impl HasStreamLock for VideoDecoder {
429 fn stream_lock(&self) -> *mut glib::ffi::GRecMutex {
430 let decoder_sys: *const ffi::GstVideoDecoder = self.to_glib_none().0;
431 unsafe { mut_override(&(*decoder_sys).stream_lock) }
432 }
433
434 fn element_as_ptr(&self) -> *const gst::ffi::GstElement {
435 self.as_ptr() as *mut gst::ffi::GstElement
436 }
437}
438
439#[macro_export]
440macro_rules! video_decoder_error(
441 ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
442 use $crate::prelude::VideoDecoderExtManual;
443 $obj.error(
444 $weight,
445 $err,
446 Some(&format!($($msg)*)),
447 Some(&format!($($debug)*)),
448 file!(),
449 $crate::glib::function_name!(),
450 line!(),
451 )
452 }};
453 ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*)) => { {
454 use $crate::prelude::VideoDecoderExtManual;
455 $obj.error(
456 $weight,
457 $err,
458 Some(&format!($($msg)*)),
459 None,
460 file!(),
461 $crate::glib::function_name!(),
462 line!(),
463 )
464 }};
465 ($obj:expr, $weight:expr, $err:expr, [$($debug:tt)*]) => { {
466 use $crate::prelude::VideoDecoderExtManual;
467 $obj.error(
468 $weight,
469 $err,
470 None,
471 Some(&format!($($debug)*)),
472 file!(),
473 $crate::glib::function_name!(),
474 line!(),
475 )
476 }};
477);