gstreamer_video/
video_overlay_composition.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, mem};
4
5use crate::ffi;
6use glib::translate::*;
7
8gst::mini_object_wrapper!(
9    VideoOverlayRectangle,
10    VideoOverlayRectangleRef,
11    ffi::GstVideoOverlayRectangle,
12    || ffi::gst_video_overlay_rectangle_get_type()
13);
14
15impl fmt::Debug for VideoOverlayRectangle {
16    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17        VideoOverlayRectangleRef::fmt(self, f)
18    }
19}
20
21impl fmt::Debug for VideoOverlayRectangleRef {
22    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23        f.debug_struct("VideoOverlayRectangle")
24            .field("flags", &self.flags())
25            .field("global_alpha", &self.global_alpha())
26            .field("render_rectangle", &self.render_rectangle())
27            .finish()
28    }
29}
30
31impl VideoOverlayRectangle {
32    #[doc(alias = "gst_video_overlay_rectangle_new_raw")]
33    pub fn new_raw(
34        buffer: &gst::Buffer,
35        render_x: i32,
36        render_y: i32,
37        render_width: u32,
38        render_height: u32,
39        flags: crate::VideoOverlayFormatFlags,
40    ) -> Self {
41        skip_assert_initialized!();
42        assert!(buffer.meta::<crate::VideoMeta>().is_some());
43        unsafe {
44            from_glib_full(ffi::gst_video_overlay_rectangle_new_raw(
45                buffer.to_glib_none().0,
46                render_x,
47                render_y,
48                render_width,
49                render_height,
50                flags.into_glib(),
51            ))
52        }
53    }
54}
55
56impl VideoOverlayRectangleRef {
57    #[doc(alias = "get_flags")]
58    #[doc(alias = "gst_video_overlay_rectangle_get_flags")]
59    pub fn flags(&self) -> crate::VideoOverlayFormatFlags {
60        unsafe {
61            from_glib(ffi::gst_video_overlay_rectangle_get_flags(
62                self.as_mut_ptr(),
63            ))
64        }
65    }
66
67    #[doc(alias = "get_global_alpha")]
68    #[doc(alias = "gst_video_overlay_rectangle_get_global_alpha")]
69    pub fn global_alpha(&self) -> f32 {
70        unsafe { ffi::gst_video_overlay_rectangle_get_global_alpha(self.as_mut_ptr()) }
71    }
72
73    #[doc(alias = "gst_video_overlay_rectangle_set_global_alpha")]
74    pub fn set_global_alpha(&mut self, alpha: f32) {
75        unsafe { ffi::gst_video_overlay_rectangle_set_global_alpha(self.as_mut_ptr(), alpha) }
76    }
77
78    #[doc(alias = "get_seqnum")]
79    #[doc(alias = "gst_video_overlay_rectangle_get_seqnum")]
80    pub fn seqnum(&self) -> u32 {
81        unsafe { ffi::gst_video_overlay_rectangle_get_seqnum(self.as_mut_ptr()) }
82    }
83
84    #[doc(alias = "get_render_rectangle")]
85    #[doc(alias = "gst_video_overlay_rectangle_get_render_rectangle")]
86    pub fn render_rectangle(&self) -> (i32, i32, u32, u32) {
87        unsafe {
88            let mut render_x = mem::MaybeUninit::uninit();
89            let mut render_y = mem::MaybeUninit::uninit();
90            let mut render_width = mem::MaybeUninit::uninit();
91            let mut render_height = mem::MaybeUninit::uninit();
92
93            ffi::gst_video_overlay_rectangle_get_render_rectangle(
94                self.as_mut_ptr(),
95                render_x.as_mut_ptr(),
96                render_y.as_mut_ptr(),
97                render_width.as_mut_ptr(),
98                render_height.as_mut_ptr(),
99            );
100
101            (
102                render_x.assume_init(),
103                render_y.assume_init(),
104                render_width.assume_init(),
105                render_height.assume_init(),
106            )
107        }
108    }
109
110    #[doc(alias = "gst_video_overlay_rectangle_set_render_rectangle")]
111    pub fn set_render_rectangle(
112        &mut self,
113        render_x: i32,
114        render_y: i32,
115        render_width: u32,
116        render_height: u32,
117    ) {
118        unsafe {
119            ffi::gst_video_overlay_rectangle_set_render_rectangle(
120                self.as_mut_ptr(),
121                render_x,
122                render_y,
123                render_width,
124                render_height,
125            )
126        }
127    }
128
129    #[doc(alias = "get_pixels_unscaled_raw")]
130    #[doc(alias = "gst_video_overlay_rectangle_get_pixels_unscaled_raw")]
131    pub fn pixels_unscaled_raw(&self, flags: crate::VideoOverlayFormatFlags) -> gst::Buffer {
132        unsafe {
133            from_glib_none(ffi::gst_video_overlay_rectangle_get_pixels_unscaled_raw(
134                self.as_mut_ptr(),
135                flags.into_glib(),
136            ))
137        }
138    }
139
140    #[doc(alias = "get_pixels_unscaled_ayuv")]
141    #[doc(alias = "gst_video_overlay_rectangle_get_pixels_unscaled_ayuv")]
142    pub fn pixels_unscaled_ayuv(&self, flags: crate::VideoOverlayFormatFlags) -> gst::Buffer {
143        unsafe {
144            from_glib_none(ffi::gst_video_overlay_rectangle_get_pixels_unscaled_ayuv(
145                self.as_mut_ptr(),
146                flags.into_glib(),
147            ))
148        }
149    }
150
151    #[doc(alias = "get_pixels_unscaled_argb")]
152    #[doc(alias = "gst_video_overlay_rectangle_get_pixels_unscaled_argb")]
153    pub fn pixels_unscaled_argb(&self, flags: crate::VideoOverlayFormatFlags) -> gst::Buffer {
154        unsafe {
155            from_glib_none(ffi::gst_video_overlay_rectangle_get_pixels_unscaled_argb(
156                self.as_mut_ptr(),
157                flags.into_glib(),
158            ))
159        }
160    }
161
162    #[doc(alias = "get_pixels_raw")]
163    #[doc(alias = "gst_video_overlay_rectangle_get_pixels_raw")]
164    pub fn pixels_raw(&self, flags: crate::VideoOverlayFormatFlags) -> gst::Buffer {
165        unsafe {
166            from_glib_none(ffi::gst_video_overlay_rectangle_get_pixels_raw(
167                self.as_mut_ptr(),
168                flags.into_glib(),
169            ))
170        }
171    }
172
173    #[doc(alias = "get_pixels_ayuv")]
174    #[doc(alias = "gst_video_overlay_rectangle_get_pixels_ayuv")]
175    pub fn pixels_ayuv(&self, flags: crate::VideoOverlayFormatFlags) -> gst::Buffer {
176        unsafe {
177            from_glib_none(ffi::gst_video_overlay_rectangle_get_pixels_ayuv(
178                self.as_mut_ptr(),
179                flags.into_glib(),
180            ))
181        }
182    }
183
184    #[doc(alias = "get_pixels_argb")]
185    #[doc(alias = "gst_video_overlay_rectangle_get_pixels_argb")]
186    pub fn pixels_argb(&self, flags: crate::VideoOverlayFormatFlags) -> gst::Buffer {
187        unsafe {
188            from_glib_none(ffi::gst_video_overlay_rectangle_get_pixels_argb(
189                self.as_mut_ptr(),
190                flags.into_glib(),
191            ))
192        }
193    }
194}
195
196gst::mini_object_wrapper!(
197    VideoOverlayComposition,
198    VideoOverlayCompositionRef,
199    ffi::GstVideoOverlayComposition,
200    || ffi::gst_video_overlay_composition_get_type()
201);
202
203impl fmt::Debug for VideoOverlayComposition {
204    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205        VideoOverlayCompositionRef::fmt(self, f)
206    }
207}
208
209impl fmt::Debug for VideoOverlayCompositionRef {
210    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
211        f.debug_struct("VideoOverlayComposition").finish()
212    }
213}
214
215impl VideoOverlayComposition {
216    #[doc(alias = "gst_video_overlay_composition_new")]
217    pub fn new<'a>(
218        rects: impl IntoIterator<Item = &'a VideoOverlayRectangle>,
219    ) -> Result<Self, glib::error::BoolError> {
220        assert_initialized_main_thread!();
221
222        #[cfg(feature = "v1_20")]
223        unsafe {
224            use std::ptr;
225
226            let composition =
227                Self::from_glib_full(ffi::gst_video_overlay_composition_new(ptr::null_mut()));
228
229            rects.into_iter().for_each(|rect| {
230                ffi::gst_video_overlay_composition_add_rectangle(
231                    composition.as_mut_ptr(),
232                    rect.as_mut_ptr(),
233                );
234            });
235
236            Ok(composition)
237        }
238        #[cfg(not(feature = "v1_20"))]
239        unsafe {
240            let mut iter = rects.into_iter();
241
242            let first = match iter.next() {
243                None => {
244                    return Err(glib::bool_error!(
245                        "Failed to create VideoOverlayComposition"
246                    ))
247                }
248                Some(first) => first,
249            };
250
251            let composition =
252                Self::from_glib_full(ffi::gst_video_overlay_composition_new(first.as_mut_ptr()));
253
254            for rect in iter {
255                ffi::gst_video_overlay_composition_add_rectangle(
256                    composition.as_mut_ptr(),
257                    rect.as_mut_ptr(),
258                );
259            }
260
261            Ok(composition)
262        }
263    }
264}
265
266#[cfg(feature = "v1_20")]
267impl Default for VideoOverlayComposition {
268    fn default() -> Self {
269        assert_initialized_main_thread!();
270
271        use std::ptr;
272
273        unsafe { from_glib_full(ffi::gst_video_overlay_composition_new(ptr::null_mut())) }
274    }
275}
276
277impl VideoOverlayCompositionRef {
278    #[doc(alias = "gst_video_overlay_composition_n_rectangles")]
279    pub fn n_rectangles(&self) -> u32 {
280        unsafe { ffi::gst_video_overlay_composition_n_rectangles(self.as_mut_ptr()) }
281    }
282
283    #[doc(alias = "get_rectangle")]
284    #[doc(alias = "gst_video_overlay_composition_get_rectangle")]
285    pub fn rectangle(&self, idx: u32) -> Result<VideoOverlayRectangle, glib::error::BoolError> {
286        if idx >= self.n_rectangles() {
287            return Err(glib::bool_error!("Invalid index"));
288        }
289
290        unsafe {
291            match from_glib_none(ffi::gst_video_overlay_composition_get_rectangle(
292                self.as_mut_ptr(),
293                idx,
294            )) {
295                Some(r) => Ok(r),
296                None => Err(glib::bool_error!("Failed to get rectangle")),
297            }
298        }
299    }
300
301    #[doc(alias = "gst_video_overlay_composition_add_rectangle")]
302    pub fn add_rectangle(&mut self, rect: &VideoOverlayRectangleRef) {
303        unsafe {
304            ffi::gst_video_overlay_composition_add_rectangle(self.as_mut_ptr(), rect.as_mut_ptr());
305        }
306    }
307
308    #[doc(alias = "get_seqnum")]
309    #[doc(alias = "gst_video_overlay_composition_get_seqnum")]
310    pub fn seqnum(&self) -> u32 {
311        unsafe { ffi::gst_video_overlay_composition_get_seqnum(self.as_mut_ptr()) }
312    }
313
314    #[doc(alias = "gst_video_overlay_composition_blend")]
315    pub fn blend(
316        &self,
317        frame: &mut crate::VideoFrameRef<&mut gst::BufferRef>,
318    ) -> Result<(), glib::BoolError> {
319        unsafe {
320            glib::result_from_gboolean!(
321                ffi::gst_video_overlay_composition_blend(self.as_mut_ptr(), frame.as_mut_ptr()),
322                "Failed to blend overlay composition",
323            )
324        }
325    }
326
327    pub fn iter(&self) -> Iter {
328        Iter {
329            composition: self,
330            idx: 0,
331            len: self.n_rectangles() as usize,
332        }
333    }
334}
335
336impl<'a> IntoIterator for &'a VideoOverlayComposition {
337    type IntoIter = Iter<'a>;
338    type Item = VideoOverlayRectangle;
339
340    fn into_iter(self) -> Self::IntoIter {
341        self.iter()
342    }
343}
344
345impl From<VideoOverlayRectangle> for VideoOverlayComposition {
346    fn from(value: VideoOverlayRectangle) -> Self {
347        skip_assert_initialized!();
348
349        unsafe {
350            Self::from_glib_full(ffi::gst_video_overlay_composition_new(
351                value.into_glib_ptr(),
352            ))
353        }
354    }
355}
356
357impl<'a> From<&'a VideoOverlayRectangle> for VideoOverlayComposition {
358    fn from(value: &'a VideoOverlayRectangle) -> Self {
359        skip_assert_initialized!();
360
361        unsafe { Self::from_glib_full(ffi::gst_video_overlay_composition_new(value.as_mut_ptr())) }
362    }
363}
364
365#[cfg(feature = "v1_20")]
366impl<const N: usize> From<[VideoOverlayRectangle; N]> for VideoOverlayComposition {
367    fn from(value: [VideoOverlayRectangle; N]) -> Self {
368        assert_initialized_main_thread!();
369
370        unsafe {
371            use std::ptr;
372
373            let composition =
374                Self::from_glib_full(ffi::gst_video_overlay_composition_new(ptr::null_mut()));
375
376            value.into_iter().for_each(|rect| {
377                ffi::gst_video_overlay_composition_add_rectangle(
378                    composition.as_mut_ptr(),
379                    rect.into_glib_ptr(),
380                );
381            });
382
383            composition
384        }
385    }
386}
387
388#[cfg(feature = "v1_20")]
389impl<'a, const N: usize> From<[&'a VideoOverlayRectangle; N]> for VideoOverlayComposition {
390    fn from(value: [&'a VideoOverlayRectangle; N]) -> Self {
391        assert_initialized_main_thread!();
392
393        unsafe {
394            use std::ptr;
395
396            let composition =
397                Self::from_glib_full(ffi::gst_video_overlay_composition_new(ptr::null_mut()));
398
399            value.into_iter().for_each(|rect| {
400                ffi::gst_video_overlay_composition_add_rectangle(
401                    composition.as_mut_ptr(),
402                    rect.as_mut_ptr(),
403                );
404            });
405
406            composition
407        }
408    }
409}
410
411#[cfg(feature = "v1_20")]
412impl std::iter::FromIterator<VideoOverlayRectangle> for VideoOverlayComposition {
413    fn from_iter<T: IntoIterator<Item = VideoOverlayRectangle>>(iter: T) -> Self {
414        assert_initialized_main_thread!();
415
416        unsafe {
417            use std::ptr;
418
419            let composition =
420                Self::from_glib_full(ffi::gst_video_overlay_composition_new(ptr::null_mut()));
421
422            iter.into_iter().for_each(|rect| {
423                ffi::gst_video_overlay_composition_add_rectangle(
424                    composition.as_mut_ptr(),
425                    rect.into_glib_ptr(),
426                );
427            });
428
429            composition
430        }
431    }
432}
433
434#[cfg(feature = "v1_20")]
435impl<'a> std::iter::FromIterator<&'a VideoOverlayRectangle> for VideoOverlayComposition {
436    fn from_iter<T: IntoIterator<Item = &'a VideoOverlayRectangle>>(iter: T) -> Self {
437        assert_initialized_main_thread!();
438
439        unsafe {
440            use std::ptr;
441
442            let composition =
443                Self::from_glib_full(ffi::gst_video_overlay_composition_new(ptr::null_mut()));
444
445            iter.into_iter().for_each(|rect| {
446                ffi::gst_video_overlay_composition_add_rectangle(
447                    composition.as_mut_ptr(),
448                    rect.as_mut_ptr(),
449                );
450            });
451
452            composition
453        }
454    }
455}
456
457#[must_use = "iterators are lazy and do nothing unless consumed"]
458pub struct Iter<'a> {
459    composition: &'a VideoOverlayCompositionRef,
460    idx: usize,
461    len: usize,
462}
463
464impl Iterator for Iter<'_> {
465    type Item = VideoOverlayRectangle;
466
467    fn next(&mut self) -> Option<Self::Item> {
468        if self.idx >= self.len {
469            return None;
470        }
471
472        let rect = self.composition.rectangle(self.idx as u32).unwrap();
473        self.idx += 1;
474
475        Some(rect)
476    }
477
478    fn size_hint(&self) -> (usize, Option<usize>) {
479        let remaining = self.len - self.idx;
480
481        (remaining, Some(remaining))
482    }
483
484    fn count(self) -> usize {
485        self.len - self.idx
486    }
487
488    fn nth(&mut self, n: usize) -> Option<Self::Item> {
489        let (end, overflow) = self.idx.overflowing_add(n);
490        if end >= self.len || overflow {
491            self.idx = self.len;
492            None
493        } else {
494            self.idx = end + 1;
495            Some(self.composition.rectangle(end as u32).unwrap())
496        }
497    }
498
499    fn last(self) -> Option<Self::Item> {
500        if self.idx == self.len {
501            None
502        } else {
503            Some(self.composition.rectangle(self.len as u32 - 1).unwrap())
504        }
505    }
506}
507
508impl DoubleEndedIterator for Iter<'_> {
509    fn next_back(&mut self) -> Option<Self::Item> {
510        if self.idx == self.len {
511            return None;
512        }
513
514        self.len -= 1;
515
516        Some(self.composition.rectangle(self.len as u32).unwrap())
517    }
518
519    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
520        let (end, overflow) = self.len.overflowing_sub(n);
521        if end <= self.idx || overflow {
522            self.idx = self.len;
523            None
524        } else {
525            self.len = end - 1;
526            Some(self.composition.rectangle(self.len as u32).unwrap())
527        }
528    }
529}
530
531impl ExactSizeIterator for Iter<'_> {}
532
533impl std::iter::FusedIterator for Iter<'_> {}