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