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);