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")]
33 fn allocate_output_frame(
34 &self,
35 frame: &mut VideoCodecFrame,
36 params: Option<&gst::BufferPoolAcquireParams>,
37 ) -> Result<gst::FlowSuccess, gst::FlowError> {
38 unsafe {
39 let params_ptr = params.to_glib_none().0 as *mut _;
40 try_from_glib(ffi::gst_video_decoder_allocate_output_frame_with_params(
41 self.as_ref().to_glib_none().0,
42 frame.to_glib_none().0,
43 params_ptr,
44 ))
45 }
46 }
47
48 #[doc(alias = "get_frame")]
49 #[doc(alias = "gst_video_decoder_get_frame")]
50 fn frame(&self, frame_number: i32) -> Option<VideoCodecFrame<'_>> {
51 let frame = unsafe {
52 ffi::gst_video_decoder_get_frame(self.as_ref().to_glib_none().0, frame_number)
53 };
54
55 if frame.is_null() {
56 None
57 } else {
58 unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
59 }
60 }
61
62 #[doc(alias = "get_frames")]
63 #[doc(alias = "gst_video_decoder_get_frames")]
64 fn frames(&self) -> Vec<VideoCodecFrame<'_>> {
65 unsafe {
66 let frames = ffi::gst_video_decoder_get_frames(self.as_ref().to_glib_none().0);
67 let mut iter: *const glib::ffi::GList = frames;
68 let mut vec = Vec::new();
69
70 while !iter.is_null() {
71 let frame_ptr = Ptr::from((*iter).data);
72 let frame = VideoCodecFrame::new(frame_ptr, self.as_ref());
74 vec.push(frame);
75 iter = (*iter).next;
76 }
77
78 glib::ffi::g_list_free(frames);
79 vec
80 }
81 }
82
83 #[doc(alias = "get_oldest_frame")]
84 #[doc(alias = "gst_video_decoder_get_oldest_frame")]
85 fn oldest_frame(&self) -> Option<VideoCodecFrame<'_>> {
86 let frame =
87 unsafe { ffi::gst_video_decoder_get_oldest_frame(self.as_ref().to_glib_none().0) };
88
89 if frame.is_null() {
90 None
91 } else {
92 unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
93 }
94 }
95
96 #[doc(alias = "get_allocator")]
97 #[doc(alias = "gst_video_decoder_get_allocator")]
98 fn allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams) {
99 unsafe {
100 let mut allocator = ptr::null_mut();
101 let mut params = mem::MaybeUninit::uninit();
102 ffi::gst_video_decoder_get_allocator(
103 self.as_ref().to_glib_none().0,
104 &mut allocator,
105 params.as_mut_ptr(),
106 );
107 (from_glib_full(allocator), params.assume_init().into())
108 }
109 }
110 #[doc(alias = "get_latency")]
111 #[doc(alias = "gst_video_decoder_get_latency")]
112 fn latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>) {
113 let mut min_latency = gst::ffi::GST_CLOCK_TIME_NONE;
114 let mut max_latency = gst::ffi::GST_CLOCK_TIME_NONE;
115
116 unsafe {
117 ffi::gst_video_decoder_get_latency(
118 self.as_ref().to_glib_none().0,
119 &mut min_latency,
120 &mut max_latency,
121 );
122
123 (
124 try_from_glib(min_latency).expect("undefined min_latency"),
125 from_glib(max_latency),
126 )
127 }
128 }
129
130 #[doc(alias = "gst_video_decoder_set_latency")]
131 fn set_latency(
132 &self,
133 min_latency: gst::ClockTime,
134 max_latency: impl Into<Option<gst::ClockTime>>,
135 ) {
136 unsafe {
137 ffi::gst_video_decoder_set_latency(
138 self.as_ref().to_glib_none().0,
139 min_latency.into_glib(),
140 max_latency.into().into_glib(),
141 );
142 }
143 }
144
145 #[doc(alias = "get_output_state")]
146 #[doc(alias = "gst_video_decoder_get_output_state")]
147 fn output_state(&self) -> Option<VideoCodecState<'static, Readable>> {
148 let state =
149 unsafe { ffi::gst_video_decoder_get_output_state(self.as_ref().to_glib_none().0) };
150
151 if state.is_null() {
152 None
153 } else {
154 unsafe { Some(VideoCodecState::<Readable>::new(state)) }
155 }
156 }
157
158 #[doc(alias = "gst_video_decoder_set_output_state")]
159 fn set_output_state(
160 &self,
161 fmt: VideoFormat,
162 width: u32,
163 height: u32,
164 reference: Option<&VideoCodecState<Readable>>,
165 ) -> Result<VideoCodecState<'_, InNegotiation<'_>>, gst::FlowError> {
166 let state = unsafe {
167 let reference = match reference {
168 Some(reference) => reference.as_mut_ptr(),
169 None => ptr::null_mut(),
170 };
171 ffi::gst_video_decoder_set_output_state(
172 self.as_ref().to_glib_none().0,
173 fmt.into_glib(),
174 width,
175 height,
176 reference,
177 )
178 };
179
180 if state.is_null() {
181 Err(gst::FlowError::NotNegotiated)
182 } else {
183 unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
184 }
185 }
186
187 #[cfg(feature = "v1_16")]
188 #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
189 #[doc(alias = "gst_video_decoder_set_interlaced_output_state")]
190 fn set_interlaced_output_state(
191 &self,
192 fmt: VideoFormat,
193 mode: VideoInterlaceMode,
194 width: u32,
195 height: u32,
196 reference: Option<&VideoCodecState<Readable>>,
197 ) -> Result<VideoCodecState<'_, InNegotiation<'_>>, gst::FlowError> {
198 let state = unsafe {
199 let reference = match reference {
200 Some(reference) => reference.as_mut_ptr(),
201 None => ptr::null_mut(),
202 };
203 ffi::gst_video_decoder_set_interlaced_output_state(
204 self.as_ref().to_glib_none().0,
205 fmt.into_glib(),
206 mode.into_glib(),
207 width,
208 height,
209 reference,
210 )
211 };
212
213 if state.is_null() {
214 Err(gst::FlowError::NotNegotiated)
215 } else {
216 unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
217 }
218 }
219
220 #[doc(alias = "gst_video_decoder_negotiate")]
221 fn negotiate<'a>(
222 &'a self,
223 output_state: VideoCodecState<'a, InNegotiation<'a>>,
224 ) -> Result<(), gst::FlowError> {
225 let self_ptr = self.to_glib_none().0 as *const gst::ffi::GstElement;
227 assert_eq!(output_state.context.element_as_ptr(), self_ptr);
228
229 let ret = unsafe {
230 from_glib(ffi::gst_video_decoder_negotiate(
231 self.as_ref().to_glib_none().0,
232 ))
233 };
234 if ret {
235 Ok(())
236 } else {
237 Err(gst::FlowError::NotNegotiated)
238 }
239 }
240
241 #[allow(clippy::too_many_arguments)]
242 fn error<T: gst::MessageErrorDomain>(
243 &self,
244 weight: i32,
245 code: T,
246 message: Option<&str>,
247 debug: Option<&str>,
248 file: &str,
249 function: &str,
250 line: u32,
251 ) -> Result<gst::FlowSuccess, gst::FlowError> {
252 unsafe {
253 try_from_glib(_gst_video_decoder_error(
254 self.as_ref().to_glib_none().0,
255 weight,
256 T::domain().into_glib(),
257 code.code(),
258 message.to_glib_full(),
259 debug.to_glib_full(),
260 file.to_glib_none().0,
261 function.to_glib_none().0,
262 line as i32,
263 ))
264 }
265 }
266
267 fn sink_pad(&self) -> &gst::Pad {
268 unsafe {
269 let elt = &*(self.as_ptr() as *const ffi::GstVideoDecoder);
270 &*(&elt.sinkpad as *const *mut gst::ffi::GstPad as *const gst::Pad)
271 }
272 }
273
274 fn src_pad(&self) -> &gst::Pad {
275 unsafe {
276 let elt = &*(self.as_ptr() as *const ffi::GstVideoDecoder);
277 &*(&elt.srcpad as *const *mut gst::ffi::GstPad as *const gst::Pad)
278 }
279 }
280
281 fn input_segment(&self) -> gst::Segment {
282 unsafe {
283 let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _);
284 glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock));
285 let segment = ptr.input_segment;
286 glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock));
287 from_glib_none(&segment as *const gst::ffi::GstSegment)
288 }
289 }
290
291 fn output_segment(&self) -> gst::Segment {
292 unsafe {
293 let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _);
294 glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock));
295 let segment = ptr.output_segment;
296 glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock));
297 from_glib_none(&segment as *const gst::ffi::GstSegment)
298 }
299 }
300}
301
302impl<O: IsA<VideoDecoder>> VideoDecoderExtManual for O {}
303
304impl HasStreamLock for VideoDecoder {
305 fn stream_lock(&self) -> *mut glib::ffi::GRecMutex {
306 let decoder_sys: *const ffi::GstVideoDecoder = self.to_glib_none().0;
307 unsafe { mut_override(&(*decoder_sys).stream_lock) }
308 }
309
310 fn element_as_ptr(&self) -> *const gst::ffi::GstElement {
311 self.as_ptr() as *mut gst::ffi::GstElement
312 }
313}
314
315#[macro_export]
316macro_rules! video_decoder_error(
317 ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { {
318 use $crate::prelude::VideoDecoderExtManual;
319 $obj.error(
320 $weight,
321 $err,
322 Some(&format!($($msg)*)),
323 Some(&format!($($debug)*)),
324 file!(),
325 $crate::glib::function_name!(),
326 line!(),
327 )
328 }};
329 ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*)) => { {
330 use $crate::prelude::VideoDecoderExtManual;
331 $obj.error(
332 $weight,
333 $err,
334 Some(&format!($($msg)*)),
335 None,
336 file!(),
337 $crate::glib::function_name!(),
338 line!(),
339 )
340 }};
341 ($obj:expr, $weight:expr, $err:expr, [$($debug:tt)*]) => { {
342 use $crate::prelude::VideoDecoderExtManual;
343 $obj.error(
344 $weight,
345 $err,
346 None,
347 Some(&format!($($debug)*)),
348 file!(),
349 $crate::glib::function_name!(),
350 line!(),
351 )
352 }};
353);