1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, marker::PhantomData, mem, ptr, str};
4
5use glib::translate::*;
6use gst::prelude::*;
7
8#[doc(alias = "GST_VIDEO_MAX_PLANES")]
9pub const VIDEO_MAX_PLANES: usize = ffi::GST_VIDEO_MAX_PLANES as usize;
10
11#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
12#[non_exhaustive]
13#[doc(alias = "GstVideoColorRange")]
14pub enum VideoColorRange {
15 #[doc(alias = "GST_VIDEO_COLOR_RANGE_UNKNOWN")]
16 Unknown,
17 #[doc(alias = "GST_VIDEO_COLOR_RANGE_0_255")]
18 Range0_255,
19 #[doc(alias = "GST_VIDEO_COLOR_RANGE_16_235")]
20 Range16_235,
21 #[doc(hidden)]
22 __Unknown(i32),
23}
24
25#[doc(hidden)]
26impl IntoGlib for VideoColorRange {
27 type GlibType = ffi::GstVideoColorRange;
28
29 #[inline]
30 fn into_glib(self) -> ffi::GstVideoColorRange {
31 match self {
32 Self::Unknown => ffi::GST_VIDEO_COLOR_RANGE_UNKNOWN,
33 Self::Range0_255 => ffi::GST_VIDEO_COLOR_RANGE_0_255,
34 Self::Range16_235 => ffi::GST_VIDEO_COLOR_RANGE_16_235,
35 Self::__Unknown(value: i32) => value,
36 }
37 }
38}
39
40#[doc(hidden)]
41impl FromGlib<ffi::GstVideoColorRange> for VideoColorRange {
42 #[inline]
43 unsafe fn from_glib(value: ffi::GstVideoColorRange) -> Self {
44 skip_assert_initialized!();
45 match value {
46 0 => Self::Unknown,
47 1 => Self::Range0_255,
48 2 => Self::Range16_235,
49 value: i32 => Self::__Unknown(value),
50 }
51 }
52}
53
54impl StaticType for VideoColorRange {
55 #[inline]
56 fn static_type() -> glib::Type {
57 unsafe { from_glib(val:ffi::gst_video_color_range_get_type()) }
58 }
59}
60
61impl glib::value::ValueType for VideoColorRange {
62 type Type = Self;
63}
64
65unsafe impl<'a> glib::value::FromValue<'a> for VideoColorRange {
66 type Checker = glib::value::GenericValueTypeChecker<Self>;
67
68 unsafe fn from_value(value: &'a glib::Value) -> Self {
69 skip_assert_initialized!();
70 from_glib(val:glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0))
71 }
72}
73
74impl ToValue for VideoColorRange {
75 fn to_value(&self) -> glib::Value {
76 let mut value: Value = glib::Value::for_value_type::<Self>();
77 unsafe { glib::gobject_ffi::g_value_set_enum(value:value.to_glib_none_mut().0, self.into_glib()) }
78 value
79 }
80
81 fn value_type(&self) -> glib::Type {
82 Self::static_type()
83 }
84}
85
86impl From<VideoColorRange> for glib::Value {
87 fn from(v: VideoColorRange) -> glib::Value {
88 skip_assert_initialized!();
89 glib::value::ToValue::to_value(&v)
90 }
91}
92
93#[doc(alias = "GstVideoColorimetry")]
94#[derive(Copy, Clone)]
95#[repr(transparent)]
96pub struct VideoColorimetry(ffi::GstVideoColorimetry);
97
98impl VideoColorimetry {
99 pub fn new(
100 range: crate::VideoColorRange,
101 matrix: crate::VideoColorMatrix,
102 transfer: crate::VideoTransferFunction,
103 primaries: crate::VideoColorPrimaries,
104 ) -> Self {
105 skip_assert_initialized!();
106
107 let colorimetry = ffi::GstVideoColorimetry {
108 range: range.into_glib(),
109 matrix: matrix.into_glib(),
110 transfer: transfer.into_glib(),
111 primaries: primaries.into_glib(),
112 };
113
114 Self(colorimetry)
115 }
116
117 #[inline]
118 pub fn range(&self) -> crate::VideoColorRange {
119 unsafe { from_glib(self.0.range) }
120 }
121
122 #[inline]
123 pub fn matrix(&self) -> crate::VideoColorMatrix {
124 unsafe { from_glib(self.0.matrix) }
125 }
126
127 #[inline]
128 pub fn transfer(&self) -> crate::VideoTransferFunction {
129 unsafe { from_glib(self.0.transfer) }
130 }
131
132 #[inline]
133 pub fn primaries(&self) -> crate::VideoColorPrimaries {
134 unsafe { from_glib(self.0.primaries) }
135 }
136
137 #[cfg(feature = "v1_22")]
138 #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
139 #[doc(alias = "gst_video_colorimetry_is_equivalent")]
140 pub fn is_equivalent(&self, bitdepth: u32, other: &Self, other_bitdepth: u32) -> bool {
141 unsafe {
142 from_glib(ffi::gst_video_colorimetry_is_equivalent(
143 &self.0,
144 bitdepth,
145 &other.0,
146 other_bitdepth,
147 ))
148 }
149 }
150}
151
152impl PartialEq for VideoColorimetry {
153 #[doc(alias = "gst_video_colorimetry_is_equal")]
154 fn eq(&self, other: &Self) -> bool {
155 unsafe { from_glib(val:ffi::gst_video_colorimetry_is_equal(&self.0, &other.0)) }
156 }
157}
158
159impl Eq for VideoColorimetry {}
160
161impl str::FromStr for crate::VideoColorimetry {
162 type Err = glib::error::BoolError;
163
164 #[doc(alias = "gst_video_colorimetry_from_string")]
165 fn from_str(s: &str) -> Result<Self, Self::Err> {
166 assert_initialized_main_thread!();
167
168 unsafe {
169 let mut colorimetry: MaybeUninit = mem::MaybeUninit::uninit();
170 let valid: bool = from_glib(val:ffi::gst_video_colorimetry_from_string(
171 cinfo:colorimetry.as_mut_ptr(),
172 color:s.to_glib_none().0,
173 ));
174 if valid {
175 Ok(Self(colorimetry.assume_init()))
176 } else {
177 Err(glib::bool_error!("Invalid colorimetry info"))
178 }
179 }
180 }
181}
182
183impl fmt::Debug for crate::VideoColorimetry {
184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185 f&mut DebugStruct<'_, '_>.debug_struct("VideoColorimetry")
186 .field("range", &self.0.range)
187 .field("matrix", &self.0.matrix)
188 .field("transfer", &self.0.transfer)
189 .field(name:"primaries", &self.0.primaries)
190 .finish()
191 }
192}
193
194impl fmt::Display for crate::VideoColorimetry {
195 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196 let s: GString =
197 unsafe { glib::GString::from_glib_full(ptr:ffi::gst_video_colorimetry_to_string(&self.0)) };
198 f.write_str(&s)
199 }
200}
201
202impl crate::VideoChromaSite {
203 #[doc(alias = "gst_video_chroma_site_to_string")]
204 #[doc(alias = "gst_video_chroma_to_string")]
205 pub fn to_str(self) -> glib::GString {
206 assert_initialized_main_thread!();
207
208 unsafe {
209 cfg_if::cfg_if! {
210 if #[cfg(feature = "v1_20")] {
211 from_glib_full(ffi::gst_video_chroma_site_to_string(self.into_glib()))
212 } else {
213 from_glib_none(ffi::gst_video_chroma_to_string(self.into_glib()))
214 }
215 }
216 }
217 }
218}
219
220impl str::FromStr for crate::VideoChromaSite {
221 type Err = glib::error::BoolError;
222
223 #[doc(alias = "gst_video_chroma_from_string")]
224 fn from_str(s: &str) -> Result<Self, Self::Err> {
225 skip_assert_initialized!();
226
227 cfg_if::cfg_if! {
228 if #[cfg(feature = "v1_20")] {
229 let chroma_site = Self::from_string(s);
230 } else {
231 assert_initialized_main_thread!();
232 let chroma_site: Self =
233 unsafe { from_glib(ffi::gst_video_chroma_from_string(s.to_glib_none().0)) };
234 }
235 };
236
237 if chroma_site.is_empty() {
238 Err(glib::bool_error!("Invalid chroma site"))
239 } else {
240 Ok(chroma_site)
241 }
242 }
243}
244
245impl From<crate::VideoMultiviewFramePacking> for crate::VideoMultiviewMode {
246 #[inline]
247 fn from(v: crate::VideoMultiviewFramePacking) -> Self {
248 skip_assert_initialized!();
249 unsafe { from_glib(val:v.into_glib()) }
250 }
251}
252
253impl TryFrom<crate::VideoMultiviewMode> for crate::VideoMultiviewFramePacking {
254 type Error = glib::BoolError;
255
256 fn try_from(v: crate::VideoMultiviewMode) -> Result<Self, glib::BoolError> {
257 skip_assert_initialized!();
258
259 let v2: VideoMultiviewFramePacking = unsafe { from_glib(val:v.into_glib()) };
260
261 if let Self::__Unknown(_) = v2 {
262 Err(glib::bool_error!("Invalid frame packing mode"))
263 } else {
264 Ok(v2)
265 }
266 }
267}
268
269#[doc(alias = "GstVideoInfo")]
270#[derive(Clone)]
271#[repr(transparent)]
272pub struct VideoInfo(pub(crate) ffi::GstVideoInfo);
273
274impl fmt::Debug for VideoInfo {
275 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
276 f&mut DebugStruct<'_, '_>.debug_struct("VideoInfo")
277 .field("format", &self.format())
278 .field("format-info", &self.format_info())
279 .field("width", &self.width())
280 .field("height", &self.height())
281 .field("interlace_mode", &self.interlace_mode())
282 .field("flags", &self.flags())
283 .field("size", &self.size())
284 .field("views", &self.views())
285 .field("chroma_site", &self.chroma_site())
286 .field("colorimetry", &self.colorimetry())
287 .field("par", &self.par())
288 .field("fps", &self.fps())
289 .field("offset", &self.offset())
290 .field("stride", &self.stride())
291 .field("multiview_mode", &self.multiview_mode())
292 .field("multiview_flags", &self.multiview_flags())
293 .field(name:"field_order", &self.field_order())
294 .finish()
295 }
296}
297
298#[derive(Debug)]
299#[must_use = "The builder must be built to be used"]
300pub struct VideoInfoBuilder<'a> {
301 format: crate::VideoFormat,
302 width: u32,
303 height: u32,
304 interlace_mode: Option<crate::VideoInterlaceMode>,
305 flags: Option<crate::VideoFlags>,
306 size: Option<usize>,
307 views: Option<u32>,
308 chroma_site: Option<crate::VideoChromaSite>,
309 colorimetry: Option<&'a crate::VideoColorimetry>,
310 par: Option<gst::Fraction>,
311 fps: Option<gst::Fraction>,
312 offset: Option<&'a [usize]>,
313 stride: Option<&'a [i32]>,
314 multiview_mode: Option<crate::VideoMultiviewMode>,
315 multiview_flags: Option<crate::VideoMultiviewFlags>,
316 field_order: Option<crate::VideoFieldOrder>,
317}
318
319impl<'a> VideoInfoBuilder<'a> {
320 pub fn build(self) -> Result<VideoInfo, glib::error::BoolError> {
321 unsafe {
322 let mut info = mem::MaybeUninit::uninit();
323
324 cfg_if::cfg_if! {
325 if #[cfg(feature = "v1_16")] {
326 let res: bool = {
327 from_glib(if let Some(interlace_mode) = self.interlace_mode {
328 ffi::gst_video_info_set_interlaced_format(
329 info.as_mut_ptr(),
330 self.format.into_glib(),
331 interlace_mode.into_glib(),
332 self.width,
333 self.height,
334 )
335 } else {
336 ffi::gst_video_info_set_format(
337 info.as_mut_ptr(),
338 self.format.into_glib(),
339 self.width,
340 self.height,
341 )
342 })
343 };
344 } else {
345 let res: bool = {
346 let res = from_glib(ffi::gst_video_info_set_format(
347 info.as_mut_ptr(),
348 self.format.into_glib(),
349 self.width,
350 self.height,
351 ));
352
353 if res {
354 if let Some(interlace_mode) = self.interlace_mode {
355 let info = info.as_mut_ptr();
356 (*info).interlace_mode = interlace_mode.into_glib();
357 }
358 }
359
360 res
361 };
362 }
363 }
364
365 if !res {
366 return Err(glib::bool_error!("Failed to build VideoInfo"));
367 }
368
369 let mut info = info.assume_init();
370
371 if info.finfo.is_null() || info.width <= 0 || info.height <= 0 {
372 return Err(glib::bool_error!("Failed to build VideoInfo"));
373 }
374
375 if let Some(flags) = self.flags {
376 info.flags = flags.into_glib();
377 }
378
379 if let Some(size) = self.size {
380 info.size = size;
381 }
382
383 if let Some(views) = self.views {
384 info.views = views as i32;
385 }
386
387 if let Some(chroma_site) = self.chroma_site {
388 info.chroma_site = chroma_site.into_glib();
389 }
390
391 if let Some(colorimetry) = self.colorimetry {
392 ptr::write(&mut info.colorimetry, ptr::read(&colorimetry.0));
393 }
394
395 if let Some(par) = self.par {
396 info.par_n = par.numer();
397 info.par_d = par.denom();
398 }
399
400 if let Some(fps) = self.fps {
401 info.fps_n = fps.numer();
402 info.fps_d = fps.denom();
403 }
404
405 if let Some(offset) = self.offset {
406 if offset.len() != ((*info.finfo).n_planes as usize) {
407 return Err(glib::bool_error!("Failed to build VideoInfo"));
408 }
409
410 let n_planes = (*info.finfo).n_planes as usize;
411 info.offset[..n_planes].copy_from_slice(&offset[..n_planes]);
412 }
413
414 if let Some(stride) = self.stride {
415 if stride.len() != ((*info.finfo).n_planes as usize) {
416 return Err(glib::bool_error!("Failed to build VideoInfo"));
417 }
418
419 let n_planes = (*info.finfo).n_planes as usize;
420 info.stride[..n_planes].copy_from_slice(&stride[..n_planes]);
421 }
422
423 if let Some(multiview_mode) = self.multiview_mode {
424 let ptr = &mut info.ABI._gst_reserved as *mut _ as *mut i32;
425 ptr::write(ptr.offset(0), multiview_mode.into_glib());
426 }
427
428 if let Some(multiview_flags) = self.multiview_flags {
429 let ptr = &mut info.ABI._gst_reserved as *mut _ as *mut u32;
430 ptr::write(ptr.offset(1), multiview_flags.into_glib());
431 }
432
433 if let Some(field_order) = self.field_order {
434 let ptr = &mut info.ABI._gst_reserved as *mut _ as *mut i32;
435 ptr::write(ptr.offset(2), field_order.into_glib());
436 }
437
438 Ok(VideoInfo(info))
439 }
440 }
441
442 pub fn interlace_mode(self, interlace_mode: crate::VideoInterlaceMode) -> VideoInfoBuilder<'a> {
443 Self {
444 interlace_mode: Some(interlace_mode),
445 ..self
446 }
447 }
448
449 pub fn flags(self, flags: crate::VideoFlags) -> Self {
450 Self {
451 flags: Some(flags),
452 ..self
453 }
454 }
455
456 pub fn size(self, size: usize) -> Self {
457 Self {
458 size: Some(size),
459 ..self
460 }
461 }
462
463 pub fn views(self, views: u32) -> Self {
464 Self {
465 views: Some(views),
466 ..self
467 }
468 }
469
470 pub fn chroma_site(self, chroma_site: crate::VideoChromaSite) -> Self {
471 Self {
472 chroma_site: Some(chroma_site),
473 ..self
474 }
475 }
476
477 pub fn colorimetry(self, colorimetry: &'a crate::VideoColorimetry) -> VideoInfoBuilder<'a> {
478 Self {
479 colorimetry: Some(colorimetry),
480 ..self
481 }
482 }
483
484 pub fn par<T: Into<gst::Fraction>>(self, par: T) -> Self {
485 Self {
486 par: Some(par.into()),
487 ..self
488 }
489 }
490
491 pub fn fps<T: Into<gst::Fraction>>(self, fps: T) -> Self {
492 Self {
493 fps: Some(fps.into()),
494 ..self
495 }
496 }
497
498 pub fn offset(self, offset: &'a [usize]) -> VideoInfoBuilder<'a> {
499 Self {
500 offset: Some(offset),
501 ..self
502 }
503 }
504
505 pub fn stride(self, stride: &'a [i32]) -> VideoInfoBuilder<'a> {
506 Self {
507 stride: Some(stride),
508 ..self
509 }
510 }
511
512 pub fn multiview_mode(self, multiview_mode: crate::VideoMultiviewMode) -> Self {
513 Self {
514 multiview_mode: Some(multiview_mode),
515 ..self
516 }
517 }
518
519 pub fn multiview_flags(self, multiview_flags: crate::VideoMultiviewFlags) -> Self {
520 Self {
521 multiview_flags: Some(multiview_flags),
522 ..self
523 }
524 }
525
526 pub fn field_order(self, field_order: crate::VideoFieldOrder) -> Self {
527 Self {
528 field_order: Some(field_order),
529 ..self
530 }
531 }
532}
533
534impl VideoInfo {
535 pub fn builder<'a>(
536 format: crate::VideoFormat,
537 width: u32,
538 height: u32,
539 ) -> VideoInfoBuilder<'a> {
540 assert_initialized_main_thread!();
541
542 VideoInfoBuilder {
543 format,
544 width,
545 height,
546 interlace_mode: None,
547 flags: None,
548 size: None,
549 views: None,
550 chroma_site: None,
551 colorimetry: None,
552 par: None,
553 fps: None,
554 offset: None,
555 stride: None,
556 multiview_mode: None,
557 multiview_flags: None,
558 field_order: None,
559 }
560 }
561
562 #[inline]
563 pub fn is_valid(&self) -> bool {
564 !self.0.finfo.is_null() && self.0.width > 0 && self.0.height > 0 && self.0.size > 0
565 }
566
567 #[doc(alias = "gst_video_info_from_caps")]
568 pub fn from_caps(caps: &gst::CapsRef) -> Result<Self, glib::error::BoolError> {
569 skip_assert_initialized!();
570
571 unsafe {
572 let mut info = mem::MaybeUninit::uninit();
573 if from_glib(ffi::gst_video_info_from_caps(
574 info.as_mut_ptr(),
575 caps.as_ptr(),
576 )) {
577 Ok(Self(info.assume_init()))
578 } else {
579 Err(glib::bool_error!("Failed to create VideoInfo from caps"))
580 }
581 }
582 }
583
584 #[doc(alias = "gst_video_info_to_caps")]
585 pub fn to_caps(&self) -> Result<gst::Caps, glib::error::BoolError> {
586 unsafe {
587 let result = from_glib_full(ffi::gst_video_info_to_caps(&self.0 as *const _ as *mut _));
588 match result {
589 Some(c) => Ok(c),
590 None => Err(glib::bool_error!("Failed to create caps from VideoInfo")),
591 }
592 }
593 }
594
595 #[inline]
596 pub fn format(&self) -> crate::VideoFormat {
597 if self.0.finfo.is_null() {
598 return crate::VideoFormat::Unknown;
599 }
600
601 self.format_info().format()
602 }
603
604 #[inline]
605 pub fn format_info(&self) -> crate::VideoFormatInfo {
606 unsafe { crate::VideoFormatInfo::from_ptr(self.0.finfo) }
607 }
608
609 #[inline]
610 pub fn name<'a>(&self) -> &'a str {
611 self.format_info().name()
612 }
613
614 #[inline]
615 pub fn width(&self) -> u32 {
616 self.0.width as u32
617 }
618
619 #[inline]
620 pub fn height(&self) -> u32 {
621 self.0.height as u32
622 }
623
624 #[cfg(feature = "v1_16")]
625 #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
626 #[inline]
627 pub fn field_height(&self) -> u32 {
628 if self.0.interlace_mode == ffi::GST_VIDEO_INTERLACE_MODE_ALTERNATE {
629 (self.0.height as u32 + 1) / 2
630 } else {
631 self.0.height as u32
632 }
633 }
634
635 #[inline]
636 pub fn interlace_mode(&self) -> crate::VideoInterlaceMode {
637 unsafe { from_glib(self.0.interlace_mode) }
638 }
639
640 #[inline]
641 pub fn flags(&self) -> crate::VideoFlags {
642 unsafe { from_glib(self.0.flags) }
643 }
644
645 #[inline]
646 pub fn size(&self) -> usize {
647 self.0.size
648 }
649
650 #[inline]
651 pub fn views(&self) -> u32 {
652 self.0.views as u32
653 }
654
655 #[inline]
656 pub fn chroma_site(&self) -> crate::VideoChromaSite {
657 unsafe { from_glib(self.0.chroma_site) }
658 }
659
660 #[inline]
661 pub fn colorimetry(&self) -> VideoColorimetry {
662 unsafe { VideoColorimetry(ptr::read(&self.0.colorimetry)) }
663 }
664
665 #[inline]
666 pub fn comp_depth(&self, component: u8) -> u32 {
667 self.format_info().depth()[component as usize]
668 }
669
670 #[inline]
671 pub fn comp_height(&self, component: u8) -> u32 {
672 self.format_info().scale_height(component, self.height())
673 }
674
675 #[inline]
676 pub fn comp_width(&self, component: u8) -> u32 {
677 self.format_info().scale_width(component, self.width())
678 }
679
680 #[inline]
681 pub fn comp_offset(&self, component: u8) -> usize {
682 self.offset()[self.format_info().plane()[component as usize] as usize]
683 + self.format_info().poffset()[component as usize] as usize
684 }
685
686 #[inline]
687 pub fn comp_plane(&self, component: u8) -> u32 {
688 self.format_info().plane()[component as usize]
689 }
690
691 #[inline]
692 pub fn comp_poffset(&self, component: u8) -> u32 {
693 self.format_info().poffset()[component as usize]
694 }
695
696 #[inline]
697 pub fn comp_pstride(&self, component: u8) -> i32 {
698 self.format_info().pixel_stride()[component as usize]
699 }
700
701 #[inline]
702 pub fn comp_stride(&self, component: u8) -> i32 {
703 self.stride()[self.format_info().plane()[component as usize] as usize]
704 }
705
706 #[inline]
707 pub fn par(&self) -> gst::Fraction {
708 gst::Fraction::new(self.0.par_n, self.0.par_d)
709 }
710
711 #[inline]
712 pub fn fps(&self) -> gst::Fraction {
713 gst::Fraction::new(self.0.fps_n, self.0.fps_d)
714 }
715
716 #[cfg(feature = "v1_16")]
717 #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
718 #[inline]
719 pub fn field_rate(&self) -> gst::Fraction {
720 if self.interlace_mode() == crate::VideoInterlaceMode::Alternate {
721 2 * self.fps()
722 } else {
723 self.fps()
724 }
725 }
726
727 #[inline]
728 pub fn offset(&self) -> &[usize] {
729 &self.0.offset[0..(self.format_info().n_planes() as usize)]
730 }
731
732 #[inline]
733 pub fn stride(&self) -> &[i32] {
734 &self.0.stride[0..(self.format_info().n_planes() as usize)]
735 }
736
737 #[inline]
738 pub fn multiview_mode(&self) -> crate::VideoMultiviewMode {
739 unsafe {
740 let ptr = &self.0.ABI._gst_reserved as *const _ as *const i32;
741 from_glib(ptr::read(ptr.offset(0)))
742 }
743 }
744
745 #[inline]
746 pub fn multiview_flags(&self) -> crate::VideoMultiviewFlags {
747 unsafe {
748 let ptr = &self.0.ABI._gst_reserved as *const _ as *const u32;
749 from_glib(ptr::read(ptr.offset(1)))
750 }
751 }
752
753 #[inline]
754 pub fn field_order(&self) -> crate::VideoFieldOrder {
755 unsafe {
756 let ptr = &self.0.ABI._gst_reserved as *const _ as *const i32;
757 from_glib(ptr::read(ptr.offset(2)))
758 }
759 }
760
761 #[inline]
762 pub fn has_alpha(&self) -> bool {
763 self.format_info().has_alpha()
764 }
765
766 #[inline]
767 pub fn is_gray(&self) -> bool {
768 self.format_info().is_gray()
769 }
770
771 #[inline]
772 pub fn is_rgb(&self) -> bool {
773 self.format_info().is_rgb()
774 }
775
776 #[inline]
777 pub fn is_yuv(&self) -> bool {
778 self.format_info().is_yuv()
779 }
780
781 #[inline]
782 pub fn is_interlaced(&self) -> bool {
783 self.interlace_mode() != crate::VideoInterlaceMode::Progressive
784 }
785
786 #[inline]
787 pub fn n_planes(&self) -> u32 {
788 self.format_info().n_planes()
789 }
790
791 #[inline]
792 pub fn n_components(&self) -> u32 {
793 self.format_info().n_components()
794 }
795
796 #[doc(alias = "gst_video_info_convert")]
797 pub fn convert<U: gst::format::SpecificFormattedValueFullRange>(
798 &self,
799 src_val: impl gst::format::FormattedValue,
800 ) -> Option<U> {
801 skip_assert_initialized!();
802 unsafe {
803 let mut dest_val = mem::MaybeUninit::uninit();
804 if from_glib(ffi::gst_video_info_convert(
805 &self.0 as *const _ as *mut _,
806 src_val.format().into_glib(),
807 src_val.into_raw_value(),
808 U::default_format().into_glib(),
809 dest_val.as_mut_ptr(),
810 )) {
811 Some(U::from_raw(U::default_format(), dest_val.assume_init()))
812 } else {
813 None
814 }
815 }
816 }
817
818 pub fn convert_generic(
819 &self,
820 src_val: impl gst::format::FormattedValue,
821 dest_fmt: gst::Format,
822 ) -> Option<gst::GenericFormattedValue> {
823 skip_assert_initialized!();
824 unsafe {
825 let mut dest_val = mem::MaybeUninit::uninit();
826 if from_glib(ffi::gst_video_info_convert(
827 &self.0 as *const _ as *mut _,
828 src_val.format().into_glib(),
829 src_val.into_raw_value(),
830 dest_fmt.into_glib(),
831 dest_val.as_mut_ptr(),
832 )) {
833 Some(gst::GenericFormattedValue::new(
834 dest_fmt,
835 dest_val.assume_init(),
836 ))
837 } else {
838 None
839 }
840 }
841 }
842
843 #[doc(alias = "gst_video_info_align")]
844 pub fn align(&mut self, align: &mut crate::VideoAlignment) -> Result<(), glib::BoolError> {
845 unsafe {
846 glib::result_from_gboolean!(
847 ffi::gst_video_info_align(&mut self.0, &mut align.0,),
848 "Failed to align VideoInfo"
849 )
850 }
851 }
852
853 #[cfg(feature = "v1_18")]
854 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
855 #[doc(alias = "gst_video_info_align_full")]
856 pub fn align_full(
857 &mut self,
858 align: &mut crate::VideoAlignment,
859 ) -> Result<[usize; crate::VIDEO_MAX_PLANES], glib::BoolError> {
860 let mut plane_size = [0; crate::VIDEO_MAX_PLANES];
861
862 unsafe {
863 glib::result_from_gboolean!(
864 ffi::gst_video_info_align_full(&mut self.0, &mut align.0, plane_size.as_mut_ptr()),
865 "Failed to align VideoInfo"
866 )?;
867 }
868
869 Ok(plane_size)
870 }
871
872 #[doc(alias = "gst_video_color_range_offsets")]
873 #[inline]
874 pub fn range_offsets(&self, range: crate::VideoColorRange) -> ([i32; 4], [i32; 4]) {
875 self.format_info().range_offsets(range)
876 }
877}
878
879impl PartialEq for VideoInfo {
880 #[doc(alias = "gst_video_info_is_equal")]
881 fn eq(&self, other: &Self) -> bool {
882 unsafe { from_glib(val:ffi::gst_video_info_is_equal(&self.0, &other.0)) }
883 }
884}
885
886impl Eq for VideoInfo {}
887
888unsafe impl Send for VideoInfo {}
889unsafe impl Sync for VideoInfo {}
890
891impl glib::types::StaticType for VideoInfo {
892 #[inline]
893 fn static_type() -> glib::types::Type {
894 unsafe { glib::translate::from_glib(val:ffi::gst_video_info_get_type()) }
895 }
896}
897
898impl glib::value::ValueType for VideoInfo {
899 type Type = Self;
900}
901
902#[doc(hidden)]
903unsafe impl<'a> glib::value::FromValue<'a> for VideoInfo {
904 type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
905
906 unsafe fn from_value(value: &'a glib::Value) -> Self {
907 skip_assert_initialized!();
908 from_glib_none(
909 ptr:glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut ffi::GstVideoInfo
910 )
911 }
912}
913
914#[doc(hidden)]
915impl glib::value::ToValue for VideoInfo {
916 fn to_value(&self) -> glib::Value {
917 let mut value: Value = glib::Value::for_value_type::<Self>();
918 unsafe {
919 glib::gobject_ffi::g_value_set_boxed(
920 value:value.to_glib_none_mut().0,
921 self.to_glib_none().0 as *mut _,
922 )
923 }
924 value
925 }
926
927 fn value_type(&self) -> glib::Type {
928 Self::static_type()
929 }
930}
931
932#[doc(hidden)]
933impl glib::value::ToValueOptional for VideoInfo {
934 fn to_value_optional(s: Option<&Self>) -> glib::Value {
935 skip_assert_initialized!();
936 let mut value: Value = glib::Value::for_value_type::<Self>();
937 unsafe {
938 glib::gobject_ffi::g_value_set_boxed(
939 value:value.to_glib_none_mut().0,
940 v_boxed:s.to_glib_none().0 as *mut _,
941 )
942 }
943 value
944 }
945}
946
947#[doc(hidden)]
948impl From<VideoInfo> for glib::Value {
949 fn from(v: VideoInfo) -> glib::Value {
950 skip_assert_initialized!();
951 glib::value::ToValue::to_value(&v)
952 }
953}
954
955#[doc(hidden)]
956impl glib::translate::Uninitialized for VideoInfo {
957 #[inline]
958 unsafe fn uninitialized() -> Self {
959 mem::zeroed()
960 }
961}
962
963#[doc(hidden)]
964impl glib::translate::GlibPtrDefault for VideoInfo {
965 type GlibType = *mut ffi::GstVideoInfo;
966}
967
968#[doc(hidden)]
969impl<'a> glib::translate::ToGlibPtr<'a, *const ffi::GstVideoInfo> for VideoInfo {
970 type Storage = PhantomData<&'a Self>;
971
972 #[inline]
973 fn to_glib_none(&'a self) -> glib::translate::Stash<'a, *const ffi::GstVideoInfo, Self> {
974 glib::translate::Stash(&self.0, PhantomData)
975 }
976
977 fn to_glib_full(&self) -> *const ffi::GstVideoInfo {
978 unimplemented!()
979 }
980}
981
982#[doc(hidden)]
983impl glib::translate::FromGlibPtrNone<*const ffi::GstVideoInfo> for VideoInfo {
984 #[inline]
985 unsafe fn from_glib_none(ptr: *const ffi::GstVideoInfo) -> Self {
986 Self(ptr::read(src:ptr))
987 }
988}
989
990#[doc(hidden)]
991impl glib::translate::FromGlibPtrNone<*mut ffi::GstVideoInfo> for VideoInfo {
992 #[inline]
993 unsafe fn from_glib_none(ptr: *mut ffi::GstVideoInfo) -> Self {
994 Self(ptr::read(src:ptr))
995 }
996}
997
998#[doc(hidden)]
999impl glib::translate::FromGlibPtrFull<*mut ffi::GstVideoInfo> for VideoInfo {
1000 #[inline]
1001 unsafe fn from_glib_full(ptr: *mut ffi::GstVideoInfo) -> Self {
1002 let info: VideoInfo = from_glib_none(ptr);
1003 glib::ffi::g_free(mem:ptr as *mut _);
1004 info
1005 }
1006}
1007
1008impl crate::VideoFieldOrder {
1009 #[doc(alias = "gst_video_field_order_to_string")]
1010 pub fn to_str<'a>(self) -> &'a str {
1011 use std::ffi::CStr;
1012
1013 if self == Self::Unknown {
1014 return "UNKNOWN";
1015 }
1016 unsafe {
1017 CStr::from_ptr(
1018 ffi::gst_video_field_order_to_string(self.into_glib())
1019 .as_ref()
1020 .expect("gst_video_field_order_to_string returned NULL"),
1021 )
1022 .to_str()
1023 .expect(msg:"gst_video_field_order_to_string returned an invalid string")
1024 }
1025 }
1026}
1027
1028impl str::FromStr for crate::VideoFieldOrder {
1029 type Err = glib::error::BoolError;
1030
1031 fn from_str(s: &str) -> Result<Self, Self::Err> {
1032 skip_assert_initialized!();
1033
1034 let fmt: VideoFieldOrder = Self::from_string(order:s);
1035 if fmt == Self::Unknown {
1036 Err(glib::bool_error!(
1037 "Failed to parse video field order from string"
1038 ))
1039 } else {
1040 Ok(fmt)
1041 }
1042 }
1043}
1044
1045impl str::FromStr for crate::VideoInterlaceMode {
1046 type Err = glib::error::BoolError;
1047
1048 fn from_str(s: &str) -> Result<Self, Self::Err> {
1049 skip_assert_initialized!();
1050
1051 let fmt: VideoInterlaceMode = Self::from_string(mode:s);
1052 Ok(fmt)
1053 }
1054}
1055
1056#[cfg(test)]
1057mod tests {
1058 use super::*;
1059
1060 #[test]
1061 fn test_new() {
1062 gst::init().unwrap();
1063
1064 let info = VideoInfo::builder(crate::VideoFormat::I420, 320, 240)
1065 .build()
1066 .unwrap();
1067 assert_eq!(info.format(), crate::VideoFormat::I420);
1068 assert_eq!(info.width(), 320);
1069 assert_eq!(info.height(), 240);
1070 assert_eq!(info.size(), 320 * 240 + 2 * 160 * 120);
1071 assert_eq!(info.multiview_mode(), crate::VideoMultiviewMode::None);
1072 assert_eq!(&info.offset(), &[0, 320 * 240, 320 * 240 + 160 * 120]);
1073 assert_eq!(&info.stride(), &[320, 160, 160]);
1074
1075 let offsets = [0, 640 * 240 + 16, 640 * 240 + 16 + 320 * 120 + 16];
1076 let strides = [640, 320, 320];
1077 let info = VideoInfo::builder(crate::VideoFormat::I420, 320, 240)
1078 .offset(&offsets)
1079 .stride(&strides)
1080 .size(640 * 240 + 16 + 320 * 120 + 16 + 320 * 120 + 16)
1081 .multiview_mode(crate::VideoMultiviewMode::SideBySide)
1082 .build()
1083 .unwrap();
1084 assert_eq!(info.format(), crate::VideoFormat::I420);
1085 assert_eq!(info.width(), 320);
1086 assert_eq!(info.height(), 240);
1087 assert_eq!(
1088 info.size(),
1089 640 * 240 + 16 + 320 * 120 + 16 + 320 * 120 + 16
1090 );
1091 assert_eq!(info.multiview_mode(), crate::VideoMultiviewMode::SideBySide);
1092 assert_eq!(
1093 &info.offset(),
1094 &[0, 640 * 240 + 16, 640 * 240 + 16 + 320 * 120 + 16]
1095 );
1096 assert_eq!(&info.stride(), &[640, 320, 320]);
1097 }
1098
1099 #[test]
1100 fn test_from_to_caps() {
1101 gst::init().unwrap();
1102
1103 let caps = crate::VideoCapsBuilder::new()
1104 .format(crate::VideoFormat::I420)
1105 .width(320)
1106 .height(240)
1107 .framerate((30, 1).into())
1108 .pixel_aspect_ratio((1, 1).into())
1109 .field("interlace-mode", "progressive")
1110 .field("chroma-site", "mpeg2")
1111 .field("colorimetry", "bt709")
1112 .build();
1113 let info = VideoInfo::from_caps(&caps).unwrap();
1114 assert_eq!(info.format(), crate::VideoFormat::I420);
1115 assert_eq!(info.width(), 320);
1116 assert_eq!(info.height(), 240);
1117 assert_eq!(info.fps(), gst::Fraction::new(30, 1));
1118 assert_eq!(
1119 info.interlace_mode(),
1120 crate::VideoInterlaceMode::Progressive
1121 );
1122 assert_eq!(info.chroma_site(), crate::VideoChromaSite::MPEG2);
1123 assert_eq!(info.colorimetry(), "bt709".parse().unwrap());
1124
1125 let caps2 = info.to_caps().unwrap();
1126 assert_eq!(caps, caps2);
1127
1128 let info2 = VideoInfo::from_caps(&caps2).unwrap();
1129 assert!(info == info2);
1130 }
1131
1132 #[test]
1133 fn test_video_align() {
1134 gst::init().unwrap();
1135
1136 let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv16, 1920, 1080)
1137 .build()
1138 .expect("Failed to create VideoInfo");
1139
1140 assert_eq!(info.stride(), [1920, 1920]);
1141 assert_eq!(info.offset(), [0, 2_073_600]);
1142
1143 let mut align = crate::VideoAlignment::new(0, 0, 0, 8, &[0; VIDEO_MAX_PLANES]);
1144 info.align(&mut align).unwrap();
1145
1146 assert_eq!(info.stride(), [1928, 1928]);
1147 assert_eq!(info.offset(), [0, 2_082_240]);
1148
1149 #[cfg(feature = "v1_18")]
1150 {
1151 let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv16, 1920, 1080)
1152 .build()
1153 .expect("Failed to create VideoInfo");
1154
1155 let mut align = crate::VideoAlignment::new(0, 0, 0, 8, &[0; VIDEO_MAX_PLANES]);
1156 let plane_size = info.align_full(&mut align).unwrap();
1157 assert_eq!(plane_size, [2082240, 2082240, 0, 0]);
1158 }
1159 }
1160
1161 #[test]
1162 fn test_display() {
1163 gst::init().unwrap();
1164
1165 format!("{}", "sRGB".parse::<crate::VideoColorimetry>().unwrap());
1166 format!("{}", crate::VideoFieldOrder::TopFieldFirst);
1167 format!("{}", crate::VideoInterlaceMode::Progressive);
1168 }
1169}
1170