gstreamer-rs/gstreamer-analytics/src/relation_meta.rs

707 lines
21 KiB
Rust

// Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::*;
use gst::prelude::*;
use std::marker::PhantomData;
use crate::RelTypes;
#[repr(transparent)]
#[doc(alias = "GstAnalyticsRelationMeta")]
pub struct AnalyticsRelationMeta(ffi::GstAnalyticsRelationMeta);
unsafe impl Send for AnalyticsRelationMeta {}
unsafe impl Sync for AnalyticsRelationMeta {}
#[derive(Debug, Copy, Clone)]
#[doc(alias = "GstAnalyticsRelationMetaInitParams")]
pub struct AnalyticsRelationMetaInitParams(ffi::GstAnalyticsRelationMetaInitParams);
impl Default for AnalyticsRelationMetaInitParams {
fn default() -> Self {
Self(ffi::GstAnalyticsRelationMetaInitParams {
initial_relation_order: 0,
initial_buf_size: 0,
})
}
}
impl AnalyticsRelationMetaInitParams {
pub fn new(initial_relation_order: usize, initial_buf_size: usize) -> Self {
skip_assert_initialized!();
Self(ffi::GstAnalyticsRelationMetaInitParams {
initial_relation_order,
initial_buf_size,
})
}
}
#[derive(Debug, Clone)]
pub struct AnalyticsMtdRef<'a, T: AnalyticsMtd> {
id: u32,
meta: gst::MetaRef<'a, AnalyticsRelationMeta>,
mtd_type: PhantomData<&'a T>,
}
#[derive(Debug)]
pub struct AnalyticsMtdRefMut<'a, T: AnalyticsMtd> {
id: u32,
meta: &'a mut gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>,
mtd_type: PhantomData<&'a T>,
}
pub struct AnalyticsRelationPath {
garray: *mut glib::ffi::GArray,
}
impl std::fmt::Debug for AnalyticsRelationMeta {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
f.debug_struct("AnalyticsRelationMeta")
.field("len", &self.len())
.finish()
}
}
impl AnalyticsRelationMeta {
#[doc(alias = "gst_buffer_add_analytics_relation_meta")]
pub fn add(buffer: &mut gst::BufferRef) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
skip_assert_initialized!();
unsafe {
let meta_ptr = ffi::gst_buffer_add_analytics_relation_meta(buffer.as_mut_ptr());
Self::from_mut_ptr(buffer, meta_ptr)
}
}
#[doc(alias = "gst_buffer_add_analytics_relation_meta_full")]
pub fn add_full<'a>(
buffer: &'a mut gst::BufferRef,
init_params: &AnalyticsRelationMetaInitParams,
) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
skip_assert_initialized!();
unsafe {
let meta_ptr = ffi::gst_buffer_add_analytics_relation_meta_full(
buffer.as_mut_ptr(),
mut_override(&init_params.0),
);
Self::from_mut_ptr(buffer, meta_ptr)
}
}
#[doc(alias = "gst_analytics_relation_get_length")]
pub fn len(&self) -> usize {
unsafe { ffi::gst_analytics_relation_get_length(self.as_mut_ptr()) }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[doc(alias = "gst_analytics_relation_meta_set_relation")]
pub fn set_relation(
&mut self,
type_: crate::RelTypes,
an_meta_first_id: u32,
an_meta_second_id: u32,
) -> Result<(), glib::BoolError> {
let ret = unsafe {
from_glib(ffi::gst_analytics_relation_meta_set_relation(
self.as_mut_ptr(),
type_.into_glib(),
an_meta_first_id,
an_meta_second_id,
))
};
if ret {
Ok(())
} else {
Err(glib::bool_error!(
"Could not set relation {:}->{:} of type {:?}",
an_meta_first_id,
an_meta_second_id,
type_
))
}
}
#[doc(alias = "gst_analytics_relation_meta_get_relation")]
pub fn relation(&self, an_meta_first_id: u32, an_meta_second_id: u32) -> crate::RelTypes {
unsafe {
from_glib(ffi::gst_analytics_relation_meta_get_relation(
self.as_mut_ptr(),
an_meta_first_id,
an_meta_second_id,
))
}
}
#[doc(alias = "gst_analytics_relation_meta_exist")]
pub fn exist(
&self,
an_meta_first_id: u32,
an_meta_second_id: u32,
relation_span: i32,
cond_types: crate::RelTypes,
) -> bool {
unsafe {
from_glib(ffi::gst_analytics_relation_meta_exist(
self.as_mut_ptr(),
an_meta_first_id,
an_meta_second_id,
relation_span,
cond_types.into_glib(),
std::ptr::null_mut(),
))
}
}
#[doc(alias = "gst_analytics_relation_meta_exist")]
pub fn exist_path(
&self,
an_meta_first_id: u32,
an_meta_second_id: u32,
relation_span: i32,
cond_types: crate::RelTypes,
) -> Result<AnalyticsRelationPath, glib::BoolError> {
let mut array = std::ptr::null_mut::<glib::ffi::GArray>();
let ret = unsafe {
from_glib(ffi::gst_analytics_relation_meta_exist(
self.as_mut_ptr(),
an_meta_first_id,
an_meta_second_id,
relation_span,
cond_types.into_glib(),
&mut array,
))
};
if ret {
Ok(AnalyticsRelationPath { garray: array })
} else {
Err(glib::bool_error!("Such relation doesn't exist"))
}
}
pub unsafe fn as_mut_ptr(&self) -> *mut ffi::GstAnalyticsRelationMeta {
mut_override(&self.0)
}
}
impl UnsafeFrom<&AnalyticsRelationMeta> for ffi::GstAnalyticsMtd {
unsafe fn unsafe_from(t: &AnalyticsRelationMeta) -> Self {
ffi::GstAnalyticsMtd {
id: 0,
meta: t.as_mut_ptr(),
}
}
}
impl AnalyticsRelationPath {
pub fn as_slice(&self) -> &[u32] {
unsafe {
std::slice::from_raw_parts(
(*self.garray).data as *const u32,
(*self.garray).len as usize,
)
}
}
}
impl Drop for AnalyticsRelationPath {
fn drop(&mut self) {
unsafe {
glib::ffi::g_array_free(self.garray, glib::ffi::GTRUE);
}
}
}
mod sealed {
pub trait Sealed {}
impl<T> Sealed for T {}
}
pub trait AnalyticsMetaRefExt<'a>: sealed::Sealed {
#[doc(alias = "gst_analytics_relation_meta_get_mtd")]
fn mtd<T: AnalyticsMtd>(&self, an_meta_id: u32) -> Option<AnalyticsMtdRef<'a, T>>;
fn iter<T: AnalyticsMtd>(&'a self) -> AnalyticsMtdIter<T>;
fn iter_direct_related<T: AnalyticsMtd>(
&'a self,
an_meta_id: u32,
rel_type: RelTypes,
) -> AnalyticsMtdIter<T>;
}
impl<'a> AnalyticsMetaRefExt<'a> for gst::MetaRef<'a, AnalyticsRelationMeta> {
fn mtd<T: AnalyticsMtd>(&self, an_meta_id: u32) -> Option<AnalyticsMtdRef<'a, T>> {
unsafe {
let mut mtd = std::mem::MaybeUninit::uninit();
let ret = from_glib(ffi::gst_analytics_relation_meta_get_mtd(
self.as_mut_ptr(),
an_meta_id,
T::mtd_type(),
mtd.as_mut_ptr(),
));
let id = mtd.assume_init().id;
if ret {
Some(AnalyticsMtdRef::from_meta(self, id))
} else {
None
}
}
}
fn iter<T: AnalyticsMtd>(&'a self) -> AnalyticsMtdIter<'a, T> {
AnalyticsMtdIter::new(self)
}
fn iter_direct_related<T: AnalyticsMtd>(
&'a self,
an_meta_id: u32,
rel_type: RelTypes,
) -> AnalyticsMtdIter<T> {
AnalyticsMtdIter::new_direct_related(self, an_meta_id, rel_type.into_glib())
}
}
impl<'a, T: AnalyticsMtd> AnalyticsMtdRef<'a, T> {
pub fn id(&self) -> u32 {
self.id
}
pub unsafe fn from_meta(meta: &gst::MetaRef<'a, AnalyticsRelationMeta>, id: u32) -> Self {
skip_assert_initialized!();
AnalyticsMtdRef {
meta: meta.clone(),
id,
mtd_type: PhantomData,
}
}
#[doc(alias = "gst_analytics_mtd_get_mtd_type")]
pub fn mtd_type(&self) -> ffi::GstAnalyticsMtdType {
unsafe {
let mut mtd = ffi::GstAnalyticsMtd::unsafe_from(self);
ffi::gst_analytics_mtd_get_mtd_type(&mut mtd)
}
}
}
impl<'a> AnalyticsMtdRef<'a, AnalyticsAnyMtd> {
pub fn downcast<T: AnalyticsMtd>(
self,
) -> Result<AnalyticsMtdRef<'a, T>, AnalyticsMtdRef<'a, AnalyticsAnyMtd>> {
if self.mtd_type() == T::mtd_type() {
Ok(AnalyticsMtdRef {
id: self.id,
meta: self.meta,
mtd_type: PhantomData,
})
} else {
Err(self)
}
}
pub fn downcast_ref<T: AnalyticsMtd>(&self) -> Option<&AnalyticsMtdRef<'a, T>> {
unsafe {
if self.mtd_type() == T::mtd_type() {
Some(&*(self as *const _ as *const _))
} else {
None
}
}
}
}
impl<'a> AnalyticsMtdRefMut<'a, AnalyticsAnyMtd> {
pub fn downcast_mut<T: AnalyticsMtd>(&mut self) -> Option<&mut AnalyticsMtdRefMut<'a, T>> {
unsafe {
if self.as_ref().mtd_type() == T::mtd_type() {
Some(&mut *(self as *mut _ as *mut _))
} else {
None
}
}
}
}
impl<'a, T: AnalyticsMtd> UnsafeFrom<&AnalyticsMtdRef<'a, T>> for ffi::GstAnalyticsMtd {
unsafe fn unsafe_from(t: &AnalyticsMtdRef<'a, T>) -> Self {
ffi::GstAnalyticsMtd {
id: t.id,
meta: t.meta.as_mut_ptr(),
}
}
}
pub trait AnalyticsMetaRefMutExt<'a>: sealed::Sealed {
#[doc(alias = "gst_analytics_relation_meta_get_mtd")]
fn mtd_mut<T: AnalyticsMtd>(&'a mut self, an_meta_id: u32)
-> Option<AnalyticsMtdRefMut<'a, T>>;
fn iter_mut<T: AnalyticsMtd>(&'a mut self) -> AnalyticsMtdIterMut<T>;
fn iter_direct_related_mut<T: AnalyticsMtd>(
&'a mut self,
an_meta_id: u32,
rel_type: RelTypes,
) -> AnalyticsMtdIterMut<T>;
}
impl<'a> AnalyticsMetaRefMutExt<'a>
for gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>
{
fn mtd_mut<T: AnalyticsMtd>(
&'a mut self,
an_meta_id: u32,
) -> Option<AnalyticsMtdRefMut<'a, T>> {
unsafe {
let mut mtd = std::mem::MaybeUninit::uninit();
let ret = from_glib(ffi::gst_analytics_relation_meta_get_mtd(
self.as_mut_ptr(),
an_meta_id,
T::mtd_type(),
mtd.as_mut_ptr(),
));
let id = mtd.assume_init().id;
if ret {
Some(AnalyticsMtdRefMut::from_meta(self, id))
} else {
None
}
}
}
fn iter_mut<T: AnalyticsMtd>(&'a mut self) -> AnalyticsMtdIterMut<T> {
AnalyticsMtdIterMut::new(self)
}
fn iter_direct_related_mut<T: AnalyticsMtd>(
&'a mut self,
an_meta_id: u32,
rel_type: RelTypes,
) -> AnalyticsMtdIterMut<T> {
AnalyticsMtdIterMut::new_direct_related(self, an_meta_id, rel_type.into_glib())
}
}
unsafe impl MetaAPI for AnalyticsRelationMeta {
type GstType = ffi::GstAnalyticsRelationMeta;
#[doc(alias = "gst_analytics_relation_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::gst_analytics_relation_meta_api_get_type()) }
}
}
pub unsafe trait AnalyticsMtd {
fn mtd_type() -> ffi::GstAnalyticsMtdType;
}
pub trait AnalyticsMtdExt: AnalyticsMtd {
#[doc(alias = "gst_analytics_mtd_type_get_name")]
fn type_name() -> &'static str {
unsafe {
let ptr = ffi::gst_analytics_mtd_type_get_name(Self::mtd_type());
std::ffi::CStr::from_ptr(ptr).to_str().unwrap()
}
}
}
impl<T: AnalyticsMtd> AnalyticsMtdExt for T {}
impl<'a, T: AnalyticsMtd> AnalyticsMtdRefMut<'a, T> {
pub fn id(&self) -> u32 {
self.id
}
pub unsafe fn from_meta(
meta: &'a mut gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>,
id: u32,
) -> Self {
skip_assert_initialized!();
AnalyticsMtdRefMut {
meta,
id,
mtd_type: PhantomData,
}
}
}
impl<'a, T: AnalyticsMtd> UnsafeFrom<&mut AnalyticsMtdRefMut<'a, T>> for ffi::GstAnalyticsMtd {
unsafe fn unsafe_from(t: &mut AnalyticsMtdRefMut<'a, T>) -> Self {
ffi::GstAnalyticsMtd {
id: t.id,
meta: t.meta.as_mut_ptr(),
}
}
}
impl<'a, T: AnalyticsMtd> From<AnalyticsMtdRefMut<'a, T>> for AnalyticsMtdRef<'a, T> {
fn from(value: AnalyticsMtdRefMut<'a, T>) -> Self {
skip_assert_initialized!();
AnalyticsMtdRef {
meta: value.meta.as_ref().clone(),
id: value.id,
mtd_type: value.mtd_type,
}
}
}
impl<'a, T: AnalyticsMtd> From<&mut AnalyticsMtdRefMut<'a, T>> for AnalyticsMtdRef<'a, T> {
fn from(value: &mut AnalyticsMtdRefMut<'a, T>) -> Self {
skip_assert_initialized!();
AnalyticsMtdRef {
meta: value.meta.as_ref().clone(),
id: value.id,
mtd_type: value.mtd_type,
}
}
}
impl<'a, T: AnalyticsMtd> AsRef<AnalyticsMtdRef<'a, T>> for AnalyticsMtdRefMut<'a, T> {
#[inline]
fn as_ref(&self) -> &AnalyticsMtdRef<'a, T> {
unsafe { &*(self as *const AnalyticsMtdRefMut<'a, T> as *const AnalyticsMtdRef<'a, T>) }
}
}
macro_rules! define_mtd_iter {
($name:ident, $metaref:ty, $itemref:ty, $copy_meta:expr) => {
pub struct $name<'a, T: AnalyticsMtd> {
meta: $metaref,
state: glib::ffi::gpointer,
mtd_type: ffi::GstAnalyticsMtdType,
an_meta_id: u32,
rel_type: ffi::GstAnalyticsRelTypes,
phantom: std::marker::PhantomData<T>,
}
impl<'a, T: AnalyticsMtd> $name<'a, T> {
fn new(meta: $metaref) -> Self {
skip_assert_initialized!();
$name {
meta,
state: std::ptr::null_mut(),
mtd_type: T::mtd_type(),
an_meta_id: std::u32::MAX,
rel_type: RelTypes::ANY.into_glib(),
phantom: PhantomData,
}
}
fn new_direct_related(
meta: $metaref,
an_meta_id: u32,
rel_type: ffi::GstAnalyticsRelTypes,
) -> Self {
skip_assert_initialized!();
$name {
meta,
state: std::ptr::null_mut(),
mtd_type: T::mtd_type(),
an_meta_id,
rel_type,
phantom: PhantomData,
}
}
}
impl<'a, T: AnalyticsMtd + 'a> Iterator for $name<'a, T> {
type Item = $itemref;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let mut mtd = ffi::GstAnalyticsMtd::unsafe_from(&**self.meta);
let ret = {
if self.an_meta_id == std::u32::MAX {
ffi::gst_analytics_relation_meta_iterate(
self.meta.as_mut_ptr(),
&mut self.state,
self.mtd_type,
&mut mtd,
)
} else {
ffi::gst_analytics_relation_meta_get_direct_related(
self.meta.as_mut_ptr(),
self.an_meta_id,
self.rel_type,
self.mtd_type,
&mut self.state,
&mut mtd,
)
}
};
if from_glib(ret) {
// This is a known clippy limitation
// https://github.com/rust-lang/rust-clippy/issues/1553
#[allow(clippy::redundant_closure_call)]
Some(Self::Item::from_meta($copy_meta(self.meta), mtd.id))
} else {
None
}
}
}
}
};
}
define_mtd_iter!(
AnalyticsMtdIter,
&'a gst::MetaRef<'a, AnalyticsRelationMeta>,
AnalyticsMtdRef<'a, T>,
|meta| meta
);
define_mtd_iter!(
AnalyticsMtdIterMut,
&'a mut gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>,
AnalyticsMtdRefMut<'a, T>,
|meta: &mut _| &mut *(meta as *mut gst::MetaRefMut<
'a,
AnalyticsRelationMeta,
gst::meta::Standalone,
>)
);
#[derive(Debug)]
pub enum AnalyticsAnyMtd {}
unsafe impl AnalyticsMtd for AnalyticsAnyMtd {
fn mtd_type() -> ffi::GstAnalyticsMtdType {
ffi::GST_ANALYTICS_MTD_TYPE_ANY as ffi::GstAnalyticsMtdType
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn build_relation_meta() {
gst::init().unwrap();
let mut buf = gst::Buffer::new();
let meta = AnalyticsRelationMeta::add(buf.make_mut());
assert!(meta.is_empty());
}
#[test]
fn build_relation_meta_full() {
gst::init().unwrap();
let mut buf = gst::Buffer::new();
let params = AnalyticsRelationMetaInitParams::new(10, 10);
let meta = AnalyticsRelationMeta::add_full(buf.make_mut(), &params);
assert!(meta.is_empty());
}
#[test]
fn relations() {
gst::init().unwrap();
let mut buf = gst::Buffer::new();
let _ = AnalyticsRelationMeta::add(buf.make_mut());
let mut meta = buf.make_mut().meta_mut::<AnalyticsRelationMeta>().unwrap();
let od = meta
.add_od_mtd(glib::Quark::from_str("blb"), 0, 1, 10, 20, 0.8)
.unwrap();
let od1_id = od.id();
let od = meta
.add_od_mtd(glib::Quark::from_str("blb"), 0, 1, 10, 20, 0.8)
.unwrap();
let od2_id = od.id();
let od: AnalyticsMtdRef<'_, AnalyticsODMtd> = meta
.add_od_mtd(glib::Quark::from_str("blb"), 0, 1, 10, 20, 0.8)
.unwrap();
let od3_id = od.id();
meta.set_relation(RelTypes::IS_PART_OF, od1_id, od2_id)
.unwrap();
meta.set_relation(RelTypes::IS_PART_OF, od2_id, od3_id)
.unwrap();
meta.set_relation(RelTypes::IS_PART_OF, 8888, 9999)
.expect_err("Invalid id");
let meta = buf.meta::<AnalyticsRelationMeta>().unwrap();
assert!(meta.relation(od1_id, od2_id) == crate::RelTypes::IS_PART_OF);
assert!(meta.relation(od2_id, od3_id) == crate::RelTypes::IS_PART_OF);
assert!(meta.exist(od1_id, od2_id, 1, crate::RelTypes::IS_PART_OF));
assert!(meta.exist(od1_id, od3_id, 2, crate::RelTypes::IS_PART_OF));
assert!(!meta.exist(od2_id, od1_id, 1, crate::RelTypes::IS_PART_OF));
assert!(!meta.exist(od1_id, od3_id, 1, crate::RelTypes::IS_PART_OF));
assert!(!meta.exist(od1_id, od2_id, 1, crate::RelTypes::CONTAIN));
let path = meta
.exist_path(od1_id, od3_id, 3, crate::RelTypes::ANY)
.unwrap();
assert_eq!(path.as_slice().len(), 3);
assert_eq!(path.as_slice()[0], od1_id);
assert_eq!(path.as_slice()[1], od2_id);
assert_eq!(path.as_slice()[2], od3_id);
assert_eq!(meta.len(), meta.iter::<AnalyticsAnyMtd>().count());
assert_eq!(meta.len(), meta.iter::<AnalyticsODMtd>().count());
for mtd in meta.iter::<AnalyticsODMtd>() {
assert_eq!(mtd.obj_type().unwrap(), glib::Quark::from_str("blb"))
}
assert_eq!(meta.len(), meta.iter::<AnalyticsAnyMtd>().count());
for mtd in meta.iter::<AnalyticsAnyMtd>() {
if let Ok(mtd) = mtd.downcast::<AnalyticsODMtd>() {
assert_eq!(mtd.obj_type().unwrap(), glib::Quark::from_str("blb"))
}
}
assert_eq!(
meta.iter_direct_related::<AnalyticsODMtd>(od1_id, crate::RelTypes::IS_PART_OF)
.count(),
1
);
assert_eq!(
meta.iter_direct_related::<AnalyticsODMtd>(od2_id, crate::RelTypes::IS_PART_OF)
.count(),
1
);
assert_eq!(
meta.iter_direct_related::<AnalyticsODMtd>(od3_id, crate::RelTypes::IS_PART_OF)
.count(),
0
);
assert_eq!(
meta.iter_direct_related::<AnalyticsODMtd>(od1_id, crate::RelTypes::CONTAIN)
.count(),
0
);
assert_eq!(
meta.iter_direct_related::<AnalyticsAnyMtd>(od1_id, crate::RelTypes::CONTAIN)
.count(),
0
);
for mtd in meta.iter_direct_related::<AnalyticsODMtd>(od1_id, crate::RelTypes::IS_PART_OF) {
assert_eq!(mtd.obj_type().unwrap(), glib::Quark::from_str("blb"))
}
let mut meta = buf.make_mut().meta_mut::<AnalyticsRelationMeta>().unwrap();
assert_eq!(meta.len(), meta.iter_mut::<AnalyticsAnyMtd>().count());
let mut meta = buf.make_mut().meta_mut::<AnalyticsRelationMeta>().unwrap();
let _ = meta.add_tracking_mtd(10, gst::ClockTime::from_seconds(10));
let _ = meta.add_tracking_mtd(10, gst::ClockTime::from_seconds(10));
for mut item in meta.iter_mut::<AnalyticsTrackingMtd>() {
item.set_lost().unwrap();
}
}
}