Skip to main content

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