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::{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&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
64impl<'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
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: *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
95impl<'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
172impl<'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
185impl<'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
242impl<'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
252unsafe impl<'a> Send for VideoCodecState<'a, Readable> {}
253unsafe impl<'a> Sync for VideoCodecState<'a, Readable> {}
254