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 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")]
44 fn allocate_output_frame(
45 &self,
46 frame: &mut VideoCodecFrame,
47 params: Option<&gst::BufferPoolAcquireParams>,
48 ) -> Result<gst::FlowSuccess, gst::FlowError> {
49 unsafe {
50 let params_ptr = params.to_glib_none().0 as *mut _;
51 try_from_glib(ffi::gst_video_decoder_allocate_output_frame_with_params(
52 self.as_ref().to_glib_none().0,
53 frame.to_glib_none().0,
54 params_ptr,
55 ))
56 }
57 }
58
59 #[doc(alias = "get_frame")]
67 #[doc(alias = "gst_video_decoder_get_frame")]
68 fn frame(&self, frame_number: i32) -> Option<VideoCodecFrame<'_>> {
69 let frame = unsafe {
70 ffi::gst_video_decoder_get_frame(self.as_ref().to_glib_none().0, frame_number)
71 };
72
73 if frame.is_null() {
74 None
75 } else {
76 unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
77 }
78 }
79
80 #[doc(alias = "get_frames")]
86 #[doc(alias = "gst_video_decoder_get_frames")]
87 fn frames(&self) -> Vec<VideoCodecFrame<'_>> {
88 unsafe {
89 let frames = ffi::gst_video_decoder_get_frames(self.as_ref().to_glib_none().0);
90 let mut iter: *const glib::ffi::GList = frames;
91 let mut vec = Vec::new();
92
93 while !iter.is_null() {
94 let frame_ptr = Ptr::from((*iter).data);
95 let frame = VideoCodecFrame::new(frame_ptr, self.as_ref());
97 vec.push(frame);
98 iter = (*iter).next;
99 }
100
101 glib::ffi::g_list_free(frames);
102 vec
103 }
104 }
105
106 #[doc(alias = "get_oldest_frame")]
112 #[doc(alias = "gst_video_decoder_get_oldest_frame")]
113 fn oldest_frame(&self) -> Option<VideoCodecFrame<'_>> {
114 let frame =
115 unsafe { ffi::gst_video_decoder_get_oldest_frame(self.as_ref().to_glib_none().0) };
116
117 if frame.is_null() {
118 None
119 } else {
120 unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
121 }
122 }
123
124 #[doc(alias = "get_allocator")]
140 #[doc(alias = "gst_video_decoder_get_allocator")]
141 fn allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams) {
142 unsafe {
143 let mut allocator = ptr::null_mut();
144 let mut params = mem::MaybeUninit::uninit();
145 ffi::gst_video_decoder_get_allocator(
146 self.as_ref().to_glib_none().0,
147 &mut allocator,
148 params.as_mut_ptr(),
149 );
150 (from_glib_full(allocator), params.assume_init().into())
151 }
152 }
153 #[doc(alias = "get_latency")]
167 #[doc(alias = "gst_video_decoder_get_latency")]
168 fn latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>) {
169 let mut min_latency = gst::ffi::GST_CLOCK_TIME_NONE;
170 let mut max_latency = gst::ffi::GST_CLOCK_TIME_NONE;
171
172 unsafe {
173 ffi::gst_video_decoder_get_latency(
174 self.as_ref().to_glib_none().0,
175 &mut min_latency,
176 &mut max_latency,
177 );
178
179 (
180 try_from_glib(min_latency).expect("undefined min_latency"),
181 from_glib(max_latency),
182 )
183 }
184 }
185
186 #[doc(alias = "gst_video_decoder_set_latency")]
195 fn set_latency(
196 &self,
197 min_latency: gst::ClockTime,
198 max_latency: impl Into<Option<gst::ClockTime>>,
199 ) {
200 unsafe {
201 ffi::gst_video_decoder_set_latency(
202 self.as_ref().to_glib_none().0,
203 min_latency.into_glib(),
204 max_latency.into().into_glib(),
205 );
206 }
207 }
208
209 #[doc(alias = "get_output_state")]
215 #[doc(alias = "gst_video_decoder_get_output_state")]
216 fn output_state(&self) -> Option<VideoCodecState<'static, Readable>> {
217 let state =
218 unsafe { ffi::gst_video_decoder_get_output_state(self.as_ref().to_glib_none().0) };
219
220 if state.is_null() {
221 None
222 } else {
223 unsafe { Some(VideoCodecState::<Readable>::new(state)) }
224 }
225 }
226
227 #[doc(alias = "gst_video_decoder_set_output_state")]
254 fn set_output_state(
255 &self,
256 fmt: VideoFormat,
257 width: u32,
258 height: u32,
259 reference: Option<&VideoCodecState<Readable>>,
260 ) -> Result<VideoCodecState<'_, InNegotiation<'_>>, gst::FlowError> {
261 let state = unsafe {
262 let reference = match reference {
263 Some(reference) => reference.as_mut_ptr(),
264 None => ptr::null_mut(),
265 };
266 ffi::gst_video_decoder_set_output_state(
267 self.as_ref().to_glib_none().0,
268 fmt.into_glib(),
269 width,
270 height,
271 reference,
272 )
273 };
274
275 if state.is_null() {
276 Err(gst::FlowError::NotNegotiated)
277 } else {
278 unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
279 }
280 }
281
282 #[cfg(feature = "v1_16")]
299 #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
300 #[doc(alias = "gst_video_decoder_set_interlaced_output_state")]
301 fn set_interlaced_output_state(
302 &self,
303 fmt: VideoFormat,
304 mode: VideoInterlaceMode,
305 width: u32,
306 height: u32,
307 reference: Option<&VideoCodecState<Readable>>,
308 ) -> Result<VideoCodecState<'_, InNegotiation<'_>>, gst::FlowError> {
309 let state = unsafe {
310 let reference = match reference {
311 Some(reference) => reference.as_mut_ptr(),
312 None => ptr::null_mut(),
313 };
314 ffi::gst_video_decoder_set_interlaced_output_state(
315 self.as_ref().to_glib_none().0,
316 fmt.into_glib(),
317 mode.into_glib(),
318 width,
319 height,
320 reference,
321 )
322 };
323
324 if state.is_null() {
325 Err(gst::FlowError::NotNegotiated)
326 } else {
327 unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
328 }
329 }
330
331 #[doc(alias = "gst_video_decoder_negotiate")]
339 fn negotiate<'a>(
340 &'a self,
341 output_state: VideoCodecState<'a, InNegotiation<'a>>,
342 ) -> Result<(), gst::FlowError> {
343 let self_ptr = self.to_glib_none().0 as *const gst::ffi::GstElement;
345 assert_eq!(output_state.context.element_as_ptr(), self_ptr);
346
347 let ret = unsafe {
348 from_glib(ffi::gst_video_decoder_negotiate(
349 self.as_ref().to_glib_none().0,
350 ))
351 };
352 if ret {
353 Ok(())
354 } else {
355 Err(gst::FlowError::NotNegotiated)
356 }
357 }
358
359 #[allow(clippy::too_many_arguments)]
360 fn error<T: gst::MessageErrorDomain>(
361 &self,
362 weight: i32,
363 code: T,
364 message: Option<&str>,
365 debug: Option<&str>,
366 file: &str,
367 function: &str,
368 line: u32,
369 ) -> Result<gst::FlowSuccess, gst::FlowError> {
370 unsafe {
371 try_from_glib(_gst_video_decoder_error(
372 self.as_ref().to_glib_none().0,
373 weight,
374 T::domain().into_glib(),
375 code.code(),
376 message.to_glib_full(),
377 debug.to_glib_full(),
378 file.to_glib_none().0,
379 function.to_glib_none().0,
380 line as i32,
381 ))
382 }
383 }
384
385 fn sink_pad(&self) -> &gst::Pad {
386 unsafe {
387 let elt = &*(self.as_ptr() as *const ffi::GstVideoDecoder);
388 &*(&elt.sinkpad as *const *mut gst::ffi::GstPad as *const gst::Pad)
389 }
390 }
391
392 fn src_pad(&self) -> &gst::Pad {
393 unsafe {
394 let elt = &*(self.as_ptr() as *const ffi::GstVideoDecoder);
395 &*(&elt.srcpad as *const *mut gst::ffi::GstPad as *const gst::Pad)
396 }
397 }
398
399 fn input_segment(&self) -> gst::Segment {
400 unsafe {
401 let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _);
402 glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock));
403 let segment = ptr.input_segment;
404 glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock));
405 from_glib_none(&segment as *const gst::ffi::GstSegment)
406 }
407 }
408
409 fn output_segment(&self) -> gst::Segment {
410 unsafe {
411 let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _);
412 glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock));
413 let segment = ptr.output_segment;
414 glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock));
415 from_glib_none(&segment as *const gst::ffi::GstSegment)
416 }
417 }
418}
419
420impl<O: IsA<VideoDecoder>> VideoDecoderExtManual for O {}
421
422impl HasStreamLock for VideoDecoder {
423 fn stream_lock(&self) -> *mut glib::ffi::GRecMutex {
424 let decoder_sys: *const ffi::GstVideoDecoder = self.to_glib_none().0;
425 unsafe { mut_override(&(*decoder_sys).stream_lock) }
426 }
427
428 fn element_as_ptr(&self) -> *const gst::ffi::GstElement {
429 self.as_ptr() as *mut gst::ffi::GstElement
430 }
431}
432
433#[macro_export]
434macro_rules! video_decoder_error(
435 ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
436 use $crate::prelude::VideoDecoderExtManual;
437 $obj.error(
438 $weight,
439 $err,
440 Some(&format!($($msg)*)),
441 Some(&format!($($debug)*)),
442 file!(),
443 $crate::glib::function_name!(),
444 line!(),
445 )
446 }};
447 ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*)) => { {
448 use $crate::prelude::VideoDecoderExtManual;
449 $obj.error(
450 $weight,
451 $err,
452 Some(&format!($($msg)*)),
453 None,
454 file!(),
455 $crate::glib::function_name!(),
456 line!(),
457 )
458 }};
459 ($obj:expr, $weight:expr, $err:expr, [$($debug:tt)*]) => { {
460 use $crate::prelude::VideoDecoderExtManual;
461 $obj.error(
462 $weight,
463 $err,
464 None,
465 Some(&format!($($debug)*)),
466 file!(),
467 $crate::glib::function_name!(),
468 line!(),
469 )
470 }};
471);