Skip to main content

gstreamer_analytics/
classification.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::translate::*;
4
5use crate::{ffi, relation_meta::*};
6
7#[derive(Debug)]
8pub enum AnalyticsClassificationMtd {}
9
10mod sealed {
11    pub trait Sealed {}
12    impl<T: super::AnalyticsRelationMetaClassificationExt> Sealed for T {}
13}
14
15pub trait AnalyticsRelationMetaClassificationExt: sealed::Sealed {
16    fn add_one_cls_mtd(
17        &mut self,
18        confidence_level: f32,
19        class_quark: glib::Quark,
20    ) -> Result<AnalyticsMtdRef<'_, AnalyticsClassificationMtd>, glib::BoolError>;
21
22    fn add_cls_mtd(
23        &mut self,
24        confidence_levels: &[f32],
25        class_quarks: &[glib::Quark],
26    ) -> Result<AnalyticsMtdRef<'_, AnalyticsClassificationMtd>, glib::BoolError>;
27}
28
29impl<'a> AnalyticsRelationMetaClassificationExt
30    for gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>
31{
32    #[doc(alias = "gst_analytics_relation_meta_add_one_cls_mtd")]
33    fn add_one_cls_mtd(
34        &mut self,
35        confidence_level: f32,
36        class_quark: glib::Quark,
37    ) -> Result<AnalyticsMtdRef<'a, AnalyticsClassificationMtd>, glib::BoolError> {
38        unsafe {
39            let mut mtd = std::mem::MaybeUninit::uninit();
40            let ret = from_glib(ffi::gst_analytics_relation_meta_add_one_cls_mtd(
41                self.as_mut_ptr(),
42                confidence_level,
43                class_quark.into_glib(),
44                mtd.as_mut_ptr(),
45            ));
46            let id = mtd.assume_init().id;
47
48            if ret {
49                Ok(AnalyticsMtdRef::from_meta(self.as_ref(), id))
50            } else {
51                Err(glib::bool_error!("Couldn't add more data"))
52            }
53        }
54    }
55
56    #[doc(alias = "gst_analytics_relation_meta_add_cls_mtd")]
57    fn add_cls_mtd(
58        &mut self,
59        confidence_levels: &[f32],
60        class_quarks: &[glib::Quark],
61    ) -> Result<AnalyticsMtdRef<'a, AnalyticsClassificationMtd>, glib::BoolError> {
62        let length = std::cmp::min(confidence_levels.len(), class_quarks.len());
63        unsafe {
64            let mut mtd = std::mem::MaybeUninit::uninit();
65            let ret = from_glib(ffi::gst_analytics_relation_meta_add_cls_mtd(
66                self.as_mut_ptr(),
67                length,
68                mut_override(confidence_levels.as_ptr()),
69                class_quarks.as_ptr() as *mut _,
70                mtd.as_mut_ptr(),
71            ));
72            let id = mtd.assume_init().id;
73
74            if ret {
75                Ok(AnalyticsMtdRef::from_meta(self.as_ref(), id))
76            } else {
77                Err(glib::bool_error!("Couldn't add more data"))
78            }
79        }
80    }
81}
82
83unsafe impl AnalyticsMtd for AnalyticsClassificationMtd {
84    #[doc(alias = "gst_analytics_cls_mtd_get_mtd_type")]
85    fn mtd_type() -> ffi::GstAnalyticsMtdType {
86        unsafe { ffi::gst_analytics_cls_mtd_get_mtd_type() }
87    }
88}
89
90impl AnalyticsMtdRef<'_, AnalyticsClassificationMtd> {
91    #[doc(alias = "gst_analytics_cls_mtd_get_length")]
92    pub fn len(&self) -> usize {
93        unsafe {
94            let mtd = ffi::GstAnalyticsMtd::unsafe_from(self);
95            ffi::gst_analytics_cls_mtd_get_length(
96                &mtd as *const _ as *const ffi::GstAnalyticsClsMtd,
97            )
98        }
99    }
100
101    pub fn is_empty(&self) -> bool {
102        self.len() == 0
103    }
104
105    #[doc(alias = "gst_analytics_cls_mtd_get_level")]
106    pub fn level(&self, index: usize) -> f32 {
107        assert!(index < self.len());
108
109        unsafe {
110            let mtd = ffi::GstAnalyticsMtd::unsafe_from(self);
111            ffi::gst_analytics_cls_mtd_get_level(
112                &mtd as *const _ as *const ffi::GstAnalyticsClsMtd,
113                index,
114            )
115        }
116    }
117
118    #[doc(alias = "gst_analytics_cls_mtd_get_quark")]
119    pub fn quark(&self, index: usize) -> glib::Quark {
120        assert!(index < self.len());
121
122        unsafe {
123            let mtd = ffi::GstAnalyticsMtd::unsafe_from(self);
124            from_glib(ffi::gst_analytics_cls_mtd_get_quark(
125                &mtd as *const _ as *const ffi::GstAnalyticsClsMtd,
126                index,
127            ))
128        }
129    }
130
131    pub fn iterate(&self) -> AnalyticsClassificationIterator<'_> {
132        AnalyticsClassificationIterator {
133            mtd: self,
134            index: 0,
135            length: self.len(),
136        }
137    }
138}
139
140#[must_use = "iterators are lazy and do nothing unless consumed"]
141pub struct AnalyticsClassificationIterator<'a> {
142    mtd: &'a AnalyticsMtdRef<'a, AnalyticsClassificationMtd>,
143    index: usize,
144    length: usize,
145}
146
147impl Iterator for AnalyticsClassificationIterator<'_> {
148    type Item = (glib::Quark, f32);
149
150    fn next(&mut self) -> Option<Self::Item> {
151        if self.index == self.length {
152            None
153        } else {
154            let ret = Some((self.mtd.quark(self.index), self.mtd.level(self.index)));
155            self.index += 1;
156            ret
157        }
158    }
159}
160
161#[cfg(test)]
162mod tests {
163    use crate::*;
164
165    #[test]
166    fn one_class() {
167        gst::init().unwrap();
168
169        assert_eq!(AnalyticsClassificationMtd::type_name(), "classification");
170
171        let mut buf = gst::Buffer::new();
172        let mut meta = AnalyticsRelationMeta::add(buf.make_mut());
173
174        assert!(meta.is_empty());
175
176        let cls = meta
177            .add_one_cls_mtd(0.7, glib::Quark::from_str("class1"))
178            .unwrap();
179
180        assert_eq!(cls.len(), 1);
181        assert_eq!(cls.level(0), 0.7);
182        assert_eq!(cls.quark(0), glib::Quark::from_str("class1"));
183    }
184
185    #[test]
186    fn many_classes() {
187        gst::init().unwrap();
188
189        assert_eq!(AnalyticsClassificationMtd::type_name(), "classification");
190
191        let mut buf = gst::Buffer::new();
192        let mut meta = AnalyticsRelationMeta::add(buf.make_mut());
193
194        assert!(meta.is_empty());
195
196        let classes = [
197            glib::Quark::from_str("a"),
198            glib::Quark::from_str("b"),
199            glib::Quark::from_str("c"),
200            glib::Quark::from_str("d"),
201        ];
202        let levels = [0.1, 0.2, 0.3, 0.4];
203
204        let cls = meta.add_cls_mtd(&levels, &classes).unwrap();
205
206        assert_eq!(cls.len(), 4);
207        for i in 0..4usize {
208            assert_eq!(cls.level(i), levels[i]);
209            assert_eq!(cls.quark(i), classes[i]);
210        }
211
212        for (i, (q, l)) in cls.iterate().enumerate() {
213            assert_eq!(l, levels[i]);
214            assert_eq!(q, classes[i]);
215        }
216    }
217}