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