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