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