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};
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}