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
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        let stream_lock = element.stream_lock();
64        glib::ffi::g_rec_mutex_lock(stream_lock);
65        Self { frame, element }
66    }
67
68    #[doc(alias = "get_flags")]
69    #[inline]
70    pub fn flags(&self) -> VideoCodecFrameFlags {
71        let flags = unsafe { (*self.to_glib_none().0).flags };
72        VideoCodecFrameFlags::from_bits_truncate(flags)
73    }
74
75    #[inline]
76    pub fn set_flags(&mut self, flags: VideoCodecFrameFlags) {
77        unsafe { (*self.to_glib_none().0).flags |= flags.bits() }
78    }
79
80    #[inline]
81    pub fn unset_flags(&mut self, flags: VideoCodecFrameFlags) {
82        unsafe { (*self.to_glib_none().0).flags &= !flags.bits() }
83    }
84
85    #[doc(alias = "get_system_frame_number")]
86    #[inline]
87    pub fn system_frame_number(&self) -> u32 {
88        unsafe { (*self.to_glib_none().0).system_frame_number }
89    }
90
91    #[doc(alias = "get_decode_frame_number")]
92    #[inline]
93    pub fn decode_frame_number(&self) -> u32 {
94        unsafe { (*self.to_glib_none().0).decode_frame_number }
95    }
96
97    #[doc(alias = "get_presentation_frame_number")]
98    #[inline]
99    pub fn presentation_frame_number(&self) -> u32 {
100        unsafe { (*self.to_glib_none().0).presentation_frame_number }
101    }
102
103    #[doc(alias = "get_dts")]
104    #[inline]
105    pub fn dts(&self) -> Option<gst::ClockTime> {
106        unsafe { from_glib((*self.to_glib_none().0).dts) }
107    }
108
109    #[inline]
110    pub fn set_dts(&mut self, dts: impl Into<Option<gst::ClockTime>>) {
111        unsafe {
112            (*self.to_glib_none().0).dts = dts.into().into_glib();
113        }
114    }
115
116    #[doc(alias = "get_pts")]
117    #[inline]
118    pub fn pts(&self) -> Option<gst::ClockTime> {
119        unsafe { from_glib((*self.to_glib_none().0).pts) }
120    }
121
122    #[inline]
123    pub fn set_pts(&mut self, pts: impl Into<Option<gst::ClockTime>>) {
124        unsafe {
125            (*self.to_glib_none().0).pts = pts.into().into_glib();
126        }
127    }
128
129    #[doc(alias = "get_duration")]
130    #[inline]
131    pub fn duration(&self) -> Option<gst::ClockTime> {
132        unsafe { from_glib((*self.to_glib_none().0).duration) }
133    }
134
135    #[inline]
136    pub fn set_duration(&mut self, duration: impl Into<Option<gst::ClockTime>>) {
137        unsafe {
138            (*self.to_glib_none().0).duration = duration.into().into_glib();
139        }
140    }
141
142    #[doc(alias = "get_distance_from_sync")]
143    #[inline]
144    pub fn distance_from_sync(&self) -> i32 {
145        unsafe { (*self.to_glib_none().0).distance_from_sync }
146    }
147
148    #[doc(alias = "get_input_buffer")]
149    #[inline]
150    pub fn input_buffer(&self) -> Option<&gst::BufferRef> {
151        unsafe {
152            let ptr = (*self.to_glib_none().0).input_buffer;
153            if ptr.is_null() {
154                None
155            } else {
156                Some(gst::BufferRef::from_ptr(ptr))
157            }
158        }
159    }
160
161    #[doc(alias = "get_input_buffer")]
162    #[inline]
163    pub fn input_buffer_owned(&self) -> Option<gst::Buffer> {
164        unsafe {
165            let ptr = (*self.to_glib_none().0).input_buffer;
166            if ptr.is_null() {
167                None
168            } else {
169                Some(from_glib_none(ptr))
170            }
171        }
172    }
173
174    #[doc(alias = "get_output_buffer")]
175    #[inline]
176    pub fn output_buffer(&self) -> Option<&gst::BufferRef> {
177        unsafe {
178            let ptr = (*self.to_glib_none().0).output_buffer;
179            if ptr.is_null() {
180                None
181            } else {
182                Some(gst::BufferRef::from_ptr(ptr))
183            }
184        }
185    }
186
187    #[doc(alias = "get_output_buffer_mut")]
188    pub fn output_buffer_mut(&mut self) -> Option<&mut gst::BufferRef> {
189        unsafe {
190            let ptr = (*self.to_glib_none().0).output_buffer;
191            if ptr.is_null() {
192                None
193            } else {
194                let writable: bool = from_glib(gst::ffi::gst_mini_object_is_writable(
195                    ptr as *const gst::ffi::GstMiniObject,
196                ));
197                debug_assert!(writable);
198
199                Some(gst::BufferRef::from_mut_ptr(ptr))
200            }
201        }
202    }
203
204    pub fn set_output_buffer(&mut self, output_buffer: gst::Buffer) {
205        unsafe {
206            assert!(output_buffer.is_writable());
207            let prev = (*self.to_glib_none().0).output_buffer;
208
209            if !prev.is_null() {
210                gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject);
211            }
212
213            (*self.to_glib_none().0).output_buffer = output_buffer.into_glib_ptr();
214        }
215    }
216
217    #[doc(alias = "get_deadline")]
218    #[inline]
219    pub fn deadline(&self) -> Option<gst::ClockTime> {
220        unsafe { from_glib((*self.to_glib_none().0).deadline) }
221    }
222
223    #[cfg(feature = "v1_20")]
224    #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
225    #[doc(alias = "gst_video_decoder_get_processed_subframe_index")]
226    #[inline]
227    pub fn subframes_processed(&self) -> u32 {
228        unsafe { (*self.to_glib_none().0).abidata.ABI.subframes_processed }
229    }
230
231    #[cfg(feature = "v1_20")]
232    #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
233    #[doc(alias = "gst_video_decoder_get_input_subframe_index")]
234    #[inline]
235    pub fn num_subframes(&self) -> u32 {
236        unsafe { (*self.to_glib_none().0).abidata.ABI.num_subframes }
237    }
238}
239
240impl IntoGlibPtr<*mut ffi::GstVideoCodecFrame> for VideoCodecFrame<'_> {
241    #[inline]
242    fn into_glib_ptr(self) -> *mut ffi::GstVideoCodecFrame {
243        let stream_lock = self.element.stream_lock();
244        unsafe {
245            glib::ffi::g_rec_mutex_unlock(stream_lock);
246        }
247
248        let s = mem::ManuallyDrop::new(self);
249        s.to_glib_none().0
250    }
251}
252
253impl Drop for VideoCodecFrame<'_> {
254    #[inline]
255    fn drop(&mut self) {
256        unsafe {
257            let stream_lock = self.element.stream_lock();
258            glib::ffi::g_rec_mutex_unlock(stream_lock);
259
260            ffi::gst_video_codec_frame_unref(self.frame);
261        }
262    }
263}