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
47pub struct VideoCodecState<'a, T: VideoCodecStateContext<'a>> {
48    state: *mut ffi::GstVideoCodecState,
49    pub(crate) context: T,
50    phantom: PhantomData<&'a T>,
51}
52
53impl<'a, T: VideoCodecStateContext<'a>> fmt::Debug for VideoCodecState<'a, T> {
54    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55        f.debug_struct("VideoCodecState")
56            .field("info", &self.info())
57            .field("caps", &self.caps())
58            .field("codec_data", &self.codec_data())
59            .field("allocation_caps", &self.allocation_caps())
60            .finish()
61    }
62}
63
64impl VideoCodecState<'_, Readable> {
65    // Take ownership of @state
66    #[inline]
67    pub(crate) unsafe fn new(state: *mut ffi::GstVideoCodecState) -> Self {
68        skip_assert_initialized!();
69        Self {
70            state,
71            context: Readable {},
72            phantom: PhantomData,
73        }
74    }
75}
76
77impl<'a> VideoCodecState<'a, InNegotiation<'a>> {
78    // Take ownership of @state
79    #[inline]
80    pub(crate) unsafe fn new<T: HasStreamLock>(
81        state: *mut ffi::GstVideoCodecState,
82        element: &'a T,
83    ) -> Self {
84        skip_assert_initialized!();
85        unsafe {
86            let stream_lock = element.stream_lock();
87            glib::ffi::g_rec_mutex_lock(stream_lock);
88            Self {
89                state,
90                context: InNegotiation { element },
91                phantom: PhantomData,
92            }
93        }
94    }
95}
96
97impl<'a, T: VideoCodecStateContext<'a>> VideoCodecState<'a, T> {
98    #[doc(alias = "get_info")]
99    #[inline]
100    pub fn info(&self) -> &VideoInfo {
101        unsafe {
102            &*(&(*self.as_mut_ptr()).info as *const ffi::GstVideoInfo as *const crate::VideoInfo)
103        }
104    }
105
106    #[doc(alias = "get_caps")]
107    #[inline]
108    pub fn caps(&self) -> Option<&gst::CapsRef> {
109        unsafe {
110            let ptr = (*self.as_mut_ptr()).caps;
111
112            if ptr.is_null() {
113                None
114            } else {
115                Some(gst::CapsRef::from_ptr(ptr))
116            }
117        }
118    }
119
120    #[doc(alias = "get_caps")]
121    #[inline]
122    pub fn caps_owned(&self) -> Option<gst::Caps> {
123        unsafe { from_glib_none((*self.as_mut_ptr()).caps) }
124    }
125
126    #[doc(alias = "get_codec_data")]
127    #[inline]
128    pub fn codec_data(&self) -> Option<&gst::BufferRef> {
129        unsafe {
130            let ptr = (*self.as_mut_ptr()).codec_data;
131
132            if ptr.is_null() {
133                None
134            } else {
135                Some(gst::BufferRef::from_ptr(ptr))
136            }
137        }
138    }
139
140    #[doc(alias = "get_codec_data")]
141    #[inline]
142    pub fn codec_data_owned(&self) -> Option<gst::Buffer> {
143        unsafe { from_glib_none((*self.as_mut_ptr()).codec_data) }
144    }
145
146    #[doc(alias = "get_allocation_caps")]
147    #[inline]
148    pub fn allocation_caps(&self) -> Option<&gst::CapsRef> {
149        unsafe {
150            let ptr = (*self.as_mut_ptr()).allocation_caps;
151
152            if ptr.is_null() {
153                None
154            } else {
155                Some(gst::CapsRef::from_ptr(ptr))
156            }
157        }
158    }
159
160    #[doc(alias = "get_allocation_caps")]
161    #[inline]
162    pub fn allocation_caps_owned(&self) -> Option<gst::Caps> {
163        unsafe { from_glib_none((*self.as_mut_ptr()).allocation_caps) }
164    }
165
166    #[doc(hidden)]
167    #[inline]
168    pub fn as_mut_ptr(&self) -> *mut ffi::GstVideoCodecState {
169        self.state
170    }
171}
172
173impl<'a, T: VideoCodecStateContext<'a>> Drop for VideoCodecState<'a, T> {
174    #[inline]
175    fn drop(&mut self) {
176        unsafe {
177            if let Some(element) = self.context.element() {
178                let stream_lock = element.stream_lock();
179                glib::ffi::g_rec_mutex_unlock(stream_lock);
180            }
181            ffi::gst_video_codec_state_unref(self.state);
182        }
183    }
184}
185
186impl<'a> VideoCodecState<'a, InNegotiation<'a>> {
187    #[inline]
188    pub fn set_info(&mut self, info: VideoInfo) {
189        unsafe {
190            ptr::write(&mut (*self.as_mut_ptr()).info, *(info.to_glib_none().0));
191        }
192    }
193
194    #[inline]
195    pub fn set_caps(&mut self, caps: &gst::Caps) {
196        unsafe {
197            let prev = (*self.as_mut_ptr()).caps;
198
199            if !prev.is_null() {
200                gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
201            }
202
203            ptr::write(
204                &mut (*self.as_mut_ptr()).caps,
205                gst::ffi::gst_mini_object_ref(caps.as_mut_ptr() as *mut _) as *mut _,
206            );
207        }
208    }
209
210    #[inline]
211    pub fn set_codec_data(&mut self, codec_data: &gst::Buffer) {
212        unsafe {
213            let prev = (*self.as_mut_ptr()).codec_data;
214
215            if !prev.is_null() {
216                gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
217            }
218
219            ptr::write(
220                &mut (*self.as_mut_ptr()).codec_data,
221                gst::ffi::gst_mini_object_ref(codec_data.as_mut_ptr() as *mut _) as *mut _,
222            );
223        }
224    }
225
226    #[inline]
227    pub fn set_allocation_caps(&mut self, allocation_caps: &gst::Caps) {
228        unsafe {
229            let prev = (*self.as_mut_ptr()).allocation_caps;
230
231            if !prev.is_null() {
232                gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
233            }
234
235            ptr::write(
236                &mut (*self.as_mut_ptr()).allocation_caps,
237                gst::ffi::gst_mini_object_ref(allocation_caps.as_mut_ptr() as *mut _) as *mut _,
238            );
239        }
240    }
241}
242
243impl Clone for VideoCodecState<'_, Readable> {
244    #[inline]
245    fn clone(&self) -> Self {
246        unsafe {
247            let state = ffi::gst_video_codec_state_ref(self.state);
248            Self::new(state)
249        }
250    }
251}
252
253unsafe impl Send for VideoCodecState<'_, Readable> {}
254unsafe impl Sync for VideoCodecState<'_, Readable> {}