gstreamer_video/
video_encoder.rs

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