1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::{fmt, marker::PhantomData, ptr}; |
4 | |
5 | use glib::translate::*; |
6 | |
7 | use crate::{ffi, utils::HasStreamLock, video_info::VideoInfo}; |
8 | |
9 | pub 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 | |
16 | pub 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 | } |
21 | pub struct Readable {} |
22 | |
23 | impl<'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 | |
35 | impl<'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 | pub struct VideoCodecState<'a, T: VideoCodecStateContext<'a>> { |
48 | state: *mut ffi::GstVideoCodecState, |
49 | pub(crate) context: T, |
50 | phantom: PhantomData<&'a T>, |
51 | } |
52 | |
53 | impl<'a, T: VideoCodecStateContext<'a>> fmt::Debug for VideoCodecState<'a, T> { |
54 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
55 | f&mut DebugStruct<'_, '_>.debug_struct("VideoCodecState" ) |
56 | .field("info" , &self.info()) |
57 | .field("caps" , &self.caps()) |
58 | .field("codec_data" , &self.codec_data()) |
59 | .field(name:"allocation_caps" , &self.allocation_caps()) |
60 | .finish() |
61 | } |
62 | } |
63 | |
64 | impl 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 | |
77 | impl<'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: *mut GRecMutex = element.stream_lock(); |
86 | glib::ffi::g_rec_mutex_lock(rec_mutex:stream_lock); |
87 | Self { |
88 | state, |
89 | context: InNegotiation { element }, |
90 | phantom: PhantomData, |
91 | } |
92 | } |
93 | } |
94 | |
95 | impl<'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 | |
171 | impl<'a, T: VideoCodecStateContext<'a>> Drop for VideoCodecState<'a, T> { |
172 | #[inline ] |
173 | fn drop(&mut self) { |
174 | unsafe { |
175 | if let Some(element: &'a dyn HasStreamLock) = self.context.element() { |
176 | let stream_lock: *mut GRecMutex = element.stream_lock(); |
177 | glib::ffi::g_rec_mutex_unlock(rec_mutex:stream_lock); |
178 | } |
179 | ffi::gst_video_codec_state_unref(self.state); |
180 | } |
181 | } |
182 | } |
183 | |
184 | impl<'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 | |
241 | impl Clone for VideoCodecState<'_, Readable> { |
242 | #[inline ] |
243 | fn clone(&self) -> Self { |
244 | unsafe { |
245 | let state: *mut GstVideoCodecState = ffi::gst_video_codec_state_ref(self.state); |
246 | Self::new(state) |
247 | } |
248 | } |
249 | } |
250 | |
251 | unsafe impl Send for VideoCodecState<'_, Readable> {} |
252 | unsafe impl Sync for VideoCodecState<'_, Readable> {} |
253 | |