1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::{mem, ptr}; |
4 | |
5 | use glib::{prelude::*, translate::*}; |
6 | |
7 | use crate::{ |
8 | ffi, |
9 | utils::HasStreamLock, |
10 | video_codec_state::{InNegotiation, Readable, VideoCodecState, VideoCodecStateContext}, |
11 | VideoCodecFrame, VideoEncoder, |
12 | }; |
13 | mod sealed { |
14 | pub trait Sealed {} |
15 | impl<T: super::IsA<super::VideoEncoder>> Sealed for T {} |
16 | } |
17 | |
18 | pub trait VideoEncoderExtManual: sealed::Sealed + IsA<VideoEncoder> + 'static { |
19 | #[doc (alias = "gst_video_encoder_allocate_output_frame" )] |
20 | fn allocate_output_frame( |
21 | &self, |
22 | frame: &mut VideoCodecFrame, |
23 | size: usize, |
24 | ) -> Result<gst::FlowSuccess, gst::FlowError> { |
25 | unsafe { |
26 | try_from_glib(ffi::gst_video_encoder_allocate_output_frame( |
27 | self.as_ref().to_glib_none().0, |
28 | frame.to_glib_none().0, |
29 | size, |
30 | )) |
31 | } |
32 | } |
33 | |
34 | #[doc (alias = "get_frame" )] |
35 | #[doc (alias = "gst_video_encoder_get_frame" )] |
36 | fn frame(&self, frame_number: i32) -> Option<VideoCodecFrame> { |
37 | let frame = unsafe { |
38 | ffi::gst_video_encoder_get_frame(self.as_ref().to_glib_none().0, frame_number) |
39 | }; |
40 | |
41 | if frame.is_null() { |
42 | None |
43 | } else { |
44 | unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) } |
45 | } |
46 | } |
47 | |
48 | #[doc (alias = "get_frames" )] |
49 | #[doc (alias = "gst_video_encoder_get_frames" )] |
50 | fn frames(&self) -> Vec<VideoCodecFrame> { |
51 | unsafe { |
52 | let frames = ffi::gst_video_encoder_get_frames(self.as_ref().to_glib_none().0); |
53 | let mut iter: *const glib::ffi::GList = frames; |
54 | let mut vec = Vec::new(); |
55 | |
56 | while !iter.is_null() { |
57 | let frame_ptr = Ptr::from((*iter).data); |
58 | /* transfer ownership of the frame */ |
59 | let frame = VideoCodecFrame::new(frame_ptr, self.as_ref()); |
60 | vec.push(frame); |
61 | iter = (*iter).next; |
62 | } |
63 | |
64 | glib::ffi::g_list_free(frames); |
65 | vec |
66 | } |
67 | } |
68 | |
69 | #[doc (alias = "get_oldest_frame" )] |
70 | #[doc (alias = "gst_video_encoder_get_oldest_frame" )] |
71 | fn oldest_frame(&self) -> Option<VideoCodecFrame> { |
72 | let frame = |
73 | unsafe { ffi::gst_video_encoder_get_oldest_frame(self.as_ref().to_glib_none().0) }; |
74 | |
75 | if frame.is_null() { |
76 | None |
77 | } else { |
78 | unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) } |
79 | } |
80 | } |
81 | |
82 | #[doc (alias = "get_allocator" )] |
83 | #[doc (alias = "gst_video_encoder_get_allocator" )] |
84 | fn allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams) { |
85 | unsafe { |
86 | let mut allocator = ptr::null_mut(); |
87 | let mut params = mem::MaybeUninit::uninit(); |
88 | ffi::gst_video_encoder_get_allocator( |
89 | self.as_ref().to_glib_none().0, |
90 | &mut allocator, |
91 | params.as_mut_ptr(), |
92 | ); |
93 | (from_glib_full(allocator), params.assume_init().into()) |
94 | } |
95 | } |
96 | |
97 | #[cfg (feature = "v1_18" )] |
98 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_18" )))] |
99 | #[doc (alias = "gst_video_encoder_finish_subframe" )] |
100 | fn finish_subframe(&self, frame: &VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError> { |
101 | unsafe { |
102 | try_from_glib(ffi::gst_video_encoder_finish_subframe( |
103 | self.as_ref().to_glib_none().0, |
104 | frame.to_glib_none().0, |
105 | )) |
106 | } |
107 | } |
108 | |
109 | #[doc (alias = "get_latency" )] |
110 | #[doc (alias = "gst_video_encoder_get_latency" )] |
111 | fn latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>) { |
112 | let mut min_latency = gst::ffi::GST_CLOCK_TIME_NONE; |
113 | let mut max_latency = gst::ffi::GST_CLOCK_TIME_NONE; |
114 | |
115 | unsafe { |
116 | ffi::gst_video_encoder_get_latency( |
117 | self.as_ref().to_glib_none().0, |
118 | &mut min_latency, |
119 | &mut max_latency, |
120 | ); |
121 | |
122 | ( |
123 | try_from_glib(min_latency).expect("undefined min_latency" ), |
124 | from_glib(max_latency), |
125 | ) |
126 | } |
127 | } |
128 | |
129 | #[doc (alias = "gst_video_encoder_set_latency" )] |
130 | fn set_latency( |
131 | &self, |
132 | min_latency: gst::ClockTime, |
133 | max_latency: impl Into<Option<gst::ClockTime>>, |
134 | ) { |
135 | unsafe { |
136 | ffi::gst_video_encoder_set_latency( |
137 | self.as_ref().to_glib_none().0, |
138 | min_latency.into_glib(), |
139 | max_latency.into().into_glib(), |
140 | ); |
141 | } |
142 | } |
143 | #[doc (alias = "get_output_state" )] |
144 | #[doc (alias = "gst_video_encoder_get_output_state" )] |
145 | fn output_state(&self) -> Option<VideoCodecState<'static, Readable>> { |
146 | let state = |
147 | unsafe { ffi::gst_video_encoder_get_output_state(self.as_ref().to_glib_none().0) }; |
148 | |
149 | if state.is_null() { |
150 | None |
151 | } else { |
152 | unsafe { Some(VideoCodecState::<Readable>::new(state)) } |
153 | } |
154 | } |
155 | |
156 | #[doc (alias = "gst_video_encoder_set_output_state" )] |
157 | fn set_output_state( |
158 | &self, |
159 | caps: gst::Caps, |
160 | reference: Option<&VideoCodecState<Readable>>, |
161 | ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError> { |
162 | let state = unsafe { |
163 | let reference = match reference { |
164 | Some(reference) => reference.as_mut_ptr(), |
165 | None => ptr::null_mut(), |
166 | }; |
167 | ffi::gst_video_encoder_set_output_state( |
168 | self.as_ref().to_glib_none().0, |
169 | caps.into_glib_ptr(), |
170 | reference, |
171 | ) |
172 | }; |
173 | |
174 | if state.is_null() { |
175 | Err(gst::FlowError::NotNegotiated) |
176 | } else { |
177 | unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) } |
178 | } |
179 | } |
180 | |
181 | #[doc (alias = "gst_video_encoder_negotiate" )] |
182 | fn negotiate<'a>( |
183 | &'a self, |
184 | output_state: VideoCodecState<'a, InNegotiation<'a>>, |
185 | ) -> Result<(), gst::FlowError> { |
186 | // Consume output_state so user won't be able to modify it anymore |
187 | let self_ptr = self.to_glib_none().0 as *const gst::ffi::GstElement; |
188 | assert_eq!(output_state.context.element_as_ptr(), self_ptr); |
189 | |
190 | let ret = unsafe { |
191 | from_glib(ffi::gst_video_encoder_negotiate( |
192 | self.as_ref().to_glib_none().0, |
193 | )) |
194 | }; |
195 | if ret { |
196 | Ok(()) |
197 | } else { |
198 | Err(gst::FlowError::NotNegotiated) |
199 | } |
200 | } |
201 | |
202 | #[doc (alias = "gst_video_encoder_set_headers" )] |
203 | fn set_headers(&self, headers: impl IntoIterator<Item = gst::Buffer>) { |
204 | unsafe { |
205 | ffi::gst_video_encoder_set_headers( |
206 | self.as_ref().to_glib_none().0, |
207 | headers |
208 | .into_iter() |
209 | .collect::<glib::List<_>>() |
210 | .into_glib_ptr(), |
211 | ); |
212 | } |
213 | } |
214 | |
215 | fn sink_pad(&self) -> &gst::Pad { |
216 | unsafe { |
217 | let elt = &*(self.as_ptr() as *const ffi::GstVideoEncoder); |
218 | &*(&elt.sinkpad as *const *mut gst::ffi::GstPad as *const gst::Pad) |
219 | } |
220 | } |
221 | |
222 | fn src_pad(&self) -> &gst::Pad { |
223 | unsafe { |
224 | let elt = &*(self.as_ptr() as *const ffi::GstVideoEncoder); |
225 | &*(&elt.srcpad as *const *mut gst::ffi::GstPad as *const gst::Pad) |
226 | } |
227 | } |
228 | |
229 | fn input_segment(&self) -> gst::Segment { |
230 | unsafe { |
231 | let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _); |
232 | glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock)); |
233 | let segment = ptr.input_segment; |
234 | glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock)); |
235 | from_glib_none(&segment as *const gst::ffi::GstSegment) |
236 | } |
237 | } |
238 | |
239 | fn output_segment(&self) -> gst::Segment { |
240 | unsafe { |
241 | let ptr: &ffi::GstVideoDecoder = &*(self.as_ptr() as *const _); |
242 | glib::ffi::g_rec_mutex_lock(mut_override(&ptr.stream_lock)); |
243 | let segment = ptr.output_segment; |
244 | glib::ffi::g_rec_mutex_unlock(mut_override(&ptr.stream_lock)); |
245 | from_glib_none(&segment as *const gst::ffi::GstSegment) |
246 | } |
247 | } |
248 | } |
249 | |
250 | impl<O: IsA<VideoEncoder>> VideoEncoderExtManual for O {} |
251 | |
252 | impl HasStreamLock for VideoEncoder { |
253 | fn stream_lock(&self) -> *mut glib::ffi::GRecMutex { |
254 | let encoder_sys: *const ffi::GstVideoEncoder = self.to_glib_none().0; |
255 | unsafe { mut_override(&(*encoder_sys).stream_lock) } |
256 | } |
257 | |
258 | fn element_as_ptr(&self) -> *const gst::ffi::GstElement { |
259 | self.as_ptr() as *const gst::ffi::GstElement |
260 | } |
261 | } |
262 | |