1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, marker::PhantomData, mem};
4
5use glib::translate::*;
6
7use crate::{utils::HasStreamLock, VideoCodecFrameFlags};
8
9pub 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)]
17impl<'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
31impl<'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
54impl<'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
238impl<'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
249impl<'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