1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::{fmt, marker::PhantomData, mem}; |
4 | |
5 | use glib::translate::*; |
6 | |
7 | use crate::{utils::HasStreamLock, VideoCodecFrameFlags}; |
8 | |
9 | pub struct VideoCodecFrame<'a> { |
10 | frame: *mut ffi::GstVideoCodecFrame, |
11 | /* GstVideoCodecFrame API isn't safe so protect the frame using the |
12 | * element (decoder or encoder) stream lock */ |
13 | element: &'a dyn HasStreamLock, |
14 | } |
15 | |
16 | #[doc (hidden)] |
17 | impl<'a> ::glib::translate::ToGlibPtr<'a, *mut ffi::GstVideoCodecFrame> for VideoCodecFrame<'a> { |
18 | type Storage = PhantomData<&'a Self>; |
19 | |
20 | #[inline ] |
21 | fn to_glib_none(&'a self) -> ::glib::translate::Stash<'a, *mut ffi::GstVideoCodecFrame, Self> { |
22 | Stash(self.frame, PhantomData) |
23 | } |
24 | |
25 | #[inline ] |
26 | fn to_glib_full(&self) -> *mut ffi::GstVideoCodecFrame { |
27 | unsafe { ffi::gst_video_codec_frame_ref(self.frame) } |
28 | } |
29 | } |
30 | |
31 | impl<'a> fmt::Debug for VideoCodecFrame<'a> { |
32 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
33 | let mut b: DebugStruct<'_, '_> = f.debug_struct(name:"VideoCodecFrame" ); |
34 | |
35 | b.field("flags" , &self.flags()) |
36 | .field("system_frame_number" , &self.system_frame_number()) |
37 | .field("decode_frame_number" , &self.decode_frame_number()) |
38 | .field( |
39 | "presentation_frame_number" , |
40 | &self.presentation_frame_number(), |
41 | ) |
42 | .field("dts" , &self.dts()) |
43 | .field("pts" , &self.pts()) |
44 | .field("duration" , &self.duration()) |
45 | .field("distance_from_sync" , &self.distance_from_sync()) |
46 | .field("input_buffer" , &self.input_buffer()) |
47 | .field("output_buffer" , &self.output_buffer()) |
48 | .field(name:"deadline" , &self.deadline()); |
49 | |
50 | b.finish() |
51 | } |
52 | } |
53 | |
54 | impl<'a> VideoCodecFrame<'a> { |
55 | // Take ownership of @frame |
56 | pub(crate) unsafe fn new<T: HasStreamLock>( |
57 | frame: *mut ffi::GstVideoCodecFrame, |
58 | element: &'a T, |
59 | ) -> Self { |
60 | skip_assert_initialized!(); |
61 | let stream_lock = element.stream_lock(); |
62 | glib::ffi::g_rec_mutex_lock(stream_lock); |
63 | Self { frame, element } |
64 | } |
65 | |
66 | #[doc (alias = "get_flags" )] |
67 | #[inline ] |
68 | pub fn flags(&self) -> VideoCodecFrameFlags { |
69 | let flags = unsafe { (*self.to_glib_none().0).flags }; |
70 | VideoCodecFrameFlags::from_bits_truncate(flags) |
71 | } |
72 | |
73 | #[inline ] |
74 | pub fn set_flags(&mut self, flags: VideoCodecFrameFlags) { |
75 | unsafe { (*self.to_glib_none().0).flags |= flags.bits() } |
76 | } |
77 | |
78 | #[inline ] |
79 | pub fn unset_flags(&mut self, flags: VideoCodecFrameFlags) { |
80 | unsafe { (*self.to_glib_none().0).flags &= !flags.bits() } |
81 | } |
82 | |
83 | #[doc (alias = "get_system_frame_number" )] |
84 | #[inline ] |
85 | pub fn system_frame_number(&self) -> u32 { |
86 | unsafe { (*self.to_glib_none().0).system_frame_number } |
87 | } |
88 | |
89 | #[doc (alias = "get_decode_frame_number" )] |
90 | #[inline ] |
91 | pub fn decode_frame_number(&self) -> u32 { |
92 | unsafe { (*self.to_glib_none().0).decode_frame_number } |
93 | } |
94 | |
95 | #[doc (alias = "get_presentation_frame_number" )] |
96 | #[inline ] |
97 | pub fn presentation_frame_number(&self) -> u32 { |
98 | unsafe { (*self.to_glib_none().0).presentation_frame_number } |
99 | } |
100 | |
101 | #[doc (alias = "get_dts" )] |
102 | #[inline ] |
103 | pub fn dts(&self) -> Option<gst::ClockTime> { |
104 | unsafe { from_glib((*self.to_glib_none().0).dts) } |
105 | } |
106 | |
107 | #[inline ] |
108 | pub fn set_dts(&mut self, dts: impl Into<Option<gst::ClockTime>>) { |
109 | unsafe { |
110 | (*self.to_glib_none().0).dts = dts.into().into_glib(); |
111 | } |
112 | } |
113 | |
114 | #[doc (alias = "get_pts" )] |
115 | #[inline ] |
116 | pub fn pts(&self) -> Option<gst::ClockTime> { |
117 | unsafe { from_glib((*self.to_glib_none().0).pts) } |
118 | } |
119 | |
120 | #[inline ] |
121 | pub fn set_pts(&mut self, pts: impl Into<Option<gst::ClockTime>>) { |
122 | unsafe { |
123 | (*self.to_glib_none().0).pts = pts.into().into_glib(); |
124 | } |
125 | } |
126 | |
127 | #[doc (alias = "get_duration" )] |
128 | #[inline ] |
129 | pub fn duration(&self) -> Option<gst::ClockTime> { |
130 | unsafe { from_glib((*self.to_glib_none().0).duration) } |
131 | } |
132 | |
133 | #[inline ] |
134 | pub fn set_duration(&mut self, duration: impl Into<Option<gst::ClockTime>>) { |
135 | unsafe { |
136 | (*self.to_glib_none().0).duration = duration.into().into_glib(); |
137 | } |
138 | } |
139 | |
140 | #[doc (alias = "get_distance_from_sync" )] |
141 | #[inline ] |
142 | pub fn distance_from_sync(&self) -> i32 { |
143 | unsafe { (*self.to_glib_none().0).distance_from_sync } |
144 | } |
145 | |
146 | #[doc (alias = "get_input_buffer" )] |
147 | #[inline ] |
148 | pub fn input_buffer(&self) -> Option<&gst::BufferRef> { |
149 | unsafe { |
150 | let ptr = (*self.to_glib_none().0).input_buffer; |
151 | if ptr.is_null() { |
152 | None |
153 | } else { |
154 | Some(gst::BufferRef::from_ptr(ptr)) |
155 | } |
156 | } |
157 | } |
158 | |
159 | #[doc (alias = "get_input_buffer" )] |
160 | #[inline ] |
161 | pub fn input_buffer_owned(&self) -> Option<gst::Buffer> { |
162 | unsafe { |
163 | let ptr = (*self.to_glib_none().0).input_buffer; |
164 | if ptr.is_null() { |
165 | None |
166 | } else { |
167 | Some(from_glib_none(ptr)) |
168 | } |
169 | } |
170 | } |
171 | |
172 | #[doc (alias = "get_output_buffer" )] |
173 | #[inline ] |
174 | pub fn output_buffer(&self) -> Option<&gst::BufferRef> { |
175 | unsafe { |
176 | let ptr = (*self.to_glib_none().0).output_buffer; |
177 | if ptr.is_null() { |
178 | None |
179 | } else { |
180 | Some(gst::BufferRef::from_ptr(ptr)) |
181 | } |
182 | } |
183 | } |
184 | |
185 | #[doc (alias = "get_output_buffer_mut" )] |
186 | pub fn output_buffer_mut(&mut self) -> Option<&mut gst::BufferRef> { |
187 | unsafe { |
188 | let ptr = (*self.to_glib_none().0).output_buffer; |
189 | if ptr.is_null() { |
190 | None |
191 | } else { |
192 | let writable: bool = from_glib(gst::ffi::gst_mini_object_is_writable( |
193 | ptr as *const gst::ffi::GstMiniObject, |
194 | )); |
195 | debug_assert!(writable); |
196 | |
197 | Some(gst::BufferRef::from_mut_ptr(ptr)) |
198 | } |
199 | } |
200 | } |
201 | |
202 | pub fn set_output_buffer(&mut self, output_buffer: gst::Buffer) { |
203 | unsafe { |
204 | assert!(output_buffer.is_writable()); |
205 | let prev = (*self.to_glib_none().0).output_buffer; |
206 | |
207 | if !prev.is_null() { |
208 | gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject); |
209 | } |
210 | |
211 | (*self.to_glib_none().0).output_buffer = output_buffer.into_glib_ptr(); |
212 | } |
213 | } |
214 | |
215 | #[doc (alias = "get_deadline" )] |
216 | #[inline ] |
217 | pub fn deadline(&self) -> Option<gst::ClockTime> { |
218 | unsafe { from_glib((*self.to_glib_none().0).deadline) } |
219 | } |
220 | |
221 | #[cfg (feature = "v1_20" )] |
222 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_20" )))] |
223 | #[doc (alias = "gst_video_decoder_get_processed_subframe_index" )] |
224 | #[inline ] |
225 | pub fn subframes_processed(&self) -> u32 { |
226 | unsafe { (*self.to_glib_none().0).abidata.ABI.subframes_processed } |
227 | } |
228 | |
229 | #[cfg (feature = "v1_20" )] |
230 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_20" )))] |
231 | #[doc (alias = "gst_video_decoder_get_input_subframe_index" )] |
232 | #[inline ] |
233 | pub fn num_subframes(&self) -> u32 { |
234 | unsafe { (*self.to_glib_none().0).abidata.ABI.num_subframes } |
235 | } |
236 | } |
237 | |
238 | impl<'a> IntoGlibPtr<*mut ffi::GstVideoCodecFrame> for VideoCodecFrame<'a> { |
239 | #[inline ] |
240 | unsafe fn into_glib_ptr(self) -> *mut ffi::GstVideoCodecFrame { |
241 | let stream_lock: *mut GRecMutex = self.element.stream_lock(); |
242 | glib::ffi::g_rec_mutex_unlock(rec_mutex:stream_lock); |
243 | |
244 | let s: ManuallyDrop> = mem::ManuallyDrop::new(self); |
245 | s.to_glib_none().0 |
246 | } |
247 | } |
248 | |
249 | impl<'a> Drop for VideoCodecFrame<'a> { |
250 | #[inline ] |
251 | fn drop(&mut self) { |
252 | unsafe { |
253 | let stream_lock: *mut GRecMutex = self.element.stream_lock(); |
254 | glib::ffi::g_rec_mutex_unlock(rec_mutex:stream_lock); |
255 | |
256 | ffi::gst_video_codec_frame_unref(self.frame); |
257 | } |
258 | } |
259 | } |
260 | |