gstreamer_video/
video_codec_frame.rs

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::{ffi, 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 fmt::Debug for VideoCodecFrame<'_> {
32    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33        let mut b = f.debug_struct("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("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 IntoGlibPtr<*mut ffi::GstVideoCodecFrame> for VideoCodecFrame<'_> {
239    #[inline]
240    unsafe fn into_glib_ptr(self) -> *mut ffi::GstVideoCodecFrame {
241        let stream_lock = self.element.stream_lock();
242        glib::ffi::g_rec_mutex_unlock(stream_lock);
243
244        let s = mem::ManuallyDrop::new(self);
245        s.to_glib_none().0
246    }
247}
248
249impl Drop for VideoCodecFrame<'_> {
250    #[inline]
251    fn drop(&mut self) {
252        unsafe {
253            let stream_lock = self.element.stream_lock();
254            glib::ffi::g_rec_mutex_unlock(stream_lock);
255
256            ffi::gst_video_codec_frame_unref(self.frame);
257        }
258    }
259}