1use std::{fmt, ptr};
4
5use crate::ffi;
6use glib::translate::*;
7use gst::prelude::*;
8
9#[repr(transparent)]
10#[doc(alias = "GstVideoMeta")]
11pub struct VideoMeta(ffi::GstVideoMeta);
12
13unsafe impl Send for VideoMeta {}
14unsafe impl Sync for VideoMeta {}
15
16impl VideoMeta {
17 #[doc(alias = "gst_buffer_add_video_meta")]
18 pub fn add(
19 buffer: &mut gst::BufferRef,
20 video_frame_flags: crate::VideoFrameFlags,
21 format: crate::VideoFormat,
22 width: u32,
23 height: u32,
24 ) -> Result<gst::MetaRefMut<'_, Self, gst::meta::Standalone>, glib::BoolError> {
25 skip_assert_initialized!();
26
27 if format == crate::VideoFormat::Unknown || format == crate::VideoFormat::Encoded {
28 return Err(glib::bool_error!("Unsupported video format {}", format));
29 }
30
31 let info = crate::VideoInfo::builder(format, width, height).build()?;
32
33 if !info.is_valid() {
34 return Err(glib::bool_error!("Invalid video info"));
35 }
36
37 if buffer.size() < info.size() {
38 return Err(glib::bool_error!(
39 "Buffer smaller than required frame size ({} < {})",
40 buffer.size(),
41 info.size()
42 ));
43 }
44
45 unsafe {
46 let meta = ffi::gst_buffer_add_video_meta(
47 buffer.as_mut_ptr(),
48 video_frame_flags.into_glib(),
49 format.into_glib(),
50 width,
51 height,
52 );
53
54 if meta.is_null() {
55 return Err(glib::bool_error!("Failed to add video meta"));
56 }
57
58 Ok(Self::from_mut_ptr(buffer, meta))
59 }
60 }
61
62 pub fn add_full<'a>(
63 buffer: &'a mut gst::BufferRef,
64 video_frame_flags: crate::VideoFrameFlags,
65 format: crate::VideoFormat,
66 width: u32,
67 height: u32,
68 offset: &[usize],
69 stride: &[i32],
70 ) -> Result<gst::MetaRefMut<'a, Self, gst::meta::Standalone>, glib::BoolError> {
71 skip_assert_initialized!();
72
73 if format == crate::VideoFormat::Unknown || format == crate::VideoFormat::Encoded {
74 return Err(glib::bool_error!("Unsupported video format {}", format));
75 }
76
77 let n_planes = offset.len() as u32;
78 let info_builder = crate::VideoInfo::builder(format, width, height)
79 .offset(offset)
80 .stride(stride);
81
82 #[cfg(feature = "v1_16")]
83 let info_builder = info_builder.interlace_mode_if(
84 crate::VideoInterlaceMode::Alternate,
85 video_frame_flags.contains(crate::VideoFrameFlags::ONEFIELD),
86 );
87
88 let info = info_builder.build()?;
89
90 if !info.is_valid() {
91 return Err(glib::bool_error!("Invalid video info"));
92 }
93
94 if buffer.size() < info.size() {
95 return Err(glib::bool_error!(
96 "Buffer smaller than required frame size ({} < {})",
97 buffer.size(),
98 info.size()
99 ));
100 }
101
102 unsafe {
103 let meta = ffi::gst_buffer_add_video_meta_full(
104 buffer.as_mut_ptr(),
105 video_frame_flags.into_glib(),
106 format.into_glib(),
107 width,
108 height,
109 n_planes,
110 offset.as_ptr() as *mut _,
111 stride.as_ptr() as *mut _,
112 );
113
114 if meta.is_null() {
115 return Err(glib::bool_error!("Failed to add video meta"));
116 }
117
118 Ok(Self::from_mut_ptr(buffer, meta))
119 }
120 }
121
122 #[doc(alias = "get_flags")]
123 #[inline]
124 pub fn video_frame_flags(&self) -> crate::VideoFrameFlags {
125 unsafe { from_glib(self.0.flags) }
126 }
127
128 #[doc(alias = "get_format")]
129 #[inline]
130 pub fn format(&self) -> crate::VideoFormat {
131 unsafe { from_glib(self.0.format) }
132 }
133
134 #[doc(alias = "get_id")]
135 #[inline]
136 pub fn id(&self) -> i32 {
137 self.0.id
138 }
139
140 #[doc(alias = "get_width")]
141 #[inline]
142 pub fn width(&self) -> u32 {
143 self.0.width
144 }
145
146 #[doc(alias = "get_height")]
147 #[inline]
148 pub fn height(&self) -> u32 {
149 self.0.height
150 }
151
152 #[doc(alias = "get_n_planes")]
153 #[inline]
154 pub fn n_planes(&self) -> u32 {
155 self.0.n_planes
156 }
157
158 #[doc(alias = "get_offset")]
159 #[inline]
160 pub fn offset(&self) -> &[usize] {
161 &self.0.offset[0..(self.0.n_planes as usize)]
162 }
163
164 #[doc(alias = "get_stride")]
165 #[inline]
166 pub fn stride(&self) -> &[i32] {
167 &self.0.stride[0..(self.0.n_planes as usize)]
168 }
169
170 #[cfg(feature = "v1_18")]
171 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
172 #[doc(alias = "get_alignment")]
173 #[inline]
174 pub fn alignment(&self) -> crate::VideoAlignment {
175 crate::VideoAlignment::new(
176 self.0.alignment.padding_top,
177 self.0.alignment.padding_bottom,
178 self.0.alignment.padding_left,
179 self.0.alignment.padding_right,
180 &self.0.alignment.stride_align,
181 )
182 }
183
184 #[cfg(feature = "v1_18")]
185 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
186 #[doc(alias = "get_plane_size")]
187 #[doc(alias = "gst_video_meta_get_plane_size")]
188 pub fn plane_size(&self) -> Result<[usize; crate::VIDEO_MAX_PLANES], glib::BoolError> {
189 let mut plane_size = [0; crate::VIDEO_MAX_PLANES];
190
191 unsafe {
192 glib::result_from_gboolean!(
193 ffi::gst_video_meta_get_plane_size(mut_override(&self.0), &mut plane_size,),
194 "Failed to get plane size"
195 )?;
196 }
197
198 Ok(plane_size)
199 }
200
201 #[cfg(feature = "v1_18")]
202 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
203 #[doc(alias = "get_plane_height")]
204 #[doc(alias = "gst_video_meta_get_plane_height")]
205 pub fn plane_height(&self) -> Result<[u32; crate::VIDEO_MAX_PLANES], glib::BoolError> {
206 let mut plane_height = [0; crate::VIDEO_MAX_PLANES];
207
208 unsafe {
209 glib::result_from_gboolean!(
210 ffi::gst_video_meta_get_plane_height(mut_override(&self.0), &mut plane_height,),
211 "Failed to get plane height"
212 )?;
213 }
214
215 Ok(plane_height)
216 }
217
218 #[cfg(feature = "v1_18")]
219 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
220 #[doc(alias = "gst_video_meta_set_alignment")]
221 pub fn set_alignment(
222 &mut self,
223 alignment: &crate::VideoAlignment,
224 ) -> Result<(), glib::BoolError> {
225 unsafe {
226 glib::result_from_gboolean!(
227 ffi::gst_video_meta_set_alignment(&mut self.0, alignment.0),
228 "Failed to set alignment on VideoMeta"
229 )
230 }
231 }
232}
233
234unsafe impl MetaAPI for VideoMeta {
235 type GstType = ffi::GstVideoMeta;
236
237 #[doc(alias = "gst_video_meta_api_get_type")]
238 #[inline]
239 fn meta_api() -> glib::Type {
240 unsafe { from_glib(ffi::gst_video_meta_api_get_type()) }
241 }
242}
243
244impl fmt::Debug for VideoMeta {
245 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246 f.debug_struct("VideoMeta")
247 .field("id", &self.id())
248 .field("video_frame_flags", &self.video_frame_flags())
249 .field("format", &self.format())
250 .field("width", &self.width())
251 .field("height", &self.height())
252 .field("n_planes", &self.n_planes())
253 .field("offset", &self.offset())
254 .field("stride", &self.stride())
255 .finish()
256 }
257}
258
259#[repr(transparent)]
260#[doc(alias = "GstVideoCropMeta")]
261pub struct VideoCropMeta(ffi::GstVideoCropMeta);
262
263unsafe impl Send for VideoCropMeta {}
264unsafe impl Sync for VideoCropMeta {}
265
266impl VideoCropMeta {
267 #[doc(alias = "gst_buffer_add_meta")]
268 pub fn add(
269 buffer: &mut gst::BufferRef,
270 rect: (u32, u32, u32, u32),
271 ) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
272 skip_assert_initialized!();
273 unsafe {
274 let meta = gst::ffi::gst_buffer_add_meta(
275 buffer.as_mut_ptr(),
276 ffi::gst_video_crop_meta_get_info(),
277 ptr::null_mut(),
278 ) as *mut ffi::GstVideoCropMeta;
279
280 {
281 let meta = &mut *meta;
282 meta.x = rect.0;
283 meta.y = rect.1;
284 meta.width = rect.2;
285 meta.height = rect.3;
286 }
287
288 Self::from_mut_ptr(buffer, meta)
289 }
290 }
291
292 #[doc(alias = "get_rect")]
293 #[inline]
294 pub fn rect(&self) -> (u32, u32, u32, u32) {
295 (self.0.x, self.0.y, self.0.width, self.0.height)
296 }
297
298 #[inline]
299 pub fn set_rect(&mut self, rect: (u32, u32, u32, u32)) {
300 self.0.x = rect.0;
301 self.0.y = rect.1;
302 self.0.width = rect.2;
303 self.0.height = rect.3;
304 }
305}
306
307unsafe impl MetaAPI for VideoCropMeta {
308 type GstType = ffi::GstVideoCropMeta;
309
310 #[doc(alias = "gst_video_crop_meta_api_get_type")]
311 #[inline]
312 fn meta_api() -> glib::Type {
313 unsafe { from_glib(ffi::gst_video_crop_meta_api_get_type()) }
314 }
315}
316
317impl fmt::Debug for VideoCropMeta {
318 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
319 f.debug_struct("VideoCropMeta")
320 .field("rect", &self.rect())
321 .finish()
322 }
323}
324
325#[repr(transparent)]
326#[doc(alias = "GstVideoRegionOfInterestMeta")]
327pub struct VideoRegionOfInterestMeta(ffi::GstVideoRegionOfInterestMeta);
328
329unsafe impl Send for VideoRegionOfInterestMeta {}
330unsafe impl Sync for VideoRegionOfInterestMeta {}
331
332impl VideoRegionOfInterestMeta {
333 #[doc(alias = "gst_buffer_add_video_region_of_interest_meta")]
334 pub fn add<'a>(
335 buffer: &'a mut gst::BufferRef,
336 roi_type: &str,
337 rect: (u32, u32, u32, u32),
338 ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
339 skip_assert_initialized!();
340 unsafe {
341 let meta = ffi::gst_buffer_add_video_region_of_interest_meta(
342 buffer.as_mut_ptr(),
343 roi_type.to_glib_none().0,
344 rect.0,
345 rect.1,
346 rect.2,
347 rect.3,
348 );
349
350 Self::from_mut_ptr(buffer, meta)
351 }
352 }
353
354 #[doc(alias = "get_rect")]
355 #[inline]
356 pub fn rect(&self) -> (u32, u32, u32, u32) {
357 (self.0.x, self.0.y, self.0.w, self.0.h)
358 }
359
360 #[doc(alias = "get_id")]
361 #[inline]
362 pub fn id(&self) -> i32 {
363 self.0.id
364 }
365
366 #[doc(alias = "get_parent_id")]
367 #[inline]
368 pub fn parent_id(&self) -> i32 {
369 self.0.parent_id
370 }
371
372 #[doc(alias = "get_roi_type")]
373 #[inline]
374 pub fn roi_type<'a>(&self) -> &'a str {
375 unsafe { glib::Quark::from_glib(self.0.roi_type).as_str() }
376 }
377
378 #[doc(alias = "get_params")]
379 pub fn params(&self) -> ParamsIter<'_> {
380 ParamsIter {
381 _meta: self,
382 list: ptr::NonNull::new(self.0.params),
383 }
384 }
385
386 #[doc(alias = "get_param")]
387 #[inline]
388 pub fn param<'b>(&'b self, name: &str) -> Option<&'b gst::StructureRef> {
389 self.params().find(|s| s.name() == name)
390 }
391
392 #[inline]
393 pub fn set_rect(&mut self, rect: (u32, u32, u32, u32)) {
394 self.0.x = rect.0;
395 self.0.y = rect.1;
396 self.0.w = rect.2;
397 self.0.h = rect.3;
398 }
399
400 #[inline]
401 pub fn set_id(&mut self, id: i32) {
402 self.0.id = id
403 }
404
405 #[inline]
406 pub fn set_parent_id(&mut self, id: i32) {
407 self.0.parent_id = id
408 }
409
410 #[doc(alias = "gst_video_region_of_interest_meta_add_param")]
411 pub fn add_param(&mut self, s: gst::Structure) {
412 unsafe {
413 ffi::gst_video_region_of_interest_meta_add_param(&mut self.0, s.into_glib_ptr());
414 }
415 }
416}
417
418#[must_use = "iterators are lazy and do nothing unless consumed"]
419pub struct ParamsIter<'a> {
420 _meta: &'a VideoRegionOfInterestMeta,
421 list: Option<ptr::NonNull<glib::ffi::GList>>,
422}
423
424impl<'a> Iterator for ParamsIter<'a> {
425 type Item = &'a gst::StructureRef;
426
427 fn next(&mut self) -> Option<&'a gst::StructureRef> {
428 match self.list {
429 None => None,
430 Some(list) => unsafe {
431 self.list = ptr::NonNull::new(list.as_ref().next);
432 let data = list.as_ref().data;
433
434 let s = gst::StructureRef::from_glib_borrow(data as *const gst::ffi::GstStructure);
435
436 Some(s)
437 },
438 }
439 }
440}
441
442impl std::iter::FusedIterator for ParamsIter<'_> {}
443
444unsafe impl MetaAPI for VideoRegionOfInterestMeta {
445 type GstType = ffi::GstVideoRegionOfInterestMeta;
446
447 #[doc(alias = "gst_video_region_of_interest_meta_api_get_type")]
448 #[inline]
449 fn meta_api() -> glib::Type {
450 unsafe { from_glib(ffi::gst_video_region_of_interest_meta_api_get_type()) }
451 }
452}
453
454impl fmt::Debug for VideoRegionOfInterestMeta {
455 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
456 f.debug_struct("VideoRegionOfInterestMeta")
457 .field("roi_type", &self.roi_type())
458 .field("rect", &self.rect())
459 .field("id", &self.id())
460 .field("parent_id", &self.parent_id())
461 .field("params", &self.params().collect::<Vec<_>>())
462 .finish()
463 }
464}
465
466#[repr(transparent)]
467#[doc(alias = "GstVideoAffineTransformationMeta")]
468pub struct VideoAffineTransformationMeta(ffi::GstVideoAffineTransformationMeta);
469
470unsafe impl Send for VideoAffineTransformationMeta {}
471unsafe impl Sync for VideoAffineTransformationMeta {}
472
473impl VideoAffineTransformationMeta {
474 #[doc(alias = "gst_buffer_add_meta")]
475 pub fn add<'a>(
476 buffer: &'a mut gst::BufferRef,
477 matrix: Option<&[[f32; 4]; 4]>,
478 ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
479 skip_assert_initialized!();
480 unsafe {
481 let meta = gst::ffi::gst_buffer_add_meta(
482 buffer.as_mut_ptr(),
483 ffi::gst_video_affine_transformation_meta_get_info(),
484 ptr::null_mut(),
485 ) as *mut ffi::GstVideoAffineTransformationMeta;
486
487 if let Some(matrix) = matrix {
488 let meta = &mut *meta;
489 for (i, o) in Iterator::zip(matrix.iter().flatten(), meta.matrix.iter_mut()) {
490 *o = *i;
491 }
492 }
493
494 Self::from_mut_ptr(buffer, meta)
495 }
496 }
497
498 #[doc(alias = "get_matrix")]
499 #[inline]
500 pub fn matrix(&self) -> &[[f32; 4]; 4] {
501 unsafe { &*(&self.0.matrix as *const [f32; 16] as *const [[f32; 4]; 4]) }
502 }
503
504 #[inline]
505 pub fn set_matrix(&mut self, matrix: &[[f32; 4]; 4]) {
506 for (i, o) in Iterator::zip(matrix.iter().flatten(), self.0.matrix.iter_mut()) {
507 *o = *i;
508 }
509 }
510
511 #[doc(alias = "gst_video_affine_transformation_meta_apply_matrix")]
512 pub fn apply_matrix(&mut self, matrix: &[[f32; 4]; 4]) {
513 unsafe {
514 ffi::gst_video_affine_transformation_meta_apply_matrix(
515 &mut self.0,
516 matrix as *const [[f32; 4]; 4] as *const [f32; 16],
517 );
518 }
519 }
520}
521
522unsafe impl MetaAPI for VideoAffineTransformationMeta {
523 type GstType = ffi::GstVideoAffineTransformationMeta;
524
525 #[doc(alias = "gst_video_affine_transformation_meta_api_get_type")]
526 #[inline]
527 fn meta_api() -> glib::Type {
528 unsafe { from_glib(ffi::gst_video_affine_transformation_meta_api_get_type()) }
529 }
530}
531
532impl fmt::Debug for VideoAffineTransformationMeta {
533 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
534 f.debug_struct("VideoAffineTransformationMeta")
535 .field("matrix", &self.matrix())
536 .finish()
537 }
538}
539
540#[repr(transparent)]
541#[doc(alias = "GstVideoOverlayCompositionMeta")]
542pub struct VideoOverlayCompositionMeta(ffi::GstVideoOverlayCompositionMeta);
543
544unsafe impl Send for VideoOverlayCompositionMeta {}
545unsafe impl Sync for VideoOverlayCompositionMeta {}
546
547impl VideoOverlayCompositionMeta {
548 #[doc(alias = "gst_buffer_add_video_overlay_composition_meta")]
549 pub fn add<'a>(
550 buffer: &'a mut gst::BufferRef,
551 overlay: &crate::VideoOverlayComposition,
552 ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
553 skip_assert_initialized!();
554 unsafe {
555 let meta = ffi::gst_buffer_add_video_overlay_composition_meta(
556 buffer.as_mut_ptr(),
557 overlay.as_mut_ptr(),
558 );
559
560 Self::from_mut_ptr(buffer, meta)
561 }
562 }
563
564 #[doc(alias = "get_overlay")]
565 #[inline]
566 pub fn overlay(&self) -> &crate::VideoOverlayCompositionRef {
567 unsafe { crate::VideoOverlayCompositionRef::from_ptr(self.0.overlay) }
568 }
569
570 #[doc(alias = "get_overlay_owned")]
571 #[inline]
572 pub fn overlay_owned(&self) -> crate::VideoOverlayComposition {
573 unsafe { from_glib_none(self.overlay().as_ptr()) }
574 }
575
576 #[inline]
577 pub fn set_overlay(&mut self, overlay: &crate::VideoOverlayComposition) {
578 #![allow(clippy::cast_ptr_alignment)]
579 unsafe {
580 gst::ffi::gst_mini_object_unref(self.0.overlay as *mut _);
581 self.0.overlay =
582 gst::ffi::gst_mini_object_ref(overlay.as_mut_ptr() as *mut _) as *mut _;
583 }
584 }
585}
586
587unsafe impl MetaAPI for VideoOverlayCompositionMeta {
588 type GstType = ffi::GstVideoOverlayCompositionMeta;
589
590 #[doc(alias = "gst_video_overlay_composition_meta_api_get_type")]
591 #[inline]
592 fn meta_api() -> glib::Type {
593 unsafe { from_glib(ffi::gst_video_overlay_composition_meta_api_get_type()) }
594 }
595}
596
597impl fmt::Debug for VideoOverlayCompositionMeta {
598 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
599 f.debug_struct("VideoOverlayCompositionMeta")
600 .field("overlay", &self.overlay())
601 .finish()
602 }
603}
604
605#[cfg(feature = "v1_16")]
606#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
607#[repr(transparent)]
608#[doc(alias = "GstVideoCaptionMeta")]
609pub struct VideoCaptionMeta(ffi::GstVideoCaptionMeta);
610
611#[cfg(feature = "v1_16")]
612#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
613unsafe impl Send for VideoCaptionMeta {}
614#[cfg(feature = "v1_16")]
615#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
616unsafe impl Sync for VideoCaptionMeta {}
617
618#[cfg(feature = "v1_16")]
619#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
620impl VideoCaptionMeta {
621 #[doc(alias = "gst_buffer_add_video_caption_meta")]
622 pub fn add<'a>(
623 buffer: &'a mut gst::BufferRef,
624 caption_type: crate::VideoCaptionType,
625 data: &[u8],
626 ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
627 skip_assert_initialized!();
628 assert!(!data.is_empty());
629 unsafe {
630 let meta = ffi::gst_buffer_add_video_caption_meta(
631 buffer.as_mut_ptr(),
632 caption_type.into_glib(),
633 data.as_ptr(),
634 data.len(),
635 );
636
637 Self::from_mut_ptr(buffer, meta)
638 }
639 }
640
641 #[doc(alias = "get_caption_type")]
642 #[inline]
643 pub fn caption_type(&self) -> crate::VideoCaptionType {
644 unsafe { from_glib(self.0.caption_type) }
645 }
646
647 #[doc(alias = "get_data")]
648 #[inline]
649 pub fn data(&self) -> &[u8] {
650 if self.0.size == 0 {
651 return &[];
652 }
653 unsafe {
654 use std::slice;
655
656 slice::from_raw_parts(self.0.data, self.0.size)
657 }
658 }
659}
660
661#[cfg(feature = "v1_16")]
662#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
663unsafe impl MetaAPI for VideoCaptionMeta {
664 type GstType = ffi::GstVideoCaptionMeta;
665
666 #[doc(alias = "gst_video_caption_meta_api_get_type")]
667 #[inline]
668 fn meta_api() -> glib::Type {
669 unsafe { from_glib(ffi::gst_video_caption_meta_api_get_type()) }
670 }
671}
672
673#[cfg(feature = "v1_16")]
674#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
675impl fmt::Debug for VideoCaptionMeta {
676 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
677 f.debug_struct("VideoCaptionMeta")
678 .field("caption_type", &self.caption_type())
679 .field("data", &self.data())
680 .finish()
681 }
682}
683
684#[cfg(feature = "v1_18")]
685#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
686#[repr(transparent)]
687#[doc(alias = "GstVideoAFDMeta")]
688pub struct VideoAFDMeta(ffi::GstVideoAFDMeta);
689
690#[cfg(feature = "v1_18")]
691#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
692unsafe impl Send for VideoAFDMeta {}
693#[cfg(feature = "v1_18")]
694#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
695unsafe impl Sync for VideoAFDMeta {}
696
697#[cfg(feature = "v1_18")]
698#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
699impl VideoAFDMeta {
700 #[doc(alias = "gst_buffer_add_video_afd_meta")]
701 pub fn add(
702 buffer: &mut gst::BufferRef,
703 field: u8,
704 spec: crate::VideoAFDSpec,
705 afd: crate::VideoAFDValue,
706 ) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
707 skip_assert_initialized!();
708
709 unsafe {
710 let meta = ffi::gst_buffer_add_video_afd_meta(
711 buffer.as_mut_ptr(),
712 field,
713 spec.into_glib(),
714 afd.into_glib(),
715 );
716
717 Self::from_mut_ptr(buffer, meta)
718 }
719 }
720
721 #[doc(alias = "get_field")]
722 #[inline]
723 pub fn field(&self) -> u8 {
724 self.0.field
725 }
726
727 #[doc(alias = "get_spec")]
728 #[inline]
729 pub fn spec(&self) -> crate::VideoAFDSpec {
730 unsafe { from_glib(self.0.spec) }
731 }
732
733 #[doc(alias = "get_afd")]
734 #[inline]
735 pub fn afd(&self) -> crate::VideoAFDValue {
736 unsafe { from_glib(self.0.afd) }
737 }
738}
739
740#[cfg(feature = "v1_18")]
741#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
742unsafe impl MetaAPI for VideoAFDMeta {
743 type GstType = ffi::GstVideoAFDMeta;
744
745 #[doc(alias = "gst_video_afd_meta_api_get_type")]
746 #[inline]
747 fn meta_api() -> glib::Type {
748 unsafe { from_glib(ffi::gst_video_afd_meta_api_get_type()) }
749 }
750}
751
752#[cfg(feature = "v1_18")]
753#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
754impl fmt::Debug for VideoAFDMeta {
755 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
756 f.debug_struct("VideoAFDMeta")
757 .field("field", &self.field())
758 .field("spec", &self.spec())
759 .field("afd", &self.afd())
760 .finish()
761 }
762}
763
764#[cfg(feature = "v1_18")]
765#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
766#[repr(transparent)]
767#[doc(alias = "GstVideoBarMeta")]
768pub struct VideoBarMeta(ffi::GstVideoBarMeta);
769
770#[cfg(feature = "v1_18")]
771#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
772unsafe impl Send for VideoBarMeta {}
773#[cfg(feature = "v1_18")]
774#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
775unsafe impl Sync for VideoBarMeta {}
776
777#[cfg(feature = "v1_18")]
778#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
779impl VideoBarMeta {
780 #[doc(alias = "gst_buffer_add_video_bar_meta")]
781 pub fn add(
782 buffer: &mut gst::BufferRef,
783 field: u8,
784 is_letterbox: bool,
785 bar_data1: u32,
786 bar_data2: u32,
787 ) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
788 skip_assert_initialized!();
789
790 unsafe {
791 let meta = ffi::gst_buffer_add_video_bar_meta(
792 buffer.as_mut_ptr(),
793 field,
794 is_letterbox.into_glib(),
795 bar_data1,
796 bar_data2,
797 );
798
799 Self::from_mut_ptr(buffer, meta)
800 }
801 }
802
803 #[doc(alias = "get_field")]
804 #[inline]
805 pub fn field(&self) -> u8 {
806 self.0.field
807 }
808
809 #[inline]
810 pub fn is_letterbox(&self) -> bool {
811 unsafe { from_glib(self.0.is_letterbox) }
812 }
813
814 #[doc(alias = "get_bar_data1")]
815 #[inline]
816 pub fn bar_data1(&self) -> u32 {
817 self.0.bar_data1
818 }
819
820 #[doc(alias = "get_bar_data2")]
821 #[inline]
822 pub fn bar_data2(&self) -> u32 {
823 self.0.bar_data2
824 }
825}
826
827#[cfg(feature = "v1_18")]
828#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
829unsafe impl MetaAPI for VideoBarMeta {
830 type GstType = ffi::GstVideoBarMeta;
831
832 #[doc(alias = "gst_video_bar_meta_api_get_type")]
833 #[inline]
834 fn meta_api() -> glib::Type {
835 unsafe { from_glib(ffi::gst_video_bar_meta_api_get_type()) }
836 }
837}
838
839#[cfg(feature = "v1_18")]
840#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
841impl fmt::Debug for VideoBarMeta {
842 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
843 f.debug_struct("VideoBarMeta")
844 .field("field", &self.field())
845 .field("is_letterbox", &self.is_letterbox())
846 .field("bar_data1", &self.bar_data1())
847 .field("bar_data2", &self.bar_data2())
848 .finish()
849 }
850}
851
852#[cfg(feature = "v1_20")]
853#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
854#[repr(transparent)]
855#[doc(alias = "GstVideoCodecAlphaMeta")]
856pub struct VideoCodecAlphaMeta(ffi::GstVideoCodecAlphaMeta);
857
858#[cfg(feature = "v1_20")]
859#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
860unsafe impl Send for VideoCodecAlphaMeta {}
861#[cfg(feature = "v1_20")]
862#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
863unsafe impl Sync for VideoCodecAlphaMeta {}
864
865#[cfg(feature = "v1_20")]
866#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
867impl VideoCodecAlphaMeta {
868 #[doc(alias = "gst_buffer_add_video_codec_alpha_meta")]
869 pub fn add(
870 buffer: &mut gst::BufferRef,
871 alpha_buffer: gst::Buffer,
872 ) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
873 skip_assert_initialized!();
874 unsafe {
875 let meta = ffi::gst_buffer_add_video_codec_alpha_meta(
876 buffer.as_mut_ptr(),
877 alpha_buffer.to_glib_none().0,
878 );
879
880 Self::from_mut_ptr(buffer, meta)
881 }
882 }
883
884 #[inline]
885 pub fn alpha_buffer(&self) -> &gst::BufferRef {
886 unsafe { gst::BufferRef::from_ptr(self.0.buffer) }
887 }
888
889 #[inline]
890 pub fn alpha_buffer_owned(&self) -> gst::Buffer {
891 unsafe { from_glib_none(self.0.buffer) }
892 }
893}
894
895#[cfg(feature = "v1_20")]
896#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
897unsafe impl MetaAPI for VideoCodecAlphaMeta {
898 type GstType = ffi::GstVideoCodecAlphaMeta;
899
900 #[doc(alias = "gst_video_codec_alpha_meta_api_get_type")]
901 #[inline]
902 fn meta_api() -> glib::Type {
903 unsafe { from_glib(ffi::gst_video_codec_alpha_meta_api_get_type()) }
904 }
905}
906
907#[cfg(feature = "v1_20")]
908#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
909impl fmt::Debug for VideoCodecAlphaMeta {
910 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
911 f.debug_struct("VideoCodecAlphaMeta")
912 .field("buffer", &self.alpha_buffer())
913 .finish()
914 }
915}
916
917#[cfg(feature = "v1_22")]
918#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
919#[repr(transparent)]
920#[doc(alias = "GstVideoSEIUserDataUnregisteredMeta")]
921pub struct VideoSeiUserDataUnregisteredMeta(ffi::GstVideoSEIUserDataUnregisteredMeta);
922
923#[cfg(feature = "v1_22")]
924#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
925unsafe impl Send for VideoSeiUserDataUnregisteredMeta {}
926#[cfg(feature = "v1_22")]
927#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
928unsafe impl Sync for VideoSeiUserDataUnregisteredMeta {}
929
930#[cfg(feature = "v1_22")]
931#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
932impl VideoSeiUserDataUnregisteredMeta {
933 #[doc(alias = "gst_buffer_add_video_sei_user_data_unregistered_meta")]
934 pub fn add<'a>(
935 buffer: &'a mut gst::BufferRef,
936 uuid: &[u8; 16],
937 data: &[u8],
938 ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
939 skip_assert_initialized!();
940 assert!(!data.is_empty());
941 unsafe {
942 let meta = ffi::gst_buffer_add_video_sei_user_data_unregistered_meta(
943 buffer.as_mut_ptr(),
944 mut_override(uuid.as_ptr()),
945 mut_override(data.as_ptr()),
946 data.len(),
947 );
948
949 Self::from_mut_ptr(buffer, meta)
950 }
951 }
952
953 #[doc(alias = "get_data")]
954 #[inline]
955 pub fn data(&self) -> &[u8] {
956 if self.0.size == 0 {
957 return &[];
958 }
959 unsafe {
963 use std::slice;
964 slice::from_raw_parts(self.0.data, self.0.size)
965 }
966 }
967
968 #[doc(alias = "get_uuid")]
969 #[inline]
970 pub fn uuid(&self) -> [u8; 16] {
971 self.0.uuid
972 }
973}
974
975#[cfg(feature = "v1_22")]
976#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
977impl fmt::Debug for VideoSeiUserDataUnregisteredMeta {
978 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
979 f.debug_struct("VideoSeiUserDataUnregisteredMeta")
980 .field(
981 "uuid",
982 &format!("0x{:032X}", u128::from_be_bytes(self.uuid())),
983 )
984 .field("data", &self.data())
985 .finish()
986 }
987}
988
989#[cfg(feature = "v1_22")]
990#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
991unsafe impl MetaAPI for VideoSeiUserDataUnregisteredMeta {
992 type GstType = ffi::GstVideoSEIUserDataUnregisteredMeta;
993
994 #[doc(alias = "gst_video_sei_user_data_unregistered_meta_api_get_type")]
995 fn meta_api() -> glib::Type {
996 unsafe {
997 glib::translate::from_glib(ffi::gst_video_sei_user_data_unregistered_meta_api_get_type())
998 }
999 }
1000}
1001
1002#[cfg(feature = "v1_24")]
1003#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1004#[repr(transparent)]
1005#[doc(alias = "GstAncillaryMeta")]
1006pub struct AncillaryMeta(ffi::GstAncillaryMeta);
1007
1008#[cfg(feature = "v1_24")]
1009#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1010unsafe impl Send for AncillaryMeta {}
1011#[cfg(feature = "v1_24")]
1012#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1013unsafe impl Sync for AncillaryMeta {}
1014
1015#[cfg(feature = "v1_24")]
1016#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1017impl AncillaryMeta {
1018 #[doc(alias = "gst_buffer_add_ancillary_meta")]
1019 pub fn add(buffer: &mut gst::BufferRef) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
1020 skip_assert_initialized!();
1021 unsafe {
1022 let meta = ffi::gst_buffer_add_ancillary_meta(buffer.as_mut_ptr());
1023
1024 Self::from_mut_ptr(buffer, meta)
1025 }
1026 }
1027
1028 #[inline]
1029 pub fn field(&self) -> crate::AncillaryMetaField {
1030 unsafe { from_glib(self.0.field) }
1031 }
1032
1033 #[inline]
1034 pub fn set_field(&mut self, field: crate::AncillaryMetaField) {
1035 self.0.field = field.into_glib();
1036 }
1037
1038 #[inline]
1039 pub fn c_not_y_channel(&self) -> bool {
1040 unsafe { from_glib(self.0.c_not_y_channel) }
1041 }
1042
1043 #[inline]
1044 pub fn set_c_not_y_channel(&mut self, c_not_y_channel: bool) {
1045 self.0.c_not_y_channel = c_not_y_channel.into_glib();
1046 }
1047
1048 #[inline]
1049 pub fn line(&self) -> u16 {
1050 self.0.line
1051 }
1052
1053 #[inline]
1054 pub fn set_line(&mut self, line: u16) {
1055 self.0.line = line;
1056 }
1057
1058 #[inline]
1059 pub fn offset(&self) -> u16 {
1060 self.0.offset
1061 }
1062
1063 #[inline]
1064 pub fn set_offset(&mut self, offset: u16) {
1065 self.0.offset = offset;
1066 }
1067
1068 #[inline]
1069 pub fn did(&self) -> u16 {
1070 self.0.DID
1071 }
1072
1073 #[inline]
1074 pub fn set_did(&mut self, did: u16) {
1075 self.0.DID = did;
1076 }
1077
1078 #[inline]
1079 pub fn sdid_block_number(&self) -> u16 {
1080 self.0.SDID_block_number
1081 }
1082
1083 #[inline]
1084 pub fn set_sdid_block_number(&mut self, sdid_block_number: u16) {
1085 self.0.SDID_block_number = sdid_block_number;
1086 }
1087
1088 #[inline]
1089 pub fn data_count(&self) -> u16 {
1090 self.0.data_count
1091 }
1092
1093 #[inline]
1094 pub fn checksum(&self) -> u16 {
1095 self.0.checksum
1096 }
1097
1098 #[inline]
1099 pub fn set_checksum(&mut self, checksum: u16) {
1100 self.0.checksum = checksum;
1101 }
1102
1103 #[inline]
1104 pub fn data(&self) -> &[u16] {
1105 if self.0.data_count & 0xff == 0 {
1106 return &[];
1107 }
1108 unsafe {
1109 use std::slice;
1110
1111 slice::from_raw_parts(self.0.data, (self.0.data_count & 0xff) as usize)
1112 }
1113 }
1114
1115 #[inline]
1116 pub fn data_mut(&mut self) -> &mut [u16] {
1117 if self.0.data_count & 0xff == 0 {
1118 return &mut [];
1119 }
1120 unsafe {
1121 use std::slice;
1122
1123 slice::from_raw_parts_mut(self.0.data, (self.0.data_count & 0xff) as usize)
1124 }
1125 }
1126
1127 #[inline]
1128 pub fn set_data(&mut self, data: glib::Slice<u16>) {
1129 assert!(data.len() < 256);
1130 self.0.data_count = data.len() as u16;
1131 self.0.data = data.into_glib_ptr();
1132 }
1133
1134 #[inline]
1135 pub fn set_data_count_upper_two_bits(&mut self, upper_two_bits: u8) {
1136 assert!(upper_two_bits & !0x03 == 0);
1137 self.0.data_count = ((upper_two_bits as u16) << 8) | self.0.data_count & 0xff;
1138 }
1139}
1140
1141#[cfg(feature = "v1_24")]
1142#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1143unsafe impl MetaAPI for AncillaryMeta {
1144 type GstType = ffi::GstAncillaryMeta;
1145
1146 #[doc(alias = "gst_ancillary_meta_api_get_type")]
1147 #[inline]
1148 fn meta_api() -> glib::Type {
1149 unsafe { from_glib(ffi::gst_ancillary_meta_api_get_type()) }
1150 }
1151}
1152
1153#[cfg(feature = "v1_24")]
1154#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1155impl fmt::Debug for AncillaryMeta {
1156 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1157 f.debug_struct("AncillaryMeta")
1158 .field("field", &self.field())
1159 .field("c_not_y_channel", &self.c_not_y_channel())
1160 .field("line", &self.line())
1161 .field("offset", &self.offset())
1162 .field("did", &self.did())
1163 .field("sdid_block_number", &self.sdid_block_number())
1164 .field("data_count", &self.data_count())
1165 .field("data", &self.data())
1166 .field("checksum", &self.checksum())
1167 .finish()
1168 }
1169}
1170
1171pub mod tags {
1172 gst::impl_meta_tag!(Video, crate::ffi::GST_META_TAG_VIDEO_STR);
1173 gst::impl_meta_tag!(Size, crate::ffi::GST_META_TAG_VIDEO_SIZE_STR);
1174 gst::impl_meta_tag!(Orientation, crate::ffi::GST_META_TAG_VIDEO_ORIENTATION_STR);
1175 gst::impl_meta_tag!(Colorspace, crate::ffi::GST_META_TAG_VIDEO_COLORSPACE_STR);
1176}
1177
1178#[derive(Debug, Clone, PartialEq, Eq)]
1179pub struct VideoMetaTransformScale<'a> {
1180 in_info: &'a crate::VideoInfo,
1181 out_info: &'a crate::VideoInfo,
1182}
1183
1184impl<'a> VideoMetaTransformScale<'a> {
1185 pub fn new(in_info: &'a crate::VideoInfo, out_info: &'a crate::VideoInfo) -> Self {
1186 skip_assert_initialized!();
1187 VideoMetaTransformScale { in_info, out_info }
1188 }
1189}
1190
1191unsafe impl<'a> gst::meta::MetaTransform<'a> for VideoMetaTransformScale<'a> {
1192 type GLibType = ffi::GstVideoMetaTransform;
1193
1194 #[doc(alias = "gst_video_meta_transform_scale_get_quark")]
1195 fn quark() -> glib::Quark {
1196 unsafe { from_glib(ffi::gst_video_meta_transform_scale_get_quark()) }
1197 }
1198
1199 fn to_raw<T: MetaAPI>(
1200 &self,
1201 _meta: &gst::MetaRef<T>,
1202 ) -> Result<ffi::GstVideoMetaTransform, glib::BoolError> {
1203 Ok(ffi::GstVideoMetaTransform {
1204 in_info: mut_override(self.in_info.to_glib_none().0),
1205 out_info: mut_override(self.out_info.to_glib_none().0),
1206 })
1207 }
1208}
1209
1210#[cfg(test)]
1211mod tests {
1212 use super::*;
1213
1214 #[test]
1215 fn test_add_get_meta() {
1216 gst::init().unwrap();
1217
1218 let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1219 {
1220 let meta = VideoMeta::add(
1221 buffer.get_mut().unwrap(),
1222 crate::VideoFrameFlags::empty(),
1223 crate::VideoFormat::Argb,
1224 320,
1225 240,
1226 )
1227 .unwrap();
1228 assert_eq!(meta.id(), 0);
1229 assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1230 assert_eq!(meta.format(), crate::VideoFormat::Argb);
1231 assert_eq!(meta.width(), 320);
1232 assert_eq!(meta.height(), 240);
1233 assert_eq!(meta.n_planes(), 1);
1234 assert_eq!(meta.offset(), &[0]);
1235 assert_eq!(meta.stride(), &[320 * 4]);
1236 assert!(meta.has_tag::<gst::meta::tags::Memory>());
1237 assert!(meta.has_tag::<tags::Video>());
1238 assert!(meta.has_tag::<tags::Colorspace>());
1239 assert!(meta.has_tag::<tags::Size>());
1240 }
1241
1242 {
1243 let meta = buffer.meta::<VideoMeta>().unwrap();
1244 assert_eq!(meta.id(), 0);
1245 assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1246 assert_eq!(meta.format(), crate::VideoFormat::Argb);
1247 assert_eq!(meta.width(), 320);
1248 assert_eq!(meta.height(), 240);
1249 assert_eq!(meta.n_planes(), 1);
1250 assert_eq!(meta.offset(), &[0]);
1251 assert_eq!(meta.stride(), &[320 * 4]);
1252 }
1253 }
1254
1255 #[test]
1256 fn test_add_full_get_meta() {
1257 gst::init().unwrap();
1258
1259 let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1260 {
1261 let meta = VideoMeta::add_full(
1262 buffer.get_mut().unwrap(),
1263 crate::VideoFrameFlags::empty(),
1264 crate::VideoFormat::Argb,
1265 320,
1266 240,
1267 &[0],
1268 &[320 * 4],
1269 )
1270 .unwrap();
1271 assert_eq!(meta.id(), 0);
1272 assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1273 assert_eq!(meta.format(), crate::VideoFormat::Argb);
1274 assert_eq!(meta.width(), 320);
1275 assert_eq!(meta.height(), 240);
1276 assert_eq!(meta.n_planes(), 1);
1277 assert_eq!(meta.offset(), &[0]);
1278 assert_eq!(meta.stride(), &[320 * 4]);
1279 }
1280
1281 {
1282 let meta = buffer.meta::<VideoMeta>().unwrap();
1283 assert_eq!(meta.id(), 0);
1284 assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1285 assert_eq!(meta.format(), crate::VideoFormat::Argb);
1286 assert_eq!(meta.width(), 320);
1287 assert_eq!(meta.height(), 240);
1288 assert_eq!(meta.n_planes(), 1);
1289 assert_eq!(meta.offset(), &[0]);
1290 assert_eq!(meta.stride(), &[320 * 4]);
1291 }
1292 }
1293
1294 #[test]
1295 #[cfg(feature = "v1_16")]
1296 fn test_add_full_alternate_interlacing() {
1297 gst::init().unwrap();
1298 let mut buffer = gst::Buffer::with_size(320 * 120 * 4).unwrap();
1299 VideoMeta::add_full(
1300 buffer.get_mut().unwrap(),
1301 crate::VideoFrameFlags::TOP_FIELD,
1302 crate::VideoFormat::Argb,
1303 320,
1304 240,
1305 &[0],
1306 &[320 * 4],
1307 )
1308 .unwrap();
1309 }
1310
1311 #[test]
1312 #[cfg(feature = "v1_18")]
1313 fn test_video_meta_alignment() {
1314 gst::init().unwrap();
1315
1316 let mut buffer = gst::Buffer::with_size(115200).unwrap();
1317 let meta = VideoMeta::add(
1318 buffer.get_mut().unwrap(),
1319 crate::VideoFrameFlags::empty(),
1320 crate::VideoFormat::Nv12,
1321 320,
1322 240,
1323 )
1324 .unwrap();
1325
1326 let alig = meta.alignment();
1327 assert_eq!(alig, crate::VideoAlignment::new(0, 0, 0, 0, &[0, 0, 0, 0]));
1328
1329 assert_eq!(meta.plane_size().unwrap(), [76800, 38400, 0, 0]);
1330 assert_eq!(meta.plane_height().unwrap(), [240, 120, 0, 0]);
1331
1332 let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv12, 320, 240)
1334 .build()
1335 .expect("Failed to create VideoInfo");
1336 let mut alig = crate::VideoAlignment::new(0, 0, 2, 6, &[0, 0, 0, 0]);
1337 info.align(&mut alig).unwrap();
1338
1339 let mut meta = VideoMeta::add_full(
1340 buffer.get_mut().unwrap(),
1341 crate::VideoFrameFlags::empty(),
1342 crate::VideoFormat::Nv12,
1343 info.width(),
1344 info.height(),
1345 info.offset(),
1346 info.stride(),
1347 )
1348 .unwrap();
1349 meta.set_alignment(&alig).unwrap();
1350
1351 let alig = meta.alignment();
1352 assert_eq!(alig, crate::VideoAlignment::new(0, 0, 2, 6, &[0, 0, 0, 0]));
1353
1354 assert_eq!(meta.plane_size().unwrap(), [78720, 39360, 0, 0]);
1355 assert_eq!(meta.plane_height().unwrap(), [240, 120, 0, 0]);
1356
1357 let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv12, 320, 240)
1359 .build()
1360 .expect("Failed to create VideoInfo");
1361 let mut alig = crate::VideoAlignment::new(2, 6, 0, 0, &[0, 0, 0, 0]);
1362 info.align(&mut alig).unwrap();
1363
1364 let mut meta = VideoMeta::add_full(
1365 buffer.get_mut().unwrap(),
1366 crate::VideoFrameFlags::empty(),
1367 crate::VideoFormat::Nv12,
1368 info.width(),
1369 info.height(),
1370 info.offset(),
1371 info.stride(),
1372 )
1373 .unwrap();
1374 meta.set_alignment(&alig).unwrap();
1375
1376 let alig = meta.alignment();
1377 assert_eq!(alig, crate::VideoAlignment::new(2, 6, 0, 0, &[0, 0, 0, 0]));
1378
1379 assert_eq!(meta.plane_size().unwrap(), [79360, 39680, 0, 0]);
1380 assert_eq!(meta.plane_height().unwrap(), [248, 124, 0, 0]);
1381 }
1382
1383 #[test]
1384 #[cfg(feature = "v1_22")]
1385 fn test_get_video_sei_user_data_unregistered_meta() {
1386 gst::init().unwrap();
1387
1388 const META_UUID: &[u8; 16] = &[
1389 0x4D, 0x49, 0x53, 0x50, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x65, 0x63, 0x74, 0x69,
1390 0x6D, 0x65,
1391 ];
1392
1393 const META_DATA: &[u8] = &[
1394 0x1f, 0x00, 0x05, 0xff, 0x21, 0x7e, 0xff, 0x29, 0xb5, 0xff, 0xdc, 0x13,
1395 ];
1396
1397 let buffer_data = &[
1398 &[0x00, 0x00, 0x00, 0x20, 0x06, 0x05, 0x1c],
1399 META_UUID as &[u8],
1400 META_DATA,
1401 &[
1402 0x80, 0x00, 0x00, 0x00, 0x14, 0x65, 0x88, 0x84, 0x00, 0x10, 0xff, 0xfe, 0xf6, 0xf0,
1403 0xfe, 0x05, 0x36, 0x56, 0x04, 0x50, 0x96, 0x7b, 0x3f, 0x53, 0xe1,
1404 ],
1405 ]
1406 .concat();
1407
1408 let mut harness = gst_check::Harness::new("h264parse");
1409 harness.set_src_caps_str(r#"
1410 video/x-h264, stream-format=(string)avc,
1411 width=(int)1920, height=(int)1080, framerate=(fraction)25/1,
1412 bit-depth-chroma=(uint)8, parsed=(boolean)true,
1413 alignment=(string)au, profile=(string)high, level=(string)4,
1414 codec_data=(buffer)01640028ffe1001a67640028acb200f0044fcb080000030008000003019478c1924001000568ebccb22c
1415 "#);
1416 let buffer = gst::Buffer::from_slice(buffer_data.clone());
1417 let buffer = harness.push_and_pull(buffer).unwrap();
1418
1419 let meta = buffer.meta::<VideoSeiUserDataUnregisteredMeta>().unwrap();
1420 assert_eq!(meta.uuid(), *META_UUID);
1421 assert_eq!(meta.data(), META_DATA);
1422 assert_eq!(meta.data().len(), META_DATA.len());
1423 }
1424
1425 #[test]
1426 fn test_meta_video_transform() {
1427 gst::init().unwrap();
1428
1429 let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1430 let meta = VideoCropMeta::add(buffer.get_mut().unwrap(), (10, 10, 20, 20));
1431
1432 let mut buffer2 = gst::Buffer::with_size(640 * 480 * 4).unwrap();
1433
1434 let in_video_info = crate::VideoInfo::builder(crate::VideoFormat::Rgba, 320, 240)
1435 .build()
1436 .unwrap();
1437 let out_video_info = crate::VideoInfo::builder(crate::VideoFormat::Rgba, 640, 480)
1438 .build()
1439 .unwrap();
1440
1441 meta.transform(
1442 buffer2.get_mut().unwrap(),
1443 &VideoMetaTransformScale::new(&in_video_info, &out_video_info),
1444 )
1445 .unwrap();
1446
1447 let meta2 = buffer2.meta::<VideoCropMeta>().unwrap();
1448
1449 assert_eq!(meta2.rect(), (20, 20, 40, 40));
1450 }
1451}