Skip to main content

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