Skip to main content

gstreamer_video/
video_codec_state.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, marker::PhantomData, ptr};
4
5use glib::translate::*;
6
7use crate::{ffi, utils::HasStreamLock, video_info::VideoInfo};
8
9pub trait VideoCodecStateContext<'a> {
10    #[doc(alias = "get_element")]
11    fn element(&self) -> Option<&'a dyn HasStreamLock>;
12    #[doc(alias = "get_element_as_ptr")]
13    fn element_as_ptr(&self) -> *const gst::ffi::GstElement;
14}
15
16pub struct InNegotiation<'a> {
17    /* GstVideoCodecState API isn't safe so protect the state using the
18     * element (decoder or encoder) stream lock */
19    element: &'a dyn HasStreamLock,
20}
21pub struct Readable {}
22
23impl<'a> VideoCodecStateContext<'a> for InNegotiation<'a> {
24    #[inline]
25    fn element(&self) -> Option<&'a dyn HasStreamLock> {
26        Some(self.element)
27    }
28
29    #[inline]
30    fn element_as_ptr(&self) -> *const gst::ffi::GstElement {
31        self.element.element_as_ptr()
32    }
33}
34
35impl<'a> VideoCodecStateContext<'a> for Readable {
36    #[inline]
37    fn element(&self) -> Option<&'a dyn HasStreamLock> {
38        None
39    }
40
41    #[inline]
42    fn element_as_ptr(&self) -> *const gst::ffi::GstElement {
43        ptr::null()
44    }
45}
46
47/// Structure representing the state of an incoming or outgoing video
48/// stream for encoders and decoders.
49///
50/// Decoders and encoders will receive such a state through their
51/// respective `set_format` vmethods.
52///
53/// Decoders and encoders can set the downstream state, by using the
54/// [`VideoDecoderExtManual::set_output_state()`][crate::prelude::VideoDecoderExtManual::set_output_state()] or
55/// [`VideoEncoderExtManual::set_output_state()`][crate::prelude::VideoEncoderExtManual::set_output_state()] methods.
56pub struct VideoCodecState<'a, T: VideoCodecStateContext<'a>> {
57    state: *mut ffi::GstVideoCodecState,
58    pub(crate) context: T,
59    phantom: PhantomData<&'a T>,
60}
61
62impl<'a, T: VideoCodecStateContext<'a>> fmt::Debug for VideoCodecState<'a, T> {
63    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
64        f.debug_struct("VideoCodecState")
65            .field("info", &self.info())
66            .field("caps", &self.caps())
67            .field("codec_data", &self.codec_data())
68            .field("allocation_caps", &self.allocation_caps())
69            .finish()
70    }
71}
72
73impl VideoCodecState<'_, Readable> {
74    // Take ownership of @state
75    #[inline]
76    pub(crate) unsafe fn new(state: *mut ffi::GstVideoCodecState) -> Self {
77        skip_assert_initialized!();
78        Self {
79            state,
80            context: Readable {},
81            phantom: PhantomData,
82        }
83    }
84}
85
86impl<'a> VideoCodecState<'a, InNegotiation<'a>> {
87    // Take ownership of @state
88    #[inline]
89    pub(crate) unsafe fn new<T: HasStreamLock>(
90        state: *mut ffi::GstVideoCodecState,
91        element: &'a T,
92    ) -> Self {
93        skip_assert_initialized!();
94        unsafe {
95            let stream_lock = element.stream_lock();
96            glib::ffi::g_rec_mutex_lock(stream_lock);
97            Self {
98                state,
99                context: InNegotiation { element },
100                phantom: PhantomData,
101            }
102        }
103    }
104}
105
106impl<'a, T: VideoCodecStateContext<'a>> VideoCodecState<'a, T> {
107    #[doc(alias = "get_info")]
108    #[inline]
109    pub fn info(&self) -> &VideoInfo {
110        unsafe {
111            &*(&(*self.as_mut_ptr()).info as *const ffi::GstVideoInfo as *const crate::VideoInfo)
112        }
113    }
114
115    #[doc(alias = "get_caps")]
116    #[inline]
117    pub fn caps(&self) -> Option<&gst::CapsRef> {
118        unsafe {
119            let ptr = (*self.as_mut_ptr()).caps;
120
121            if ptr.is_null() {
122                None
123            } else {
124                Some(gst::CapsRef::from_ptr(ptr))
125            }
126        }
127    }
128
129    #[doc(alias = "get_caps")]
130    #[inline]
131    pub fn caps_owned(&self) -> Option<gst::Caps> {
132        unsafe { from_glib_none((*self.as_mut_ptr()).caps) }
133    }
134
135    #[doc(alias = "get_codec_data")]
136    #[inline]
137    pub fn codec_data(&self) -> Option<&gst::BufferRef> {
138        unsafe {
139            let ptr = (*self.as_mut_ptr()).codec_data;
140
141            if ptr.is_null() {
142                None
143            } else {
144                Some(gst::BufferRef::from_ptr(ptr))
145            }
146        }
147    }
148
149    #[doc(alias = "get_codec_data")]
150    #[inline]
151    pub fn codec_data_owned(&self) -> Option<gst::Buffer> {
152        unsafe { from_glib_none((*self.as_mut_ptr()).codec_data) }
153    }
154
155    #[doc(alias = "get_allocation_caps")]
156    #[inline]
157    pub fn allocation_caps(&self) -> Option<&gst::CapsRef> {
158        unsafe {
159            let ptr = (*self.as_mut_ptr()).allocation_caps;
160
161            if ptr.is_null() {
162                None
163            } else {
164                Some(gst::CapsRef::from_ptr(ptr))
165            }
166        }
167    }
168
169    #[doc(alias = "get_allocation_caps")]
170    #[inline]
171    pub fn allocation_caps_owned(&self) -> Option<gst::Caps> {
172        unsafe { from_glib_none((*self.as_mut_ptr()).allocation_caps) }
173    }
174
175    #[doc(hidden)]
176    #[inline]
177    pub fn as_mut_ptr(&self) -> *mut ffi::GstVideoCodecState {
178        self.state
179    }
180}
181
182impl<'a, T: VideoCodecStateContext<'a>> Drop for VideoCodecState<'a, T> {
183    #[inline]
184    fn drop(&mut self) {
185        unsafe {
186            if let Some(element) = self.context.element() {
187                let stream_lock = element.stream_lock();
188                glib::ffi::g_rec_mutex_unlock(stream_lock);
189            }
190            ffi::gst_video_codec_state_unref(self.state);
191        }
192    }
193}
194
195impl<'a> VideoCodecState<'a, InNegotiation<'a>> {
196    #[inline]
197    pub fn set_info(&mut self, info: VideoInfo) {
198        unsafe {
199            ptr::write(&mut (*self.as_mut_ptr()).info, *(info.to_glib_none().0));
200        }
201    }
202
203    #[inline]
204    pub fn set_caps(&mut self, caps: &gst::Caps) {
205        unsafe {
206            let prev = (*self.as_mut_ptr()).caps;
207
208            if !prev.is_null() {
209                gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
210            }
211
212            ptr::write(
213                &mut (*self.as_mut_ptr()).caps,
214                gst::ffi::gst_mini_object_ref(caps.as_mut_ptr() as *mut _) as *mut _,
215            );
216        }
217    }
218
219    #[inline]
220    pub fn set_codec_data(&mut self, codec_data: &gst::Buffer) {
221        unsafe {
222            let prev = (*self.as_mut_ptr()).codec_data;
223
224            if !prev.is_null() {
225                gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
226            }
227
228            ptr::write(
229                &mut (*self.as_mut_ptr()).codec_data,
230                gst::ffi::gst_mini_object_ref(codec_data.as_mut_ptr() as *mut _) as *mut _,
231            );
232        }
233    }
234
235    #[inline]
236    pub fn set_allocation_caps(&mut self, allocation_caps: &gst::Caps) {
237        unsafe {
238            let prev = (*self.as_mut_ptr()).allocation_caps;
239
240            if !prev.is_null() {
241                gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
242            }
243
244            ptr::write(
245                &mut (*self.as_mut_ptr()).allocation_caps,
246                gst::ffi::gst_mini_object_ref(allocation_caps.as_mut_ptr() as *mut _) as *mut _,
247            );
248        }
249    }
250}
251
252impl Clone for VideoCodecState<'_, Readable> {
253    #[inline]
254    fn clone(&self) -> Self {
255        unsafe {
256            let state = ffi::gst_video_codec_state_ref(self.state);
257            Self::new(state)
258        }
259    }
260}
261
262unsafe impl Send for VideoCodecState<'_, Readable> {}
263unsafe impl Sync for VideoCodecState<'_, Readable> {}