1use std::{fmt, marker::PhantomData, mem, ptr, str};
4
5use crate::ffi;
6use glib::translate::*;
7use gst::prelude::*;
8
9#[doc(alias = "GST_VIDEO_MAX_PLANES")]
10pub const VIDEO_MAX_PLANES: usize = ffi::GST_VIDEO_MAX_PLANES as usize;
11
12#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
15#[non_exhaustive]
16#[doc(alias = "GstVideoColorRange")]
17pub enum VideoColorRange {
18 #[doc(alias = "GST_VIDEO_COLOR_RANGE_UNKNOWN")]
20 Unknown,
21 #[doc(alias = "GST_VIDEO_COLOR_RANGE_0_255")]
22 Range0_255,
23 #[doc(alias = "GST_VIDEO_COLOR_RANGE_16_235")]
24 Range16_235,
25 #[doc(hidden)]
26 __Unknown(i32),
27}
28
29#[doc(hidden)]
30impl IntoGlib for VideoColorRange {
31 type GlibType = ffi::GstVideoColorRange;
32
33 #[inline]
34 fn into_glib(self) -> ffi::GstVideoColorRange {
35 match self {
36 Self::Unknown => ffi::GST_VIDEO_COLOR_RANGE_UNKNOWN,
37 Self::Range0_255 => ffi::GST_VIDEO_COLOR_RANGE_0_255,
38 Self::Range16_235 => ffi::GST_VIDEO_COLOR_RANGE_16_235,
39 Self::__Unknown(value) => value,
40 }
41 }
42}
43
44#[doc(hidden)]
45impl FromGlib<ffi::GstVideoColorRange> for VideoColorRange {
46 #[inline]
47 unsafe fn from_glib(value: ffi::GstVideoColorRange) -> Self {
48 skip_assert_initialized!();
49 match value {
50 0 => Self::Unknown,
51 1 => Self::Range0_255,
52 2 => Self::Range16_235,
53 value => Self::__Unknown(value),
54 }
55 }
56}
57
58impl StaticType for VideoColorRange {
59 #[inline]
60 fn static_type() -> glib::Type {
61 unsafe { from_glib(ffi::gst_video_color_range_get_type()) }
62 }
63}
64
65impl glib::value::ValueType for VideoColorRange {
66 type Type = Self;
67}
68
69unsafe impl<'a> glib::value::FromValue<'a> for VideoColorRange {
70 type Checker = glib::value::GenericValueTypeChecker<Self>;
71
72 unsafe fn from_value(value: &'a glib::Value) -> Self {
73 skip_assert_initialized!();
74 from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0))
75 }
76}
77
78impl ToValue for VideoColorRange {
79 fn to_value(&self) -> glib::Value {
80 let mut value = glib::Value::for_value_type::<Self>();
81 unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()) }
82 value
83 }
84
85 fn value_type(&self) -> glib::Type {
86 Self::static_type()
87 }
88}
89
90impl From<VideoColorRange> for glib::Value {
91 fn from(v: VideoColorRange) -> glib::Value {
92 skip_assert_initialized!();
93 glib::value::ToValue::to_value(&v)
94 }
95}
96
97#[doc(alias = "GstVideoColorimetry")]
99#[derive(Copy, Clone)]
100#[repr(transparent)]
101pub struct VideoColorimetry(ffi::GstVideoColorimetry);
102
103impl VideoColorimetry {
104 pub fn new(
105 range: crate::VideoColorRange,
106 matrix: crate::VideoColorMatrix,
107 transfer: crate::VideoTransferFunction,
108 primaries: crate::VideoColorPrimaries,
109 ) -> Self {
110 skip_assert_initialized!();
111
112 let colorimetry = ffi::GstVideoColorimetry {
113 range: range.into_glib(),
114 matrix: matrix.into_glib(),
115 transfer: transfer.into_glib(),
116 primaries: primaries.into_glib(),
117 };
118
119 Self(colorimetry)
120 }
121
122 #[inline]
123 pub fn range(&self) -> crate::VideoColorRange {
124 unsafe { from_glib(self.0.range) }
125 }
126
127 #[inline]
128 pub fn matrix(&self) -> crate::VideoColorMatrix {
129 unsafe { from_glib(self.0.matrix) }
130 }
131
132 #[inline]
133 pub fn transfer(&self) -> crate::VideoTransferFunction {
134 unsafe { from_glib(self.0.transfer) }
135 }
136
137 #[inline]
138 pub fn primaries(&self) -> crate::VideoColorPrimaries {
139 unsafe { from_glib(self.0.primaries) }
140 }
141
142 #[cfg(feature = "v1_22")]
154 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
155 #[doc(alias = "gst_video_colorimetry_is_equivalent")]
156 pub fn is_equivalent(&self, bitdepth: u32, other: &Self, other_bitdepth: u32) -> bool {
157 unsafe {
158 from_glib(ffi::gst_video_colorimetry_is_equivalent(
159 &self.0,
160 bitdepth,
161 &other.0,
162 other_bitdepth,
163 ))
164 }
165 }
166}
167
168impl PartialEq for VideoColorimetry {
169 #[doc(alias = "gst_video_colorimetry_is_equal")]
170 fn eq(&self, other: &Self) -> bool {
171 unsafe { from_glib(ffi::gst_video_colorimetry_is_equal(&self.0, &other.0)) }
172 }
173}
174
175impl Eq for VideoColorimetry {}
176
177impl str::FromStr for crate::VideoColorimetry {
178 type Err = glib::error::BoolError;
179
180 #[doc(alias = "gst_video_colorimetry_from_string")]
181 fn from_str(s: &str) -> Result<Self, Self::Err> {
182 assert_initialized_main_thread!();
183
184 unsafe {
185 let mut colorimetry = mem::MaybeUninit::uninit();
186 let valid: bool = from_glib(ffi::gst_video_colorimetry_from_string(
187 colorimetry.as_mut_ptr(),
188 s.to_glib_none().0,
189 ));
190 if valid {
191 Ok(Self(colorimetry.assume_init()))
192 } else {
193 Err(glib::bool_error!("Invalid colorimetry info"))
194 }
195 }
196 }
197}
198
199impl fmt::Debug for crate::VideoColorimetry {
200 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201 f.debug_struct("VideoColorimetry")
202 .field("range", &self.0.range)
203 .field("matrix", &self.0.matrix)
204 .field("transfer", &self.0.transfer)
205 .field("primaries", &self.0.primaries)
206 .finish()
207 }
208}
209
210impl fmt::Display for crate::VideoColorimetry {
211 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212 let s =
213 unsafe { glib::GString::from_glib_full(ffi::gst_video_colorimetry_to_string(&self.0)) };
214 f.write_str(&s)
215 }
216}
217
218impl crate::VideoChromaSite {
219 #[doc(alias = "gst_video_chroma_site_to_string")]
220 #[doc(alias = "gst_video_chroma_to_string")]
221 pub fn to_str(self) -> glib::GString {
222 assert_initialized_main_thread!();
223
224 unsafe {
225 cfg_if::cfg_if! {
226 if #[cfg(feature = "v1_20")] {
227 from_glib_full(ffi::gst_video_chroma_site_to_string(self.into_glib()))
228 } else {
229 from_glib_none(ffi::gst_video_chroma_to_string(self.into_glib()))
230 }
231 }
232 }
233 }
234}
235
236impl str::FromStr for crate::VideoChromaSite {
237 type Err = glib::error::BoolError;
238
239 #[doc(alias = "gst_video_chroma_from_string")]
240 fn from_str(s: &str) -> Result<Self, Self::Err> {
241 skip_assert_initialized!();
242
243 cfg_if::cfg_if! {
244 if #[cfg(feature = "v1_20")] {
245 let chroma_site = Self::from_string(s);
246 } else {
247 assert_initialized_main_thread!();
248 let chroma_site: Self =
249 unsafe { from_glib(ffi::gst_video_chroma_from_string(s.to_glib_none().0)) };
250 }
251 };
252
253 if chroma_site.is_empty() {
254 Err(glib::bool_error!("Invalid chroma site"))
255 } else {
256 Ok(chroma_site)
257 }
258 }
259}
260
261impl From<crate::VideoMultiviewFramePacking> for crate::VideoMultiviewMode {
262 #[inline]
263 fn from(v: crate::VideoMultiviewFramePacking) -> Self {
264 skip_assert_initialized!();
265 unsafe { from_glib(v.into_glib()) }
266 }
267}
268
269impl TryFrom<crate::VideoMultiviewMode> for crate::VideoMultiviewFramePacking {
270 type Error = glib::BoolError;
271
272 fn try_from(v: crate::VideoMultiviewMode) -> Result<Self, glib::BoolError> {
273 skip_assert_initialized!();
274
275 let v2 = unsafe { from_glib(v.into_glib()) };
276
277 if let Self::__Unknown(_) = v2 {
278 Err(glib::bool_error!("Invalid frame packing mode"))
279 } else {
280 Ok(v2)
281 }
282 }
283}
284
285#[doc(alias = "GstVideoInfo")]
292#[derive(Clone)]
293#[repr(transparent)]
294pub struct VideoInfo(pub(crate) ffi::GstVideoInfo);
295
296impl fmt::Debug for VideoInfo {
297 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
298 f.debug_struct("VideoInfo")
299 .field("format", &self.format())
300 .field("format-info", &self.format_info())
301 .field("width", &self.width())
302 .field("height", &self.height())
303 .field("interlace_mode", &self.interlace_mode())
304 .field("flags", &self.flags())
305 .field("size", &self.size())
306 .field("views", &self.views())
307 .field("chroma_site", &self.chroma_site())
308 .field("colorimetry", &self.colorimetry())
309 .field("par", &self.par())
310 .field("fps", &self.fps())
311 .field("offset", &self.offset())
312 .field("stride", &self.stride())
313 .field("multiview_mode", &self.multiview_mode())
314 .field("multiview_flags", &self.multiview_flags())
315 .field("field_order", &self.field_order())
316 .finish()
317 }
318}
319
320#[derive(Debug)]
321#[must_use = "The builder must be built to be used"]
322pub struct VideoInfoBuilder<'a> {
323 format: crate::VideoFormat,
324 width: u32,
325 height: u32,
326 interlace_mode: Option<crate::VideoInterlaceMode>,
327 flags: Option<crate::VideoFlags>,
328 size: Option<usize>,
329 views: Option<u32>,
330 chroma_site: Option<crate::VideoChromaSite>,
331 colorimetry: Option<&'a crate::VideoColorimetry>,
332 par: Option<gst::Fraction>,
333 fps: Option<gst::Fraction>,
334 offset: Option<&'a [usize]>,
335 stride: Option<&'a [i32]>,
336 multiview_mode: Option<crate::VideoMultiviewMode>,
337 multiview_flags: Option<crate::VideoMultiviewFlags>,
338 field_order: Option<crate::VideoFieldOrder>,
339}
340
341impl<'a> VideoInfoBuilder<'a> {
342 pub fn build(self) -> Result<VideoInfo, glib::error::BoolError> {
343 unsafe {
344 let mut info = mem::MaybeUninit::uninit();
345
346 cfg_if::cfg_if! {
347 if #[cfg(feature = "v1_16")] {
348 let res: bool = {
349 from_glib(if let Some(interlace_mode) = self.interlace_mode {
350 ffi::gst_video_info_set_interlaced_format(
351 info.as_mut_ptr(),
352 self.format.into_glib(),
353 interlace_mode.into_glib(),
354 self.width,
355 self.height,
356 )
357 } else {
358 ffi::gst_video_info_set_format(
359 info.as_mut_ptr(),
360 self.format.into_glib(),
361 self.width,
362 self.height,
363 )
364 })
365 };
366 } else {
367 let res: bool = {
368 let res = from_glib(ffi::gst_video_info_set_format(
369 info.as_mut_ptr(),
370 self.format.into_glib(),
371 self.width,
372 self.height,
373 ));
374
375 if res {
376 if let Some(interlace_mode) = self.interlace_mode {
377 let info = info.as_mut_ptr();
378 (*info).interlace_mode = interlace_mode.into_glib();
379 }
380 }
381
382 res
383 };
384 }
385 }
386
387 if !res {
388 return Err(glib::bool_error!("Failed to build VideoInfo"));
389 }
390
391 let mut info = info.assume_init();
392
393 if info.finfo.is_null() || info.width <= 0 || info.height <= 0 {
394 return Err(glib::bool_error!("Failed to build VideoInfo"));
395 }
396
397 if let Some(flags) = self.flags {
398 info.flags = flags.into_glib();
399 }
400
401 if let Some(size) = self.size {
402 info.size = size;
403 }
404
405 if let Some(views) = self.views {
406 info.views = views as i32;
407 }
408
409 if let Some(chroma_site) = self.chroma_site {
410 info.chroma_site = chroma_site.into_glib();
411 }
412
413 if let Some(colorimetry) = self.colorimetry {
414 ptr::write(&mut info.colorimetry, ptr::read(&colorimetry.0));
415 }
416
417 if let Some(par) = self.par {
418 info.par_n = par.numer();
419 info.par_d = par.denom();
420 }
421
422 if let Some(fps) = self.fps {
423 info.fps_n = fps.numer();
424 info.fps_d = fps.denom();
425 }
426
427 if let Some(offset) = self.offset {
428 if offset.len() != ((*info.finfo).n_planes as usize) {
429 return Err(glib::bool_error!("Failed to build VideoInfo"));
430 }
431
432 let n_planes = (*info.finfo).n_planes as usize;
433 info.offset[..n_planes].copy_from_slice(&offset[..n_planes]);
434 }
435
436 if let Some(stride) = self.stride {
437 if stride.len() != ((*info.finfo).n_planes as usize) {
438 return Err(glib::bool_error!("Failed to build VideoInfo"));
439 }
440
441 let n_planes = (*info.finfo).n_planes as usize;
442 info.stride[..n_planes].copy_from_slice(&stride[..n_planes]);
443 }
444
445 if let Some(multiview_mode) = self.multiview_mode {
446 let ptr = &mut info.ABI._gst_reserved as *mut _ as *mut i32;
447 ptr::write(ptr.offset(0), multiview_mode.into_glib());
448 }
449
450 if let Some(multiview_flags) = self.multiview_flags {
451 let ptr = &mut info.ABI._gst_reserved as *mut _ as *mut u32;
452 ptr::write(ptr.offset(1), multiview_flags.into_glib());
453 }
454
455 if let Some(field_order) = self.field_order {
456 let ptr = &mut info.ABI._gst_reserved as *mut _ as *mut i32;
457 ptr::write(ptr.offset(2), field_order.into_glib());
458 }
459
460 Ok(VideoInfo(info))
461 }
462 }
463
464 pub fn interlace_mode(self, interlace_mode: crate::VideoInterlaceMode) -> VideoInfoBuilder<'a> {
465 Self {
466 interlace_mode: Some(interlace_mode),
467 ..self
468 }
469 }
470
471 pub fn interlace_mode_if(
472 self,
473 interlace_mode: crate::VideoInterlaceMode,
474 predicate: bool,
475 ) -> VideoInfoBuilder<'a> {
476 if predicate {
477 self.interlace_mode(interlace_mode)
478 } else {
479 self
480 }
481 }
482
483 pub fn interlace_mode_if_some(
484 self,
485 interlace_mode: Option<crate::VideoInterlaceMode>,
486 ) -> VideoInfoBuilder<'a> {
487 if let Some(interlace_mode) = interlace_mode {
488 self.interlace_mode(interlace_mode)
489 } else {
490 self
491 }
492 }
493
494 pub fn flags(self, flags: crate::VideoFlags) -> Self {
495 Self {
496 flags: Some(flags),
497 ..self
498 }
499 }
500
501 pub fn flags_if(self, flags: crate::VideoFlags, predicate: bool) -> Self {
502 if predicate {
503 self.flags(flags)
504 } else {
505 self
506 }
507 }
508
509 pub fn flags_if_some(self, flags: Option<crate::VideoFlags>) -> Self {
510 if let Some(flags) = flags {
511 self.flags(flags)
512 } else {
513 self
514 }
515 }
516
517 pub fn size(self, size: usize) -> Self {
518 Self {
519 size: Some(size),
520 ..self
521 }
522 }
523
524 pub fn size_if(self, size: usize, predicate: bool) -> Self {
525 if predicate {
526 self.size(size)
527 } else {
528 self
529 }
530 }
531
532 pub fn size_if_some(self, size: Option<usize>) -> Self {
533 if let Some(size) = size {
534 self.size(size)
535 } else {
536 self
537 }
538 }
539
540 pub fn views(self, views: u32) -> Self {
541 Self {
542 views: Some(views),
543 ..self
544 }
545 }
546
547 pub fn views_if(self, views: u32, predicate: bool) -> Self {
548 if predicate {
549 self.views(views)
550 } else {
551 self
552 }
553 }
554
555 pub fn views_if_some(self, views: Option<u32>) -> Self {
556 if let Some(views) = views {
557 self.views(views)
558 } else {
559 self
560 }
561 }
562
563 pub fn chroma_site(self, chroma_site: crate::VideoChromaSite) -> Self {
564 Self {
565 chroma_site: Some(chroma_site),
566 ..self
567 }
568 }
569
570 pub fn chroma_site_if(self, chroma_site: crate::VideoChromaSite, predicate: bool) -> Self {
571 if predicate {
572 self.chroma_site(chroma_site)
573 } else {
574 self
575 }
576 }
577
578 pub fn chroma_site_if_some(self, chroma_site: Option<crate::VideoChromaSite>) -> Self {
579 if let Some(chroma_site) = chroma_site {
580 self.chroma_site(chroma_site)
581 } else {
582 self
583 }
584 }
585
586 pub fn colorimetry(self, colorimetry: &'a crate::VideoColorimetry) -> VideoInfoBuilder<'a> {
587 Self {
588 colorimetry: Some(colorimetry),
589 ..self
590 }
591 }
592
593 pub fn colorimetry_if(
594 self,
595 colorimetry: &'a crate::VideoColorimetry,
596 predicate: bool,
597 ) -> VideoInfoBuilder<'a> {
598 if predicate {
599 self.colorimetry(colorimetry)
600 } else {
601 self
602 }
603 }
604
605 pub fn colorimetry_if_some(
606 self,
607 colorimetry: Option<&'a crate::VideoColorimetry>,
608 ) -> VideoInfoBuilder<'a> {
609 if let Some(colorimetry) = colorimetry {
610 self.colorimetry(colorimetry)
611 } else {
612 self
613 }
614 }
615
616 pub fn par<T: Into<gst::Fraction>>(self, par: T) -> Self {
617 Self {
618 par: Some(par.into()),
619 ..self
620 }
621 }
622
623 pub fn par_if<T: Into<gst::Fraction>>(self, par: T, predicate: bool) -> Self {
624 if predicate {
625 self.par(par)
626 } else {
627 self
628 }
629 }
630
631 pub fn par_if_some<T: Into<gst::Fraction>>(self, par: Option<T>) -> Self {
632 if let Some(par) = par {
633 self.par(par)
634 } else {
635 self
636 }
637 }
638
639 pub fn fps<T: Into<gst::Fraction>>(self, fps: T) -> Self {
640 Self {
641 fps: Some(fps.into()),
642 ..self
643 }
644 }
645
646 pub fn fps_if<T: Into<gst::Fraction>>(self, fps: T, predicate: bool) -> Self {
647 if predicate {
648 self.fps(fps)
649 } else {
650 self
651 }
652 }
653
654 pub fn fps_if_some<T: Into<gst::Fraction>>(self, fps: Option<T>) -> Self {
655 if let Some(fps) = fps {
656 self.fps(fps)
657 } else {
658 self
659 }
660 }
661
662 pub fn offset(self, offset: &'a [usize]) -> VideoInfoBuilder<'a> {
663 Self {
664 offset: Some(offset),
665 ..self
666 }
667 }
668
669 pub fn offset_if(self, offset: &'a [usize], predicate: bool) -> VideoInfoBuilder<'a> {
670 if predicate {
671 self.offset(offset)
672 } else {
673 self
674 }
675 }
676
677 pub fn offset_if_some(self, offset: Option<&'a [usize]>) -> VideoInfoBuilder<'a> {
678 if let Some(offset) = offset {
679 self.offset(offset)
680 } else {
681 self
682 }
683 }
684
685 pub fn stride(self, stride: &'a [i32]) -> VideoInfoBuilder<'a> {
686 Self {
687 stride: Some(stride),
688 ..self
689 }
690 }
691
692 pub fn stride_if(self, stride: &'a [i32], predicate: bool) -> VideoInfoBuilder<'a> {
693 if predicate {
694 self.stride(stride)
695 } else {
696 self
697 }
698 }
699
700 pub fn stride_if_some(self, stride: Option<&'a [i32]>) -> VideoInfoBuilder<'a> {
701 if let Some(stride) = stride {
702 self.stride(stride)
703 } else {
704 self
705 }
706 }
707
708 pub fn multiview_mode(self, multiview_mode: crate::VideoMultiviewMode) -> Self {
709 Self {
710 multiview_mode: Some(multiview_mode),
711 ..self
712 }
713 }
714
715 pub fn multiview_mode_if(
716 self,
717 multiview_mode: crate::VideoMultiviewMode,
718 predicate: bool,
719 ) -> Self {
720 if predicate {
721 self.multiview_mode(multiview_mode)
722 } else {
723 self
724 }
725 }
726
727 pub fn multiview_mode_if_some(self, multiview_mode: Option<crate::VideoMultiviewMode>) -> Self {
728 if let Some(multiview_mode) = multiview_mode {
729 self.multiview_mode(multiview_mode)
730 } else {
731 self
732 }
733 }
734
735 pub fn multiview_flags(self, multiview_flags: crate::VideoMultiviewFlags) -> Self {
736 Self {
737 multiview_flags: Some(multiview_flags),
738 ..self
739 }
740 }
741
742 pub fn multiview_flags_if(
743 self,
744 multiview_flags: crate::VideoMultiviewFlags,
745 predicate: bool,
746 ) -> Self {
747 if predicate {
748 self.multiview_flags(multiview_flags)
749 } else {
750 self
751 }
752 }
753
754 pub fn multiview_flags_if_some(
755 self,
756 multiview_flags: Option<crate::VideoMultiviewFlags>,
757 ) -> Self {
758 if let Some(multiview_flags) = multiview_flags {
759 self.multiview_flags(multiview_flags)
760 } else {
761 self
762 }
763 }
764
765 pub fn field_order(self, field_order: crate::VideoFieldOrder) -> Self {
766 Self {
767 field_order: Some(field_order),
768 ..self
769 }
770 }
771
772 pub fn field_order_if(self, field_order: crate::VideoFieldOrder, predicate: bool) -> Self {
773 if predicate {
774 self.field_order(field_order)
775 } else {
776 self
777 }
778 }
779
780 pub fn field_order_if_some(self, field_order: Option<crate::VideoFieldOrder>) -> Self {
781 if let Some(field_order) = field_order {
782 self.field_order(field_order)
783 } else {
784 self
785 }
786 }
787}
788
789impl VideoInfo {
790 pub fn builder<'a>(
791 format: crate::VideoFormat,
792 width: u32,
793 height: u32,
794 ) -> VideoInfoBuilder<'a> {
795 assert_initialized_main_thread!();
796
797 VideoInfoBuilder {
798 format,
799 width,
800 height,
801 interlace_mode: None,
802 flags: None,
803 size: None,
804 views: None,
805 chroma_site: None,
806 colorimetry: None,
807 par: None,
808 fps: None,
809 offset: None,
810 stride: None,
811 multiview_mode: None,
812 multiview_flags: None,
813 field_order: None,
814 }
815 }
816
817 #[inline]
818 pub fn is_valid(&self) -> bool {
819 !self.0.finfo.is_null() && self.0.width > 0 && self.0.height > 0 && self.0.size > 0
820 }
821
822 #[doc(alias = "gst_video_info_from_caps")]
830 pub fn from_caps(caps: &gst::CapsRef) -> Result<Self, glib::error::BoolError> {
831 skip_assert_initialized!();
832
833 unsafe {
834 let mut info = mem::MaybeUninit::uninit();
835 if from_glib(ffi::gst_video_info_from_caps(
836 info.as_mut_ptr(),
837 caps.as_ptr(),
838 )) {
839 Ok(Self(info.assume_init()))
840 } else {
841 Err(glib::bool_error!("Failed to create VideoInfo from caps"))
842 }
843 }
844 }
845
846 #[doc(alias = "gst_video_info_to_caps")]
852 pub fn to_caps(&self) -> Result<gst::Caps, glib::error::BoolError> {
853 unsafe {
854 let result = from_glib_full(ffi::gst_video_info_to_caps(mut_override(&self.0)));
855 match result {
856 Some(c) => Ok(c),
857 None => Err(glib::bool_error!("Failed to create caps from VideoInfo")),
858 }
859 }
860 }
861
862 #[inline]
863 pub fn format(&self) -> crate::VideoFormat {
864 if self.0.finfo.is_null() {
865 return crate::VideoFormat::Unknown;
866 }
867
868 self.format_info().format()
869 }
870
871 #[inline]
872 pub fn format_info(&self) -> crate::VideoFormatInfo {
873 unsafe { crate::VideoFormatInfo::from_ptr(self.0.finfo) }
874 }
875
876 #[inline]
877 pub fn name<'a>(&self) -> &'a str {
878 self.format_info().name()
879 }
880
881 #[inline]
882 pub fn width(&self) -> u32 {
883 self.0.width as u32
884 }
885
886 #[inline]
887 pub fn height(&self) -> u32 {
888 self.0.height as u32
889 }
890
891 #[cfg(feature = "v1_16")]
892 #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
893 #[inline]
894 pub fn field_height(&self) -> u32 {
895 if self.0.interlace_mode == ffi::GST_VIDEO_INTERLACE_MODE_ALTERNATE {
896 (self.0.height as u32 + 1) / 2
897 } else {
898 self.0.height as u32
899 }
900 }
901
902 #[inline]
903 pub fn interlace_mode(&self) -> crate::VideoInterlaceMode {
904 unsafe { from_glib(self.0.interlace_mode) }
905 }
906
907 #[inline]
908 pub fn flags(&self) -> crate::VideoFlags {
909 unsafe { from_glib(self.0.flags) }
910 }
911
912 #[inline]
913 pub fn size(&self) -> usize {
914 self.0.size
915 }
916
917 #[inline]
918 pub fn views(&self) -> u32 {
919 self.0.views as u32
920 }
921
922 #[inline]
923 pub fn chroma_site(&self) -> crate::VideoChromaSite {
924 unsafe { from_glib(self.0.chroma_site) }
925 }
926
927 #[inline]
928 pub fn colorimetry(&self) -> VideoColorimetry {
929 unsafe { VideoColorimetry(ptr::read(&self.0.colorimetry)) }
930 }
931
932 #[inline]
933 pub fn comp_depth(&self, component: u8) -> u32 {
934 self.format_info().depth()[component as usize]
935 }
936
937 #[inline]
938 pub fn comp_height(&self, component: u8) -> u32 {
939 self.format_info().scale_height(component, self.height())
940 }
941
942 #[inline]
943 pub fn comp_width(&self, component: u8) -> u32 {
944 self.format_info().scale_width(component, self.width())
945 }
946
947 #[inline]
948 pub fn comp_offset(&self, component: u8) -> usize {
949 self.offset()[self.format_info().plane()[component as usize] as usize]
950 + self.format_info().poffset()[component as usize] as usize
951 }
952
953 #[inline]
954 pub fn comp_plane(&self, component: u8) -> u32 {
955 self.format_info().plane()[component as usize]
956 }
957
958 #[inline]
959 pub fn comp_poffset(&self, component: u8) -> u32 {
960 self.format_info().poffset()[component as usize]
961 }
962
963 #[inline]
964 pub fn comp_pstride(&self, component: u8) -> i32 {
965 self.format_info().pixel_stride()[component as usize]
966 }
967
968 #[inline]
969 pub fn comp_stride(&self, component: u8) -> i32 {
970 self.stride()[self.format_info().plane()[component as usize] as usize]
971 }
972
973 #[inline]
974 pub fn par(&self) -> gst::Fraction {
975 gst::Fraction::new(self.0.par_n, self.0.par_d)
976 }
977
978 #[inline]
979 pub fn fps(&self) -> gst::Fraction {
980 gst::Fraction::new(self.0.fps_n, self.0.fps_d)
981 }
982
983 #[cfg(feature = "v1_16")]
984 #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
985 #[inline]
986 pub fn field_rate(&self) -> gst::Fraction {
987 if self.interlace_mode() == crate::VideoInterlaceMode::Alternate {
988 2 * self.fps()
989 } else {
990 self.fps()
991 }
992 }
993
994 #[inline]
995 pub fn offset(&self) -> &[usize] {
996 &self.0.offset[0..(self.format_info().n_planes() as usize)]
997 }
998
999 #[inline]
1000 pub fn stride(&self) -> &[i32] {
1001 &self.0.stride[0..(self.format_info().n_planes() as usize)]
1002 }
1003
1004 #[inline]
1005 pub fn multiview_mode(&self) -> crate::VideoMultiviewMode {
1006 unsafe {
1007 let ptr = &self.0.ABI._gst_reserved as *const _ as *const i32;
1008 from_glib(ptr::read(ptr.offset(0)))
1009 }
1010 }
1011
1012 #[inline]
1013 pub fn multiview_flags(&self) -> crate::VideoMultiviewFlags {
1014 unsafe {
1015 let ptr = &self.0.ABI._gst_reserved as *const _ as *const u32;
1016 from_glib(ptr::read(ptr.offset(1)))
1017 }
1018 }
1019
1020 #[inline]
1021 pub fn field_order(&self) -> crate::VideoFieldOrder {
1022 unsafe {
1023 let ptr = &self.0.ABI._gst_reserved as *const _ as *const i32;
1024 from_glib(ptr::read(ptr.offset(2)))
1025 }
1026 }
1027
1028 #[inline]
1029 pub fn has_alpha(&self) -> bool {
1030 self.format_info().has_alpha()
1031 }
1032
1033 #[inline]
1034 pub fn is_gray(&self) -> bool {
1035 self.format_info().is_gray()
1036 }
1037
1038 #[inline]
1039 pub fn is_rgb(&self) -> bool {
1040 self.format_info().is_rgb()
1041 }
1042
1043 #[inline]
1044 pub fn is_yuv(&self) -> bool {
1045 self.format_info().is_yuv()
1046 }
1047
1048 #[inline]
1049 pub fn is_interlaced(&self) -> bool {
1050 self.interlace_mode() != crate::VideoInterlaceMode::Progressive
1051 }
1052
1053 #[inline]
1054 pub fn n_planes(&self) -> u32 {
1055 self.format_info().n_planes()
1056 }
1057
1058 #[inline]
1059 pub fn n_components(&self) -> u32 {
1060 self.format_info().n_components()
1061 }
1062
1063 #[doc(alias = "gst_video_info_convert")]
1081 pub fn convert<U: gst::format::SpecificFormattedValueFullRange>(
1082 &self,
1083 src_val: impl gst::format::FormattedValue,
1084 ) -> Option<U> {
1085 skip_assert_initialized!();
1086 unsafe {
1087 let mut dest_val = mem::MaybeUninit::uninit();
1088 if from_glib(ffi::gst_video_info_convert(
1089 mut_override(&self.0),
1090 src_val.format().into_glib(),
1091 src_val.into_raw_value(),
1092 U::default_format().into_glib(),
1093 dest_val.as_mut_ptr(),
1094 )) {
1095 Some(U::from_raw(U::default_format(), dest_val.assume_init()))
1096 } else {
1097 None
1098 }
1099 }
1100 }
1101
1102 pub fn convert_generic(
1103 &self,
1104 src_val: impl gst::format::FormattedValue,
1105 dest_fmt: gst::Format,
1106 ) -> Option<gst::GenericFormattedValue> {
1107 skip_assert_initialized!();
1108 unsafe {
1109 let mut dest_val = mem::MaybeUninit::uninit();
1110 if from_glib(ffi::gst_video_info_convert(
1111 mut_override(&self.0),
1112 src_val.format().into_glib(),
1113 src_val.into_raw_value(),
1114 dest_fmt.into_glib(),
1115 dest_val.as_mut_ptr(),
1116 )) {
1117 Some(gst::GenericFormattedValue::new(
1118 dest_fmt,
1119 dest_val.assume_init(),
1120 ))
1121 } else {
1122 None
1123 }
1124 }
1125 }
1126
1127 #[doc(alias = "gst_video_info_align")]
1140 pub fn align(&mut self, align: &mut crate::VideoAlignment) -> Result<(), glib::BoolError> {
1141 unsafe {
1142 glib::result_from_gboolean!(
1143 ffi::gst_video_info_align(&mut self.0, &mut align.0,),
1144 "Failed to align VideoInfo"
1145 )
1146 }
1147 }
1148
1149 #[cfg(feature = "v1_18")]
1169 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
1170 #[doc(alias = "gst_video_info_align_full")]
1171 pub fn align_full(
1172 &mut self,
1173 align: &mut crate::VideoAlignment,
1174 ) -> Result<[usize; crate::VIDEO_MAX_PLANES], glib::BoolError> {
1175 let mut plane_size = [0; crate::VIDEO_MAX_PLANES];
1176
1177 unsafe {
1178 glib::result_from_gboolean!(
1179 ffi::gst_video_info_align_full(&mut self.0, &mut align.0, plane_size.as_mut_ptr()),
1180 "Failed to align VideoInfo"
1181 )?;
1182 }
1183
1184 Ok(plane_size)
1185 }
1186
1187 #[doc(alias = "gst_video_color_range_offsets")]
1188 #[inline]
1189 pub fn range_offsets(&self, range: crate::VideoColorRange) -> ([i32; 4], [i32; 4]) {
1190 self.format_info().range_offsets(range)
1191 }
1192}
1193
1194impl PartialEq for VideoInfo {
1195 #[doc(alias = "gst_video_info_is_equal")]
1196 fn eq(&self, other: &Self) -> bool {
1197 unsafe { from_glib(ffi::gst_video_info_is_equal(&self.0, &other.0)) }
1198 }
1199}
1200
1201impl Eq for VideoInfo {}
1202
1203unsafe impl Send for VideoInfo {}
1204unsafe impl Sync for VideoInfo {}
1205
1206impl glib::types::StaticType for VideoInfo {
1207 #[inline]
1208 fn static_type() -> glib::types::Type {
1209 unsafe { glib::translate::from_glib(ffi::gst_video_info_get_type()) }
1210 }
1211}
1212
1213impl glib::value::ValueType for VideoInfo {
1214 type Type = Self;
1215}
1216
1217#[doc(hidden)]
1218unsafe impl<'a> glib::value::FromValue<'a> for VideoInfo {
1219 type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
1220
1221 unsafe fn from_value(value: &'a glib::Value) -> Self {
1222 skip_assert_initialized!();
1223 from_glib_none(
1224 glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut ffi::GstVideoInfo
1225 )
1226 }
1227}
1228
1229#[doc(hidden)]
1230impl glib::value::ToValue for VideoInfo {
1231 fn to_value(&self) -> glib::Value {
1232 let mut value = glib::Value::for_value_type::<Self>();
1233 unsafe {
1234 glib::gobject_ffi::g_value_set_boxed(
1235 value.to_glib_none_mut().0,
1236 self.to_glib_none().0 as *mut _,
1237 )
1238 }
1239 value
1240 }
1241
1242 fn value_type(&self) -> glib::Type {
1243 Self::static_type()
1244 }
1245}
1246
1247#[doc(hidden)]
1248impl glib::value::ToValueOptional for VideoInfo {
1249 fn to_value_optional(s: Option<&Self>) -> glib::Value {
1250 skip_assert_initialized!();
1251 let mut value = glib::Value::for_value_type::<Self>();
1252 unsafe {
1253 glib::gobject_ffi::g_value_set_boxed(
1254 value.to_glib_none_mut().0,
1255 s.to_glib_none().0 as *mut _,
1256 )
1257 }
1258 value
1259 }
1260}
1261
1262#[doc(hidden)]
1263impl From<VideoInfo> for glib::Value {
1264 fn from(v: VideoInfo) -> glib::Value {
1265 skip_assert_initialized!();
1266 glib::value::ToValue::to_value(&v)
1267 }
1268}
1269
1270#[doc(hidden)]
1271impl glib::translate::Uninitialized for VideoInfo {
1272 #[inline]
1273 unsafe fn uninitialized() -> Self {
1274 mem::zeroed()
1275 }
1276}
1277
1278#[doc(hidden)]
1279impl glib::translate::GlibPtrDefault for VideoInfo {
1280 type GlibType = *mut ffi::GstVideoInfo;
1281}
1282
1283#[doc(hidden)]
1284impl<'a> glib::translate::ToGlibPtr<'a, *const ffi::GstVideoInfo> for VideoInfo {
1285 type Storage = PhantomData<&'a Self>;
1286
1287 #[inline]
1288 fn to_glib_none(&'a self) -> glib::translate::Stash<'a, *const ffi::GstVideoInfo, Self> {
1289 glib::translate::Stash(&self.0, PhantomData)
1290 }
1291
1292 fn to_glib_full(&self) -> *const ffi::GstVideoInfo {
1293 unimplemented!()
1294 }
1295}
1296
1297#[doc(hidden)]
1298impl glib::translate::FromGlibPtrNone<*const ffi::GstVideoInfo> for VideoInfo {
1299 #[inline]
1300 unsafe fn from_glib_none(ptr: *const ffi::GstVideoInfo) -> Self {
1301 Self(ptr::read(ptr))
1302 }
1303}
1304
1305#[doc(hidden)]
1306impl glib::translate::FromGlibPtrNone<*mut ffi::GstVideoInfo> for VideoInfo {
1307 #[inline]
1308 unsafe fn from_glib_none(ptr: *mut ffi::GstVideoInfo) -> Self {
1309 Self(ptr::read(ptr))
1310 }
1311}
1312
1313#[doc(hidden)]
1314impl glib::translate::FromGlibPtrFull<*mut ffi::GstVideoInfo> for VideoInfo {
1315 #[inline]
1316 unsafe fn from_glib_full(ptr: *mut ffi::GstVideoInfo) -> Self {
1317 let info = from_glib_none(ptr);
1318 glib::ffi::g_free(ptr as *mut _);
1319 info
1320 }
1321}
1322
1323impl crate::VideoFieldOrder {
1324 #[doc(alias = "gst_video_field_order_to_string")]
1325 pub fn to_str<'a>(self) -> &'a str {
1326 use std::ffi::CStr;
1327
1328 if self == Self::Unknown {
1329 return "UNKNOWN";
1330 }
1331 unsafe {
1332 CStr::from_ptr(
1333 ffi::gst_video_field_order_to_string(self.into_glib())
1334 .as_ref()
1335 .expect("gst_video_field_order_to_string returned NULL"),
1336 )
1337 .to_str()
1338 .expect("gst_video_field_order_to_string returned an invalid string")
1339 }
1340 }
1341}
1342
1343impl str::FromStr for crate::VideoFieldOrder {
1344 type Err = glib::error::BoolError;
1345
1346 fn from_str(s: &str) -> Result<Self, Self::Err> {
1347 skip_assert_initialized!();
1348
1349 let fmt = Self::from_string(s);
1350 if fmt == Self::Unknown {
1351 Err(glib::bool_error!(
1352 "Failed to parse video field order from string"
1353 ))
1354 } else {
1355 Ok(fmt)
1356 }
1357 }
1358}
1359
1360impl str::FromStr for crate::VideoInterlaceMode {
1361 type Err = glib::error::BoolError;
1362
1363 fn from_str(s: &str) -> Result<Self, Self::Err> {
1364 skip_assert_initialized!();
1365
1366 let fmt = Self::from_string(s);
1367 Ok(fmt)
1368 }
1369}
1370
1371#[cfg(test)]
1372mod tests {
1373 use super::*;
1374
1375 #[test]
1376 fn test_new() {
1377 gst::init().unwrap();
1378
1379 let info = VideoInfo::builder(crate::VideoFormat::I420, 320, 240)
1380 .build()
1381 .unwrap();
1382 assert_eq!(info.format(), crate::VideoFormat::I420);
1383 assert_eq!(info.width(), 320);
1384 assert_eq!(info.height(), 240);
1385 assert_eq!(info.size(), 320 * 240 + 2 * 160 * 120);
1386 assert_eq!(info.multiview_mode(), crate::VideoMultiviewMode::None);
1387 assert_eq!(&info.offset(), &[0, 320 * 240, 320 * 240 + 160 * 120]);
1388 assert_eq!(&info.stride(), &[320, 160, 160]);
1389
1390 let offsets = [0, 640 * 240 + 16, 640 * 240 + 16 + 320 * 120 + 16];
1391 let strides = [640, 320, 320];
1392 let info = VideoInfo::builder(crate::VideoFormat::I420, 320, 240)
1393 .offset(&offsets)
1394 .stride(&strides)
1395 .size(640 * 240 + 16 + 320 * 120 + 16 + 320 * 120 + 16)
1396 .multiview_mode(crate::VideoMultiviewMode::SideBySide)
1397 .build()
1398 .unwrap();
1399 assert_eq!(info.format(), crate::VideoFormat::I420);
1400 assert_eq!(info.width(), 320);
1401 assert_eq!(info.height(), 240);
1402 assert_eq!(
1403 info.size(),
1404 640 * 240 + 16 + 320 * 120 + 16 + 320 * 120 + 16
1405 );
1406 assert_eq!(info.multiview_mode(), crate::VideoMultiviewMode::SideBySide);
1407 assert_eq!(
1408 &info.offset(),
1409 &[0, 640 * 240 + 16, 640 * 240 + 16 + 320 * 120 + 16]
1410 );
1411 assert_eq!(&info.stride(), &[640, 320, 320]);
1412 }
1413
1414 #[test]
1415 fn test_from_to_caps() {
1416 gst::init().unwrap();
1417
1418 let caps = crate::VideoCapsBuilder::new()
1419 .format(crate::VideoFormat::I420)
1420 .width(320)
1421 .height(240)
1422 .framerate((30, 1).into())
1423 .pixel_aspect_ratio((1, 1).into())
1424 .field("interlace-mode", "progressive")
1425 .field("chroma-site", "mpeg2")
1426 .field("colorimetry", "bt709")
1427 .build();
1428 let info = VideoInfo::from_caps(&caps).unwrap();
1429 assert_eq!(info.format(), crate::VideoFormat::I420);
1430 assert_eq!(info.width(), 320);
1431 assert_eq!(info.height(), 240);
1432 assert_eq!(info.fps(), gst::Fraction::new(30, 1));
1433 assert_eq!(
1434 info.interlace_mode(),
1435 crate::VideoInterlaceMode::Progressive
1436 );
1437 assert_eq!(info.chroma_site(), crate::VideoChromaSite::MPEG2);
1438 assert_eq!(info.colorimetry(), "bt709".parse().unwrap());
1439
1440 let caps2 = info.to_caps().unwrap();
1441 assert_eq!(caps, caps2);
1442
1443 let info2 = VideoInfo::from_caps(&caps2).unwrap();
1444 assert!(info == info2);
1445 }
1446
1447 #[test]
1448 fn test_video_align() {
1449 gst::init().unwrap();
1450
1451 let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv16, 1920, 1080)
1452 .build()
1453 .expect("Failed to create VideoInfo");
1454
1455 assert_eq!(info.stride(), [1920, 1920]);
1456 assert_eq!(info.offset(), [0, 2_073_600]);
1457
1458 let mut align = crate::VideoAlignment::new(0, 0, 0, 8, &[0; VIDEO_MAX_PLANES]);
1459 info.align(&mut align).unwrap();
1460
1461 assert_eq!(info.stride(), [1928, 1928]);
1462 assert_eq!(info.offset(), [0, 2_082_240]);
1463
1464 #[cfg(feature = "v1_18")]
1465 {
1466 let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv16, 1920, 1080)
1467 .build()
1468 .expect("Failed to create VideoInfo");
1469
1470 let mut align = crate::VideoAlignment::new(0, 0, 0, 8, &[0; VIDEO_MAX_PLANES]);
1471 let plane_size = info.align_full(&mut align).unwrap();
1472 assert_eq!(plane_size, [2082240, 2082240, 0, 0]);
1473 }
1474 }
1475
1476 #[test]
1477 fn test_display() {
1478 gst::init().unwrap();
1479
1480 let _ = format!("{}", "sRGB".parse::<crate::VideoColorimetry>().unwrap());
1481 let _ = format!("{}", crate::VideoFieldOrder::TopFieldFirst);
1482 let _ = format!("{}", crate::VideoInterlaceMode::Progressive);
1483 }
1484}