gstreamer-rs/gstreamer-video/src/video_meta.rs
Bilal Elmoussaoui 4ebec84f5e Adapt to no longer renamed ffi crates
Allows us to set all the crates in the main workspace file, so changing
their versions or branch is much simpler and reduce the amount of noise
in the diff

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1450>
2024-06-02 11:20:55 +02:00

1429 lines
42 KiB
Rust

// Take a look at the license at the top of the repository in the LICENSE file.
use std::{fmt, ptr};
use crate::ffi;
use glib::translate::*;
use gst::prelude::*;
#[repr(transparent)]
#[doc(alias = "GstVideoMeta")]
pub struct VideoMeta(ffi::GstVideoMeta);
unsafe impl Send for VideoMeta {}
unsafe impl Sync for VideoMeta {}
impl VideoMeta {
#[doc(alias = "gst_buffer_add_video_meta")]
pub fn add(
buffer: &mut gst::BufferRef,
video_frame_flags: crate::VideoFrameFlags,
format: crate::VideoFormat,
width: u32,
height: u32,
) -> Result<gst::MetaRefMut<Self, gst::meta::Standalone>, glib::BoolError> {
skip_assert_initialized!();
if format == crate::VideoFormat::Unknown || format == crate::VideoFormat::Encoded {
return Err(glib::bool_error!("Unsupported video format {}", format));
}
let info = crate::VideoInfo::builder(format, width, height).build()?;
if !info.is_valid() {
return Err(glib::bool_error!("Invalid video info"));
}
if buffer.size() < info.size() {
return Err(glib::bool_error!(
"Buffer smaller than required frame size ({} < {})",
buffer.size(),
info.size()
));
}
unsafe {
let meta = ffi::gst_buffer_add_video_meta(
buffer.as_mut_ptr(),
video_frame_flags.into_glib(),
format.into_glib(),
width,
height,
);
if meta.is_null() {
return Err(glib::bool_error!("Failed to add video meta"));
}
Ok(Self::from_mut_ptr(buffer, meta))
}
}
pub fn add_full<'a>(
buffer: &'a mut gst::BufferRef,
video_frame_flags: crate::VideoFrameFlags,
format: crate::VideoFormat,
width: u32,
height: u32,
offset: &[usize],
stride: &[i32],
) -> Result<gst::MetaRefMut<'a, Self, gst::meta::Standalone>, glib::BoolError> {
skip_assert_initialized!();
if format == crate::VideoFormat::Unknown || format == crate::VideoFormat::Encoded {
return Err(glib::bool_error!("Unsupported video format {}", format));
}
let n_planes = offset.len() as u32;
let info = crate::VideoInfo::builder(format, width, height)
.offset(offset)
.stride(stride)
.build()?;
if !info.is_valid() {
return Err(glib::bool_error!("Invalid video info"));
}
if buffer.size() < info.size() {
return Err(glib::bool_error!(
"Buffer smaller than required frame size ({} < {})",
buffer.size(),
info.size()
));
}
unsafe {
let meta = ffi::gst_buffer_add_video_meta_full(
buffer.as_mut_ptr(),
video_frame_flags.into_glib(),
format.into_glib(),
width,
height,
n_planes,
offset.as_ptr() as *mut _,
stride.as_ptr() as *mut _,
);
if meta.is_null() {
return Err(glib::bool_error!("Failed to add video meta"));
}
Ok(Self::from_mut_ptr(buffer, meta))
}
}
#[doc(alias = "get_flags")]
#[inline]
pub fn video_frame_flags(&self) -> crate::VideoFrameFlags {
unsafe { from_glib(self.0.flags) }
}
#[doc(alias = "get_format")]
#[inline]
pub fn format(&self) -> crate::VideoFormat {
unsafe { from_glib(self.0.format) }
}
#[doc(alias = "get_id")]
#[inline]
pub fn id(&self) -> i32 {
self.0.id
}
#[doc(alias = "get_width")]
#[inline]
pub fn width(&self) -> u32 {
self.0.width
}
#[doc(alias = "get_height")]
#[inline]
pub fn height(&self) -> u32 {
self.0.height
}
#[doc(alias = "get_n_planes")]
#[inline]
pub fn n_planes(&self) -> u32 {
self.0.n_planes
}
#[doc(alias = "get_offset")]
#[inline]
pub fn offset(&self) -> &[usize] {
&self.0.offset[0..(self.0.n_planes as usize)]
}
#[doc(alias = "get_stride")]
#[inline]
pub fn stride(&self) -> &[i32] {
&self.0.stride[0..(self.0.n_planes as usize)]
}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
#[doc(alias = "get_alignment")]
#[inline]
pub fn alignment(&self) -> crate::VideoAlignment {
crate::VideoAlignment::new(
self.0.alignment.padding_top,
self.0.alignment.padding_bottom,
self.0.alignment.padding_left,
self.0.alignment.padding_right,
&self.0.alignment.stride_align,
)
}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
#[doc(alias = "get_plane_size")]
#[doc(alias = "gst_video_meta_get_plane_size")]
pub fn plane_size(&self) -> Result<[usize; crate::VIDEO_MAX_PLANES], glib::BoolError> {
let mut plane_size = [0; crate::VIDEO_MAX_PLANES];
unsafe {
glib::result_from_gboolean!(
ffi::gst_video_meta_get_plane_size(mut_override(&self.0), &mut plane_size,),
"Failed to get plane size"
)?;
}
Ok(plane_size)
}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
#[doc(alias = "get_plane_height")]
#[doc(alias = "gst_video_meta_get_plane_height")]
pub fn plane_height(&self) -> Result<[u32; crate::VIDEO_MAX_PLANES], glib::BoolError> {
let mut plane_height = [0; crate::VIDEO_MAX_PLANES];
unsafe {
glib::result_from_gboolean!(
ffi::gst_video_meta_get_plane_height(mut_override(&self.0), &mut plane_height,),
"Failed to get plane height"
)?;
}
Ok(plane_height)
}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
#[doc(alias = "gst_video_meta_set_alignment")]
pub fn set_alignment(
&mut self,
alignment: &crate::VideoAlignment,
) -> Result<(), glib::BoolError> {
unsafe {
glib::result_from_gboolean!(
ffi::gst_video_meta_set_alignment(&mut self.0, alignment.0),
"Failed to set alignment on VideoMeta"
)
}
}
}
unsafe impl MetaAPI for VideoMeta {
type GstType = ffi::GstVideoMeta;
#[doc(alias = "gst_video_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::gst_video_meta_api_get_type()) }
}
}
impl fmt::Debug for VideoMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VideoMeta")
.field("id", &self.id())
.field("video_frame_flags", &self.video_frame_flags())
.field("format", &self.format())
.field("width", &self.width())
.field("height", &self.height())
.field("n_planes", &self.n_planes())
.field("offset", &self.offset())
.field("stride", &self.stride())
.finish()
}
}
#[repr(transparent)]
#[doc(alias = "GstVideoCropMeta")]
pub struct VideoCropMeta(ffi::GstVideoCropMeta);
unsafe impl Send for VideoCropMeta {}
unsafe impl Sync for VideoCropMeta {}
impl VideoCropMeta {
#[doc(alias = "gst_buffer_add_meta")]
pub fn add(
buffer: &mut gst::BufferRef,
rect: (u32, u32, u32, u32),
) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
skip_assert_initialized!();
unsafe {
let meta = gst::ffi::gst_buffer_add_meta(
buffer.as_mut_ptr(),
ffi::gst_video_crop_meta_get_info(),
ptr::null_mut(),
) as *mut ffi::GstVideoCropMeta;
{
let meta = &mut *meta;
meta.x = rect.0;
meta.y = rect.1;
meta.width = rect.2;
meta.height = rect.3;
}
Self::from_mut_ptr(buffer, meta)
}
}
#[doc(alias = "get_rect")]
#[inline]
pub fn rect(&self) -> (u32, u32, u32, u32) {
(self.0.x, self.0.y, self.0.width, self.0.height)
}
#[inline]
pub fn set_rect(&mut self, rect: (u32, u32, u32, u32)) {
self.0.x = rect.0;
self.0.y = rect.1;
self.0.width = rect.2;
self.0.height = rect.3;
}
}
unsafe impl MetaAPI for VideoCropMeta {
type GstType = ffi::GstVideoCropMeta;
#[doc(alias = "gst_video_crop_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::gst_video_crop_meta_api_get_type()) }
}
}
impl fmt::Debug for VideoCropMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VideoCropMeta")
.field("rect", &self.rect())
.finish()
}
}
#[repr(transparent)]
#[doc(alias = "GstVideoRegionOfInterestMeta")]
pub struct VideoRegionOfInterestMeta(ffi::GstVideoRegionOfInterestMeta);
unsafe impl Send for VideoRegionOfInterestMeta {}
unsafe impl Sync for VideoRegionOfInterestMeta {}
impl VideoRegionOfInterestMeta {
#[doc(alias = "gst_buffer_add_video_region_of_interest_meta")]
pub fn add<'a>(
buffer: &'a mut gst::BufferRef,
roi_type: &str,
rect: (u32, u32, u32, u32),
) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
skip_assert_initialized!();
unsafe {
let meta = ffi::gst_buffer_add_video_region_of_interest_meta(
buffer.as_mut_ptr(),
roi_type.to_glib_none().0,
rect.0,
rect.1,
rect.2,
rect.3,
);
Self::from_mut_ptr(buffer, meta)
}
}
#[doc(alias = "get_rect")]
#[inline]
pub fn rect(&self) -> (u32, u32, u32, u32) {
(self.0.x, self.0.y, self.0.w, self.0.h)
}
#[doc(alias = "get_id")]
#[inline]
pub fn id(&self) -> i32 {
self.0.id
}
#[doc(alias = "get_parent_id")]
#[inline]
pub fn parent_id(&self) -> i32 {
self.0.parent_id
}
#[doc(alias = "get_roi_type")]
#[inline]
pub fn roi_type<'a>(&self) -> &'a str {
unsafe { glib::Quark::from_glib(self.0.roi_type).as_str() }
}
#[doc(alias = "get_params")]
pub fn params(&self) -> ParamsIter {
ParamsIter {
_meta: self,
list: ptr::NonNull::new(self.0.params),
}
}
#[doc(alias = "get_param")]
#[inline]
pub fn param<'b>(&'b self, name: &str) -> Option<&'b gst::StructureRef> {
self.params().find(|s| s.name() == name)
}
#[inline]
pub fn set_rect(&mut self, rect: (u32, u32, u32, u32)) {
self.0.x = rect.0;
self.0.y = rect.1;
self.0.w = rect.2;
self.0.h = rect.3;
}
#[inline]
pub fn set_id(&mut self, id: i32) {
self.0.id = id
}
#[inline]
pub fn set_parent_id(&mut self, id: i32) {
self.0.parent_id = id
}
#[doc(alias = "gst_video_region_of_interest_meta_add_param")]
pub fn add_param(&mut self, s: gst::Structure) {
unsafe {
ffi::gst_video_region_of_interest_meta_add_param(&mut self.0, s.into_glib_ptr());
}
}
}
pub struct ParamsIter<'a> {
_meta: &'a VideoRegionOfInterestMeta,
list: Option<ptr::NonNull<glib::ffi::GList>>,
}
impl<'a> Iterator for ParamsIter<'a> {
type Item = &'a gst::StructureRef;
fn next(&mut self) -> Option<&'a gst::StructureRef> {
match self.list {
None => None,
Some(list) => unsafe {
self.list = ptr::NonNull::new(list.as_ref().next);
let data = list.as_ref().data;
let s = gst::StructureRef::from_glib_borrow(data as *const gst::ffi::GstStructure);
Some(s)
},
}
}
}
impl<'a> std::iter::FusedIterator for ParamsIter<'a> {}
unsafe impl MetaAPI for VideoRegionOfInterestMeta {
type GstType = ffi::GstVideoRegionOfInterestMeta;
#[doc(alias = "gst_video_region_of_interest_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::gst_video_region_of_interest_meta_api_get_type()) }
}
}
impl fmt::Debug for VideoRegionOfInterestMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VideoRegionOfInterestMeta")
.field("roi_type", &self.roi_type())
.field("rect", &self.rect())
.field("id", &self.id())
.field("parent_id", &self.parent_id())
.field("params", &self.params().collect::<Vec<_>>())
.finish()
}
}
#[repr(transparent)]
#[doc(alias = "GstVideoAffineTransformationMeta")]
pub struct VideoAffineTransformationMeta(ffi::GstVideoAffineTransformationMeta);
unsafe impl Send for VideoAffineTransformationMeta {}
unsafe impl Sync for VideoAffineTransformationMeta {}
impl VideoAffineTransformationMeta {
#[doc(alias = "gst_buffer_add_meta")]
pub fn add<'a>(
buffer: &'a mut gst::BufferRef,
matrix: Option<&[[f32; 4]; 4]>,
) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
skip_assert_initialized!();
unsafe {
let meta = gst::ffi::gst_buffer_add_meta(
buffer.as_mut_ptr(),
ffi::gst_video_affine_transformation_meta_get_info(),
ptr::null_mut(),
) as *mut ffi::GstVideoAffineTransformationMeta;
if let Some(matrix) = matrix {
let meta = &mut *meta;
for (i, o) in Iterator::zip(matrix.iter().flatten(), meta.matrix.iter_mut()) {
*o = *i;
}
}
Self::from_mut_ptr(buffer, meta)
}
}
#[doc(alias = "get_matrix")]
#[inline]
pub fn matrix(&self) -> &[[f32; 4]; 4] {
unsafe { &*(&self.0.matrix as *const [f32; 16] as *const [[f32; 4]; 4]) }
}
#[inline]
pub fn set_matrix(&mut self, matrix: &[[f32; 4]; 4]) {
for (i, o) in Iterator::zip(matrix.iter().flatten(), self.0.matrix.iter_mut()) {
*o = *i;
}
}
#[doc(alias = "gst_video_affine_transformation_meta_apply_matrix")]
pub fn apply_matrix(&mut self, matrix: &[[f32; 4]; 4]) {
unsafe {
ffi::gst_video_affine_transformation_meta_apply_matrix(
&mut self.0,
matrix as *const [[f32; 4]; 4] as *const [f32; 16],
);
}
}
}
unsafe impl MetaAPI for VideoAffineTransformationMeta {
type GstType = ffi::GstVideoAffineTransformationMeta;
#[doc(alias = "gst_video_affine_transformation_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::gst_video_affine_transformation_meta_api_get_type()) }
}
}
impl fmt::Debug for VideoAffineTransformationMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VideoAffineTransformationMeta")
.field("matrix", &self.matrix())
.finish()
}
}
#[repr(transparent)]
#[doc(alias = "GstVideoOverlayCompositionMeta")]
pub struct VideoOverlayCompositionMeta(ffi::GstVideoOverlayCompositionMeta);
unsafe impl Send for VideoOverlayCompositionMeta {}
unsafe impl Sync for VideoOverlayCompositionMeta {}
impl VideoOverlayCompositionMeta {
#[doc(alias = "gst_buffer_add_video_overlay_composition_meta")]
pub fn add<'a>(
buffer: &'a mut gst::BufferRef,
overlay: &crate::VideoOverlayComposition,
) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
skip_assert_initialized!();
unsafe {
let meta = ffi::gst_buffer_add_video_overlay_composition_meta(
buffer.as_mut_ptr(),
overlay.as_mut_ptr(),
);
Self::from_mut_ptr(buffer, meta)
}
}
#[doc(alias = "get_overlay")]
#[inline]
pub fn overlay(&self) -> &crate::VideoOverlayCompositionRef {
unsafe { crate::VideoOverlayCompositionRef::from_ptr(self.0.overlay) }
}
#[doc(alias = "get_overlay_owned")]
#[inline]
pub fn overlay_owned(&self) -> crate::VideoOverlayComposition {
unsafe { from_glib_none(self.overlay().as_ptr()) }
}
#[inline]
pub fn set_overlay(&mut self, overlay: &crate::VideoOverlayComposition) {
#![allow(clippy::cast_ptr_alignment)]
unsafe {
gst::ffi::gst_mini_object_unref(self.0.overlay as *mut _);
self.0.overlay =
gst::ffi::gst_mini_object_ref(overlay.as_mut_ptr() as *mut _) as *mut _;
}
}
}
unsafe impl MetaAPI for VideoOverlayCompositionMeta {
type GstType = ffi::GstVideoOverlayCompositionMeta;
#[doc(alias = "gst_video_overlay_composition_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::gst_video_overlay_composition_meta_api_get_type()) }
}
}
impl fmt::Debug for VideoOverlayCompositionMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VideoOverlayCompositionMeta")
.field("overlay", &self.overlay())
.finish()
}
}
#[cfg(feature = "v1_16")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
#[repr(transparent)]
#[doc(alias = "GstVideoCaptionMeta")]
pub struct VideoCaptionMeta(ffi::GstVideoCaptionMeta);
#[cfg(feature = "v1_16")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
unsafe impl Send for VideoCaptionMeta {}
#[cfg(feature = "v1_16")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
unsafe impl Sync for VideoCaptionMeta {}
#[cfg(feature = "v1_16")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
impl VideoCaptionMeta {
#[doc(alias = "gst_buffer_add_video_caption_meta")]
pub fn add<'a>(
buffer: &'a mut gst::BufferRef,
caption_type: crate::VideoCaptionType,
data: &[u8],
) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
skip_assert_initialized!();
assert!(!data.is_empty());
unsafe {
let meta = ffi::gst_buffer_add_video_caption_meta(
buffer.as_mut_ptr(),
caption_type.into_glib(),
data.as_ptr(),
data.len(),
);
Self::from_mut_ptr(buffer, meta)
}
}
#[doc(alias = "get_caption_type")]
#[inline]
pub fn caption_type(&self) -> crate::VideoCaptionType {
unsafe { from_glib(self.0.caption_type) }
}
#[doc(alias = "get_data")]
#[inline]
pub fn data(&self) -> &[u8] {
if self.0.size == 0 {
return &[];
}
unsafe {
use std::slice;
slice::from_raw_parts(self.0.data, self.0.size)
}
}
}
#[cfg(feature = "v1_16")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
unsafe impl MetaAPI for VideoCaptionMeta {
type GstType = ffi::GstVideoCaptionMeta;
#[doc(alias = "gst_video_caption_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::gst_video_caption_meta_api_get_type()) }
}
}
#[cfg(feature = "v1_16")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
impl fmt::Debug for VideoCaptionMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VideoCaptionMeta")
.field("caption_type", &self.caption_type())
.field("data", &self.data())
.finish()
}
}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
#[repr(transparent)]
#[doc(alias = "GstVideoAFDMeta")]
pub struct VideoAFDMeta(ffi::GstVideoAFDMeta);
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
unsafe impl Send for VideoAFDMeta {}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
unsafe impl Sync for VideoAFDMeta {}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
impl VideoAFDMeta {
#[doc(alias = "gst_buffer_add_video_afd_meta")]
pub fn add(
buffer: &mut gst::BufferRef,
field: u8,
spec: crate::VideoAFDSpec,
afd: crate::VideoAFDValue,
) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
skip_assert_initialized!();
unsafe {
let meta = ffi::gst_buffer_add_video_afd_meta(
buffer.as_mut_ptr(),
field,
spec.into_glib(),
afd.into_glib(),
);
Self::from_mut_ptr(buffer, meta)
}
}
#[doc(alias = "get_field")]
#[inline]
pub fn field(&self) -> u8 {
self.0.field
}
#[doc(alias = "get_spec")]
#[inline]
pub fn spec(&self) -> crate::VideoAFDSpec {
unsafe { from_glib(self.0.spec) }
}
#[doc(alias = "get_afd")]
#[inline]
pub fn afd(&self) -> crate::VideoAFDValue {
unsafe { from_glib(self.0.afd) }
}
}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
unsafe impl MetaAPI for VideoAFDMeta {
type GstType = ffi::GstVideoAFDMeta;
#[doc(alias = "gst_video_afd_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::gst_video_afd_meta_api_get_type()) }
}
}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
impl fmt::Debug for VideoAFDMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VideoAFDMeta")
.field("field", &self.field())
.field("spec", &self.spec())
.field("afd", &self.afd())
.finish()
}
}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
#[repr(transparent)]
#[doc(alias = "GstVideoBarMeta")]
pub struct VideoBarMeta(ffi::GstVideoBarMeta);
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
unsafe impl Send for VideoBarMeta {}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
unsafe impl Sync for VideoBarMeta {}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
impl VideoBarMeta {
#[doc(alias = "gst_buffer_add_video_bar_meta")]
pub fn add(
buffer: &mut gst::BufferRef,
field: u8,
is_letterbox: bool,
bar_data1: u32,
bar_data2: u32,
) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
skip_assert_initialized!();
unsafe {
let meta = ffi::gst_buffer_add_video_bar_meta(
buffer.as_mut_ptr(),
field,
is_letterbox.into_glib(),
bar_data1,
bar_data2,
);
Self::from_mut_ptr(buffer, meta)
}
}
#[doc(alias = "get_field")]
#[inline]
pub fn field(&self) -> u8 {
self.0.field
}
#[inline]
pub fn is_letterbox(&self) -> bool {
unsafe { from_glib(self.0.is_letterbox) }
}
#[doc(alias = "get_bar_data1")]
#[inline]
pub fn bar_data1(&self) -> u32 {
self.0.bar_data1
}
#[doc(alias = "get_bar_data2")]
#[inline]
pub fn bar_data2(&self) -> u32 {
self.0.bar_data2
}
}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
unsafe impl MetaAPI for VideoBarMeta {
type GstType = ffi::GstVideoBarMeta;
#[doc(alias = "gst_video_bar_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::gst_video_bar_meta_api_get_type()) }
}
}
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
impl fmt::Debug for VideoBarMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VideoBarMeta")
.field("field", &self.field())
.field("is_letterbox", &self.is_letterbox())
.field("bar_data1", &self.bar_data1())
.field("bar_data2", &self.bar_data2())
.finish()
}
}
#[cfg(feature = "v1_20")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
#[repr(transparent)]
#[doc(alias = "GstVideoCodecAlphaMeta")]
pub struct VideoCodecAlphaMeta(ffi::GstVideoCodecAlphaMeta);
#[cfg(feature = "v1_20")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
unsafe impl Send for VideoCodecAlphaMeta {}
#[cfg(feature = "v1_20")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
unsafe impl Sync for VideoCodecAlphaMeta {}
#[cfg(feature = "v1_20")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
impl VideoCodecAlphaMeta {
#[doc(alias = "gst_buffer_add_video_codec_alpha_meta")]
pub fn add(
buffer: &mut gst::BufferRef,
alpha_buffer: gst::Buffer,
) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
skip_assert_initialized!();
unsafe {
let meta = ffi::gst_buffer_add_video_codec_alpha_meta(
buffer.as_mut_ptr(),
alpha_buffer.to_glib_none().0,
);
Self::from_mut_ptr(buffer, meta)
}
}
#[inline]
pub fn alpha_buffer(&self) -> &gst::BufferRef {
unsafe { gst::BufferRef::from_ptr(self.0.buffer) }
}
#[inline]
pub fn alpha_buffer_owned(&self) -> gst::Buffer {
unsafe { from_glib_none(self.0.buffer) }
}
}
#[cfg(feature = "v1_20")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
unsafe impl MetaAPI for VideoCodecAlphaMeta {
type GstType = ffi::GstVideoCodecAlphaMeta;
#[doc(alias = "gst_video_codec_alpha_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::gst_video_codec_alpha_meta_api_get_type()) }
}
}
#[cfg(feature = "v1_20")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
impl fmt::Debug for VideoCodecAlphaMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VideoCodecAlphaMeta")
.field("buffer", &self.alpha_buffer())
.finish()
}
}
#[cfg(feature = "v1_22")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
#[repr(transparent)]
#[doc(alias = "GstVideoSEIUserDataUnregisteredMeta")]
pub struct VideoSeiUserDataUnregisteredMeta(ffi::GstVideoSEIUserDataUnregisteredMeta);
#[cfg(feature = "v1_22")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
unsafe impl Send for VideoSeiUserDataUnregisteredMeta {}
#[cfg(feature = "v1_22")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
unsafe impl Sync for VideoSeiUserDataUnregisteredMeta {}
#[cfg(feature = "v1_22")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
impl VideoSeiUserDataUnregisteredMeta {
#[doc(alias = "gst_buffer_add_video_sei_user_data_unregistered_meta")]
pub fn add<'a>(
buffer: &'a mut gst::BufferRef,
uuid: &[u8; 16],
data: &[u8],
) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
skip_assert_initialized!();
assert!(!data.is_empty());
unsafe {
let meta = ffi::gst_buffer_add_video_sei_user_data_unregistered_meta(
buffer.as_mut_ptr(),
mut_override(uuid.as_ptr()),
mut_override(data.as_ptr()),
data.len(),
);
Self::from_mut_ptr(buffer, meta)
}
}
#[doc(alias = "get_data")]
#[inline]
pub fn data(&self) -> &[u8] {
if self.0.size == 0 {
return &[];
}
// SAFETY: In the C API we have a pointer data and a size variable
// indicating the length of the data. Here we convert it to a size,
// making sure we read the size specified in the C API.
unsafe {
use std::slice;
slice::from_raw_parts(self.0.data, self.0.size)
}
}
#[doc(alias = "get_uuid")]
#[inline]
pub fn uuid(&self) -> [u8; 16] {
self.0.uuid
}
}
#[cfg(feature = "v1_22")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
impl fmt::Debug for VideoSeiUserDataUnregisteredMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("VideoSeiUserDataUnregisteredMeta")
.field(
"uuid",
&format!("0x{:032X}", u128::from_be_bytes(self.uuid())),
)
.field("data", &self.data())
.finish()
}
}
#[cfg(feature = "v1_22")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
unsafe impl MetaAPI for VideoSeiUserDataUnregisteredMeta {
type GstType = ffi::GstVideoSEIUserDataUnregisteredMeta;
#[doc(alias = "gst_video_sei_user_data_unregistered_meta_api_get_type")]
fn meta_api() -> glib::Type {
unsafe {
glib::translate::from_glib(ffi::gst_video_sei_user_data_unregistered_meta_api_get_type())
}
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[repr(transparent)]
#[doc(alias = "GstAncillaryMeta")]
pub struct AncillaryMeta(ffi::GstAncillaryMeta);
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
unsafe impl Send for AncillaryMeta {}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
unsafe impl Sync for AncillaryMeta {}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
impl AncillaryMeta {
#[doc(alias = "gst_buffer_add_ancillary_meta")]
pub fn add(buffer: &mut gst::BufferRef) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
skip_assert_initialized!();
unsafe {
let meta = ffi::gst_buffer_add_ancillary_meta(buffer.as_mut_ptr());
Self::from_mut_ptr(buffer, meta)
}
}
#[inline]
pub fn field(&self) -> crate::AncillaryMetaField {
unsafe { from_glib(self.0.field) }
}
#[inline]
pub fn set_field(&mut self, field: crate::AncillaryMetaField) {
self.0.field = field.into_glib();
}
#[inline]
pub fn c_not_y_channel(&self) -> bool {
unsafe { from_glib(self.0.c_not_y_channel) }
}
#[inline]
pub fn set_c_not_y_channel(&mut self, c_not_y_channel: bool) {
self.0.c_not_y_channel = c_not_y_channel.into_glib();
}
#[inline]
pub fn line(&self) -> u16 {
self.0.line
}
#[inline]
pub fn set_line(&mut self, line: u16) {
self.0.line = line;
}
#[inline]
pub fn offset(&self) -> u16 {
self.0.offset
}
#[inline]
pub fn set_offset(&mut self, offset: u16) {
self.0.offset = offset;
}
#[inline]
pub fn did(&self) -> u16 {
self.0.DID
}
#[inline]
pub fn set_did(&mut self, did: u16) {
self.0.DID = did;
}
#[inline]
pub fn sdid_block_number(&self) -> u16 {
self.0.SDID_block_number
}
#[inline]
pub fn set_sdid_block_number(&mut self, sdid_block_number: u16) {
self.0.SDID_block_number = sdid_block_number;
}
#[inline]
pub fn data_count(&self) -> u16 {
self.0.data_count
}
#[inline]
pub fn checksum(&self) -> u16 {
self.0.checksum
}
#[inline]
pub fn set_checksum(&mut self, checksum: u16) {
self.0.checksum = checksum;
}
#[inline]
pub fn data(&self) -> &[u16] {
if self.0.data_count & 0xff == 0 {
return &[];
}
unsafe {
use std::slice;
slice::from_raw_parts(self.0.data, (self.0.data_count & 0xff) as usize)
}
}
#[inline]
pub fn data_mut(&mut self) -> &mut [u16] {
if self.0.data_count & 0xff == 0 {
return &mut [];
}
unsafe {
use std::slice;
slice::from_raw_parts_mut(self.0.data, (self.0.data_count & 0xff) as usize)
}
}
#[inline]
pub fn set_data(&mut self, data: glib::Slice<u16>) {
unsafe {
assert!(data.len() < 256);
self.0.data_count = data.len() as u16;
self.0.data = data.into_glib_ptr();
}
}
#[inline]
pub fn set_data_count_upper_two_bits(&mut self, upper_two_bits: u8) {
assert!(upper_two_bits & !0x03 == 0);
self.0.data_count = ((upper_two_bits as u16) << 8) | self.0.data_count & 0xff;
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
unsafe impl MetaAPI for AncillaryMeta {
type GstType = ffi::GstAncillaryMeta;
#[doc(alias = "gst_ancillary_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::gst_ancillary_meta_api_get_type()) }
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
impl fmt::Debug for AncillaryMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("AncillaryMeta")
.field("field", &self.field())
.field("c_not_y_channel", &self.c_not_y_channel())
.field("line", &self.line())
.field("offset", &self.offset())
.field("did", &self.did())
.field("sdid_block_number", &self.sdid_block_number())
.field("data_count", &self.data_count())
.field("data", &self.data())
.field("checksum", &self.checksum())
.finish()
}
}
pub mod tags {
gst::impl_meta_tag!(Video, crate::ffi::GST_META_TAG_VIDEO_STR);
gst::impl_meta_tag!(Size, crate::ffi::GST_META_TAG_VIDEO_SIZE_STR);
gst::impl_meta_tag!(Orientation, crate::ffi::GST_META_TAG_VIDEO_ORIENTATION_STR);
gst::impl_meta_tag!(Colorspace, crate::ffi::GST_META_TAG_VIDEO_COLORSPACE_STR);
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VideoMetaTransformScale<'a> {
in_info: &'a crate::VideoInfo,
out_info: &'a crate::VideoInfo,
}
impl<'a> VideoMetaTransformScale<'a> {
pub fn new(in_info: &'a crate::VideoInfo, out_info: &'a crate::VideoInfo) -> Self {
skip_assert_initialized!();
VideoMetaTransformScale { in_info, out_info }
}
}
unsafe impl<'a> gst::meta::MetaTransform<'a> for VideoMetaTransformScale<'a> {
type GLibType = ffi::GstVideoMetaTransform;
#[doc(alias = "gst_video_meta_transform_scale_get_quark")]
fn quark() -> glib::Quark {
unsafe { from_glib(ffi::gst_video_meta_transform_scale_get_quark()) }
}
fn to_raw<T: MetaAPI>(
&self,
_meta: &gst::MetaRef<T>,
) -> Result<ffi::GstVideoMetaTransform, glib::BoolError> {
Ok(ffi::GstVideoMetaTransform {
in_info: mut_override(self.in_info.to_glib_none().0),
out_info: mut_override(self.out_info.to_glib_none().0),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add_get_meta() {
gst::init().unwrap();
let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
{
let meta = VideoMeta::add(
buffer.get_mut().unwrap(),
crate::VideoFrameFlags::empty(),
crate::VideoFormat::Argb,
320,
240,
)
.unwrap();
assert_eq!(meta.id(), 0);
assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
assert_eq!(meta.format(), crate::VideoFormat::Argb);
assert_eq!(meta.width(), 320);
assert_eq!(meta.height(), 240);
assert_eq!(meta.n_planes(), 1);
assert_eq!(meta.offset(), &[0]);
assert_eq!(meta.stride(), &[320 * 4]);
assert!(meta.has_tag::<gst::meta::tags::Memory>());
assert!(meta.has_tag::<tags::Video>());
assert!(meta.has_tag::<tags::Colorspace>());
assert!(meta.has_tag::<tags::Size>());
}
{
let meta = buffer.meta::<VideoMeta>().unwrap();
assert_eq!(meta.id(), 0);
assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
assert_eq!(meta.format(), crate::VideoFormat::Argb);
assert_eq!(meta.width(), 320);
assert_eq!(meta.height(), 240);
assert_eq!(meta.n_planes(), 1);
assert_eq!(meta.offset(), &[0]);
assert_eq!(meta.stride(), &[320 * 4]);
}
}
#[test]
fn test_add_full_get_meta() {
gst::init().unwrap();
let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
{
let meta = VideoMeta::add_full(
buffer.get_mut().unwrap(),
crate::VideoFrameFlags::empty(),
crate::VideoFormat::Argb,
320,
240,
&[0],
&[320 * 4],
)
.unwrap();
assert_eq!(meta.id(), 0);
assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
assert_eq!(meta.format(), crate::VideoFormat::Argb);
assert_eq!(meta.width(), 320);
assert_eq!(meta.height(), 240);
assert_eq!(meta.n_planes(), 1);
assert_eq!(meta.offset(), &[0]);
assert_eq!(meta.stride(), &[320 * 4]);
}
{
let meta = buffer.meta::<VideoMeta>().unwrap();
assert_eq!(meta.id(), 0);
assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
assert_eq!(meta.format(), crate::VideoFormat::Argb);
assert_eq!(meta.width(), 320);
assert_eq!(meta.height(), 240);
assert_eq!(meta.n_planes(), 1);
assert_eq!(meta.offset(), &[0]);
assert_eq!(meta.stride(), &[320 * 4]);
}
}
#[test]
#[cfg(feature = "v1_18")]
fn test_video_meta_alignment() {
gst::init().unwrap();
let mut buffer = gst::Buffer::with_size(115200).unwrap();
let meta = VideoMeta::add(
buffer.get_mut().unwrap(),
crate::VideoFrameFlags::empty(),
crate::VideoFormat::Nv12,
320,
240,
)
.unwrap();
let alig = meta.alignment();
assert_eq!(alig, crate::VideoAlignment::new(0, 0, 0, 0, &[0, 0, 0, 0]));
assert_eq!(meta.plane_size().unwrap(), [76800, 38400, 0, 0]);
assert_eq!(meta.plane_height().unwrap(), [240, 120, 0, 0]);
/* horizontal padding */
let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv12, 320, 240)
.build()
.expect("Failed to create VideoInfo");
let mut alig = crate::VideoAlignment::new(0, 0, 2, 6, &[0, 0, 0, 0]);
info.align(&mut alig).unwrap();
let mut meta = VideoMeta::add_full(
buffer.get_mut().unwrap(),
crate::VideoFrameFlags::empty(),
crate::VideoFormat::Nv12,
info.width(),
info.height(),
info.offset(),
info.stride(),
)
.unwrap();
meta.set_alignment(&alig).unwrap();
let alig = meta.alignment();
assert_eq!(alig, crate::VideoAlignment::new(0, 0, 2, 6, &[0, 0, 0, 0]));
assert_eq!(meta.plane_size().unwrap(), [78720, 39360, 0, 0]);
assert_eq!(meta.plane_height().unwrap(), [240, 120, 0, 0]);
/* vertical alignment */
let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv12, 320, 240)
.build()
.expect("Failed to create VideoInfo");
let mut alig = crate::VideoAlignment::new(2, 6, 0, 0, &[0, 0, 0, 0]);
info.align(&mut alig).unwrap();
let mut meta = VideoMeta::add_full(
buffer.get_mut().unwrap(),
crate::VideoFrameFlags::empty(),
crate::VideoFormat::Nv12,
info.width(),
info.height(),
info.offset(),
info.stride(),
)
.unwrap();
meta.set_alignment(&alig).unwrap();
let alig = meta.alignment();
assert_eq!(alig, crate::VideoAlignment::new(2, 6, 0, 0, &[0, 0, 0, 0]));
assert_eq!(meta.plane_size().unwrap(), [79360, 39680, 0, 0]);
assert_eq!(meta.plane_height().unwrap(), [248, 124, 0, 0]);
}
#[test]
#[cfg(feature = "v1_22")]
fn test_get_video_sei_user_data_unregistered_meta() {
gst::init().unwrap();
const META_UUID: &[u8; 16] = &[
0x4D, 0x49, 0x53, 0x50, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x65, 0x63, 0x74, 0x69,
0x6D, 0x65,
];
const META_DATA: &[u8] = &[
0x1f, 0x00, 0x05, 0xff, 0x21, 0x7e, 0xff, 0x29, 0xb5, 0xff, 0xdc, 0x13,
];
let buffer_data = &[
&[0x00, 0x00, 0x00, 0x20, 0x06, 0x05, 0x1c],
META_UUID as &[u8],
META_DATA,
&[
0x80, 0x00, 0x00, 0x00, 0x14, 0x65, 0x88, 0x84, 0x00, 0x10, 0xff, 0xfe, 0xf6, 0xf0,
0xfe, 0x05, 0x36, 0x56, 0x04, 0x50, 0x96, 0x7b, 0x3f, 0x53, 0xe1,
],
]
.concat();
let mut harness = gst_check::Harness::new("h264parse");
harness.set_src_caps_str(r#"
video/x-h264, stream-format=(string)avc,
width=(int)1920, height=(int)1080, framerate=(fraction)25/1,
bit-depth-chroma=(uint)8, parsed=(boolean)true,
alignment=(string)au, profile=(string)high, level=(string)4,
codec_data=(buffer)01640028ffe1001a67640028acb200f0044fcb080000030008000003019478c1924001000568ebccb22c
"#);
let buffer = gst::Buffer::from_slice(buffer_data.clone());
let buffer = harness.push_and_pull(buffer).unwrap();
let meta = buffer.meta::<VideoSeiUserDataUnregisteredMeta>().unwrap();
assert_eq!(meta.uuid(), *META_UUID);
assert_eq!(meta.data(), META_DATA);
assert_eq!(meta.data().len(), META_DATA.len());
}
#[test]
fn test_meta_video_transform() {
gst::init().unwrap();
let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
let meta = VideoCropMeta::add(buffer.get_mut().unwrap(), (10, 10, 20, 20));
let mut buffer2 = gst::Buffer::with_size(640 * 480 * 4).unwrap();
let in_video_info = crate::VideoInfo::builder(crate::VideoFormat::Rgba, 320, 240)
.build()
.unwrap();
let out_video_info = crate::VideoInfo::builder(crate::VideoFormat::Rgba, 640, 480)
.build()
.unwrap();
meta.transform(
buffer2.get_mut().unwrap(),
&VideoMetaTransformScale::new(&in_video_info, &out_video_info),
)
.unwrap();
let meta2 = buffer2.meta::<VideoCropMeta>().unwrap();
assert_eq!(meta2.rect(), (20, 20, 40, 40));
}
}