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&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 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: *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 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: &'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
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: *mut GstVideoCodecState = 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> {}
253