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        let stream_lock = element.stream_lock();
95        glib::ffi::g_rec_mutex_lock(stream_lock);
96        Self {
97            state,
98            context: InNegotiation { element },
99            phantom: PhantomData,
100        }
101    }
102}
103
104impl<'a, T: VideoCodecStateContext<'a>> VideoCodecState<'a, T> {
105    #[doc(alias = "get_info")]
106    #[inline]
107    pub fn info(&self) -> &VideoInfo {
108        unsafe {
109            &*(&(*self.as_mut_ptr()).info as *const ffi::GstVideoInfo as *const crate::VideoInfo)
110        }
111    }
112
113    #[doc(alias = "get_caps")]
114    #[inline]
115    pub fn caps(&self) -> Option<&gst::CapsRef> {
116        unsafe {
117            let ptr = (*self.as_mut_ptr()).caps;
118
119            if ptr.is_null() {
120                None
121            } else {
122                Some(gst::CapsRef::from_ptr(ptr))
123            }
124        }
125    }
126
127    #[doc(alias = "get_caps")]
128    #[inline]
129    pub fn caps_owned(&self) -> Option<gst::Caps> {
130        unsafe { from_glib_none((*self.as_mut_ptr()).caps) }
131    }
132
133    #[doc(alias = "get_codec_data")]
134    #[inline]
135    pub fn codec_data(&self) -> Option<&gst::BufferRef> {
136        unsafe {
137            let ptr = (*self.as_mut_ptr()).codec_data;
138
139            if ptr.is_null() {
140                None
141            } else {
142                Some(gst::BufferRef::from_ptr(ptr))
143            }
144        }
145    }
146
147    #[doc(alias = "get_codec_data")]
148    #[inline]
149    pub fn codec_data_owned(&self) -> Option<gst::Buffer> {
150        unsafe { from_glib_none((*self.as_mut_ptr()).codec_data) }
151    }
152
153    #[doc(alias = "get_allocation_caps")]
154    #[inline]
155    pub fn allocation_caps(&self) -> Option<&gst::CapsRef> {
156        unsafe {
157            let ptr = (*self.as_mut_ptr()).allocation_caps;
158
159            if ptr.is_null() {
160                None
161            } else {
162                Some(gst::CapsRef::from_ptr(ptr))
163            }
164        }
165    }
166
167    #[doc(alias = "get_allocation_caps")]
168    #[inline]
169    pub fn allocation_caps_owned(&self) -> Option<gst::Caps> {
170        unsafe { from_glib_none((*self.as_mut_ptr()).allocation_caps) }
171    }
172
173    #[doc(hidden)]
174    #[inline]
175    pub fn as_mut_ptr(&self) -> *mut ffi::GstVideoCodecState {
176        self.state
177    }
178}
179
180impl<'a, T: VideoCodecStateContext<'a>> Drop for VideoCodecState<'a, T> {
181    #[inline]
182    fn drop(&mut self) {
183        unsafe {
184            if let Some(element) = self.context.element() {
185                let stream_lock = element.stream_lock();
186                glib::ffi::g_rec_mutex_unlock(stream_lock);
187            }
188            ffi::gst_video_codec_state_unref(self.state);
189        }
190    }
191}
192
193impl<'a> VideoCodecState<'a, InNegotiation<'a>> {
194    #[inline]
195    pub fn set_info(&mut self, info: VideoInfo) {
196        unsafe {
197            ptr::write(&mut (*self.as_mut_ptr()).info, *(info.to_glib_none().0));
198        }
199    }
200
201    #[inline]
202    pub fn set_caps(&mut self, caps: &gst::Caps) {
203        unsafe {
204            let prev = (*self.as_mut_ptr()).caps;
205
206            if !prev.is_null() {
207                gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
208            }
209
210            ptr::write(
211                &mut (*self.as_mut_ptr()).caps,
212                gst::ffi::gst_mini_object_ref(caps.as_mut_ptr() as *mut _) as *mut _,
213            );
214        }
215    }
216
217    #[inline]
218    pub fn set_codec_data(&mut self, codec_data: &gst::Buffer) {
219        unsafe {
220            let prev = (*self.as_mut_ptr()).codec_data;
221
222            if !prev.is_null() {
223                gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
224            }
225
226            ptr::write(
227                &mut (*self.as_mut_ptr()).codec_data,
228                gst::ffi::gst_mini_object_ref(codec_data.as_mut_ptr() as *mut _) as *mut _,
229            );
230        }
231    }
232
233    #[inline]
234    pub fn set_allocation_caps(&mut self, allocation_caps: &gst::Caps) {
235        unsafe {
236            let prev = (*self.as_mut_ptr()).allocation_caps;
237
238            if !prev.is_null() {
239                gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
240            }
241
242            ptr::write(
243                &mut (*self.as_mut_ptr()).allocation_caps,
244                gst::ffi::gst_mini_object_ref(allocation_caps.as_mut_ptr() as *mut _) as *mut _,
245            );
246        }
247    }
248}
249
250impl Clone for VideoCodecState<'_, Readable> {
251    #[inline]
252    fn clone(&self) -> Self {
253        unsafe {
254            let state = ffi::gst_video_codec_state_ref(self.state);
255            Self::new(state)
256        }
257    }
258}
259
260unsafe impl Send for VideoCodecState<'_, Readable> {}
261unsafe impl Sync for VideoCodecState<'_, Readable> {}