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