1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{mem, ptr};
4
5use glib::{prelude::*, translate::*};
6
7use crate::{
8 ffi,
9 utils::HasStreamLock,
10 video_codec_state::{InNegotiation, Readable, VideoCodecState, VideoCodecStateContext},
11 VideoCodecFrame, VideoEncoder,
12};
13mod sealed {
14 pub trait Sealed {}
15 impl<T: super::IsA<super::VideoEncoder>> Sealed for T {}
16}
17
18pub 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
250impl<O: IsA<VideoEncoder>> VideoEncoderExtManual for O {}
251
252impl 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