diff --git a/Cargo.lock b/Cargo.lock index 0589e3745..e3bd3ef9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -881,6 +881,29 @@ dependencies = [ "tempfile", ] +[[package]] +name = "gstreamer-analytics" +version = "0.22.0" +dependencies = [ + "gir-format-check", + "glib", + "gstreamer", + "gstreamer-analytics-sys", + "libc", +] + +[[package]] +name = "gstreamer-analytics-sys" +version = "0.22.0" +dependencies = [ + "glib-sys", + "gstreamer-sys", + "libc", + "shell-words", + "system-deps", + "tempfile", +] + [[package]] name = "gstreamer-app" version = "0.22.0" diff --git a/Cargo.toml b/Cargo.toml index 17164c80b..b417e65dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ resolver = "2" default-members = [ "gstreamer/sys", + "gstreamer-analytics/sys", "gstreamer-app/sys", "gstreamer-audio/sys", "gstreamer-base/sys", @@ -22,6 +23,7 @@ default-members = [ "gstreamer-video/sys", "gstreamer-webrtc/sys", "gstreamer", + "gstreamer-analytics", "gstreamer-app", "gstreamer-audio", "gstreamer-base", @@ -47,6 +49,7 @@ default-members = [ members = [ "gstreamer/sys", + "gstreamer-analytics/sys", "gstreamer-app/sys", "gstreamer-audio/sys", "gstreamer-base/sys", @@ -71,6 +74,7 @@ members = [ "gstreamer-webrtc/sys", "gstreamer-allocators/sys", "gstreamer", + "gstreamer-analytics", "gstreamer-app", "gstreamer-audio", "gstreamer-base", diff --git a/ci/run-clippy.sh b/ci/run-clippy.sh index 8ae00b0d9..341d84d87 100755 --- a/ci/run-clippy.sh +++ b/ci/run-clippy.sh @@ -13,7 +13,7 @@ get_features() { gstreamer-audio|gstreamer-editing-services|gstreamer-gl|gstreamer-pbutils|gstreamer-rtp|gstreamer-rtsp|gstreamer-video|gstreamer) echo "--features=serde,v1_24" ;; - gstreamer-validate) + gstreamer-analytics) echo "" ;; *) diff --git a/gst-gir-files b/gst-gir-files index 3f9f549ac..63e90a301 160000 --- a/gst-gir-files +++ b/gst-gir-files @@ -1 +1 @@ -Subproject commit 3f9f549accb70d139a2ae049d36f32c059398060 +Subproject commit 63e90a30193bf8d228057c4570a50a0a2b40f2bd diff --git a/gstreamer-allocators/src/auto/versions.txt b/gstreamer-allocators/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-allocators/src/auto/versions.txt +++ b/gstreamer-allocators/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-allocators/sys/src/auto/versions.txt b/gstreamer-allocators/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-allocators/sys/src/auto/versions.txt +++ b/gstreamer-allocators/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-analytics/CHANGELOG.md b/gstreamer-analytics/CHANGELOG.md new file mode 120000 index 000000000..670919a56 --- /dev/null +++ b/gstreamer-analytics/CHANGELOG.md @@ -0,0 +1 @@ +../gstreamer/CHANGELOG.md \ No newline at end of file diff --git a/gstreamer-analytics/COPYRIGHT b/gstreamer-analytics/COPYRIGHT new file mode 120000 index 000000000..dc5f40a22 --- /dev/null +++ b/gstreamer-analytics/COPYRIGHT @@ -0,0 +1 @@ +../COPYRIGHT \ No newline at end of file diff --git a/gstreamer-analytics/Cargo.toml b/gstreamer-analytics/Cargo.toml new file mode 100644 index 000000000..88869b2f2 --- /dev/null +++ b/gstreamer-analytics/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "gstreamer-analytics" +authors = ["Olivier CrĂȘte "] +description = "Rust bindings for GStreamer Analytics library" +license = "MIT OR Apache-2.0" +readme = "README.md" +documentation = "https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer_analytics/" +keywords = ["gstreamer", "multimedia", "audio", "video", "gnome"] +version.workspace = true +categories.workspace = true +repository.workspace = true +homepage.workspace = true +edition.workspace = true +rust-version.workspace = true + +[dependencies] +libc = "0.2" +ffi = { package = "gstreamer-analytics-sys", path = "sys" } +glib.workspace = true +gst.workspace = true + +[dev-dependencies] +gir-format-check = "0.1" + +[features] +default = [] + +[package.metadata.docs.rs] +all-features = true +rustc-args = ["--cfg", "docsrs"] +rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] diff --git a/gstreamer-analytics/Gir.toml b/gstreamer-analytics/Gir.toml new file mode 100644 index 000000000..ef55a1da8 --- /dev/null +++ b/gstreamer-analytics/Gir.toml @@ -0,0 +1,34 @@ +[options] +girs_directories = ["../gir-files", "../gst-gir-files"] +library = "GstAnalytics" +version = "1.0" +min_cfg_version = "1.24" +work_mode = "normal" +concurrency = "send+sync" +generate_safety_asserts = true +single_version_file = true +generate_display_trait = false +trust_return_value_nullability = true + +external_libraries = [ + "GLib", + "GObject", + "Gst", +] + +generate = [ + "GstAnalytics.RelTypes" +] + +manual = [ + "GObject.Object", + "Gst.Element", + "Gst.MiniObject", + "Gst.Object" +] + + +[[object]] +name = "Gst.Buffer" +status = "manual" +ref_mode = "ref" diff --git a/gstreamer-analytics/LICENSE-APACHE b/gstreamer-analytics/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/gstreamer-analytics/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/gstreamer-analytics/LICENSE-MIT b/gstreamer-analytics/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/gstreamer-analytics/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/gstreamer-analytics/README.md b/gstreamer-analytics/README.md new file mode 100644 index 000000000..3252a810c --- /dev/null +++ b/gstreamer-analytics/README.md @@ -0,0 +1,214 @@ +# gstreamer-rs [![crates.io](https://img.shields.io/crates/v/gstreamer-app.svg)](https://crates.io/crates/gstreamer-app) [![pipeline status](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/badges/main/pipeline.svg)](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/commits/main) + +[GStreamer](https://gstreamer.freedesktop.org/) (App library) bindings for Rust. +Documentation can be found [here](https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer_app/). + +These bindings are providing a safe API that can be used to interface with +GStreamer, e.g. for writing GStreamer-based applications and GStreamer plugins. + +The bindings are mostly autogenerated with [gir](https://github.com/gtk-rs/gir/) +based on the [GObject-Introspection](https://wiki.gnome.org/Projects/GObjectIntrospection/) +API metadata provided by the GStreamer project. + +## Table of Contents +1. [Installation](#installation) + 1. [Linux/BSDs](#installation-linux) + 1. [macOS](#installation-macos) + 1. [Windows](#installation-windows) +1. [Getting Started](#getting-started) +1. [License](#license) +1. [Contribution](#contribution) + + + +## Installation + +To build the GStreamer bindings or anything depending on them, you need to +have at least GStreamer 1.14 and gst-plugins-base 1.14 installed. In addition, +some of the examples/tutorials require various GStreamer plugins to be +available, which can be found in gst-plugins-base, gst-plugins-good, +gst-plugins-bad, gst-plugins-ugly and/or gst-libav. + + + +### Linux/BSDs + +You need to install the above mentioned packages with your distributions +package manager, or build them from source. + +On Debian/Ubuntu they can be installed with + +```console +$ apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ + gstreamer1.0-plugins-base gstreamer1.0-plugins-good \ + gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \ + gstreamer1.0-libav libgstrtspserver-1.0-dev libges-1.0-dev +``` + +The minimum required version of the above libraries is >= 1.14. If you +build the gstreamer-player sub-crate, or any of the examples that +depend on gstreamer-player, you must ensure that in addition to the above +packages, `libgstreamer-plugins-bad1.0-dev` is installed. See the `Cargo.toml` +files for the full details, + +```console +$ apt-get install libgstreamer-plugins-bad1.0-dev +``` + +Package names on other distributions should be similar. +Please submit a pull request with instructions for yours. + + + +### macOS + +You can install GStreamer and the plugins via [Homebrew](https://brew.sh/) or +by installing the [binaries](https://gstreamer.freedesktop.org/data/pkg/osx/) +provided by the GStreamer project. + +We recommend using the official GStreamer binaries over Homebrew, especially +as GStreamer in Homebrew is [currently broken](https://github.com/orgs/Homebrew/discussions/3740#discussioncomment-3804964). + +#### GStreamer Binaries + +You need to download the *two* `.pkg` files from the GStreamer website and +install them, e.g. `gstreamer-1.0-1.20.4-universal.pkg` and +`gstreamer-1.0-devel-1.20.4-universal.pkg`. + +After installation, you also need to set the `PATH` environment variable as +follows + +```console +$ export PATH="/Library/Frameworks/GStreamer.framework/Versions/1.0/bin${PATH:+:$PATH}" +``` + +Also note that the `pkg-config` from GStreamer should be the first one in +the `PATH` as other versions have all kinds of quirks that will cause +problems. + +#### Homebrew + +Homebrew only installs various plugins if explicitly enabled, so some extra +`--with-*` flags may be required. + +```console +$ brew install gstreamer gst-plugins-base gst-plugins-good \ + gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server \ + gst-editing-services --with-orc --with-libogg --with-opus \ + --with-pango --with-theora --with-libvorbis --with-libvpx \ + --enable-gtk3 +``` + +Make sure the version of these libraries is >= 1.14. + + + +### Windows + +You can install GStreamer and the plugins via [MSYS2](http://www.msys2.org/) +with `pacman` or by installing the +[binaries](https://gstreamer.freedesktop.org/data/pkg/windows/) provided by +the GStreamer project. + +We recommend using the official GStreamer binaries over MSYS2. + +#### GStreamer Binaries + +You need to download the *two* `.msi` files for your platform from the +GStreamer website and install them, e.g. `gstreamer-1.0-x86_64-1.20.4.msi` and +`gstreamer-1.0-devel-x86_64-1.20.4.msi`. Make sure to select the version that +matches your Rust toolchain, i.e. MinGW or MSVC. + +After installation set the ``PATH` environment variable as follows: + +```console +# For a UNIX-style shell: +$ export PATH="c:/gstreamer/1.0/msvc_x86_64/bin${PATH:+:$PATH}" + +# For cmd.exe: +$ set PATH=C:\gstreamer\1.0\msvc_x86_64\bin;%PATH% +``` + +Make sure to update the path to where you have actually installed GStreamer +and for the corresponding toolchain. + +Also note that the `pkg-config.exe` from GStreamer should be the first one in +the `PATH` as other versions have all kinds of quirks that will cause +problems. + +#### MSYS2 / pacman + +```console +$ pacman -S glib2-devel pkg-config \ + mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base \ + mingw-w64-x86_64-gst-plugins-good mingw-w64-x86_64-gst-plugins-bad \ + mingw-w64-x86_64-gst-plugins-ugly mingw-w64-x86_64-gst-libav \ + mingw-w64-x86_64-gst-rtsp-server +``` + +Make sure the version of these libraries is >= 1.14. + +Note that the version of `pkg-config` included in `MSYS2` is +[known to have problems](https://github.com/rust-lang/pkg-config-rs/issues/51#issuecomment-346300858) +compiling GStreamer, so you may need to install another version. One option +would be [`pkg-config-lite`](https://sourceforge.net/projects/pkgconfiglite/). + + + +## Getting Started + +The API reference can be found +[here](https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer/), however it is +only the Rust API reference and does not explain any of the concepts. + +For getting started with GStreamer development, the best would be to follow +the [documentation](https://gstreamer.freedesktop.org/documentation/) on the +GStreamer website, especially the [Application Development +Manual](https://gstreamer.freedesktop.org/documentation/application-development/). +While being C-centric, it explains all the fundamental concepts of GStreamer +and the code examples should be relatively easily translatable to Rust. The +API is basically the same, function/struct names are the same and everything +is only more convenient (hopefully) and safer. + +In addition there are +[tutorials](https://gstreamer.freedesktop.org/documentation/tutorials/) on the +GStreamer website. Many of them were ported to Rust already and the code can +be found in the +[tutorials](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/tree/main/tutorials) +directory. + +Some further examples for various aspects of GStreamer and how to use it from +Rust can be found in the +[examples](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/tree/main/examples) +directory. + +Various GStreamer plugins written in Rust can be found in the +[gst-plugins-rs](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs) +repository. + + + +## LICENSE + +gstreamer-rs and all crates contained in here are licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +GStreamer itself is licensed under the Lesser General Public License version +2.1 or (at your option) any later version: +https://www.gnu.org/licenses/lgpl-2.1.html + + + +## Contribution + +Any kinds of contributions are welcome as a pull request. + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in gstreamer-rs by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/gstreamer-analytics/src/auto/flags.rs b/gstreamer-analytics/src/auto/flags.rs new file mode 100644 index 000000000..e7cef0c5f --- /dev/null +++ b/gstreamer-analytics/src/auto/flags.rs @@ -0,0 +1,44 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git) +// DO NOT EDIT + +use glib::{bitflags::bitflags, translate::*}; + +bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + #[doc(alias = "GstAnalyticsRelTypes")] + pub struct RelTypes: u32 { + #[doc(alias = "GST_ANALYTICS_REL_TYPE_NONE")] + const NONE = ffi::GST_ANALYTICS_REL_TYPE_NONE as _; + #[doc(alias = "GST_ANALYTICS_REL_TYPE_IS_PART_OF")] + const IS_PART_OF = ffi::GST_ANALYTICS_REL_TYPE_IS_PART_OF as _; + #[doc(alias = "GST_ANALYTICS_REL_TYPE_CONTAIN")] + const CONTAIN = ffi::GST_ANALYTICS_REL_TYPE_CONTAIN as _; + #[doc(alias = "GST_ANALYTICS_REL_TYPE_RELATE_TO")] + const RELATE_TO = ffi::GST_ANALYTICS_REL_TYPE_RELATE_TO as _; + #[doc(alias = "GST_ANALYTICS_REL_TYPE_LAST")] + const LAST = ffi::GST_ANALYTICS_REL_TYPE_LAST as _; + #[doc(alias = "GST_ANALYTICS_REL_TYPE_ANY")] + const ANY = ffi::GST_ANALYTICS_REL_TYPE_ANY as _; + } +} + +#[doc(hidden)] +impl IntoGlib for RelTypes { + type GlibType = ffi::GstAnalyticsRelTypes; + + #[inline] + fn into_glib(self) -> ffi::GstAnalyticsRelTypes { + self.bits() + } +} + +#[doc(hidden)] +impl FromGlib for RelTypes { + #[inline] + unsafe fn from_glib(value: ffi::GstAnalyticsRelTypes) -> Self { + skip_assert_initialized!(); + Self::from_bits_truncate(value) + } +} diff --git a/gstreamer-analytics/src/auto/mod.rs b/gstreamer-analytics/src/auto/mod.rs new file mode 100644 index 000000000..ab5bac596 --- /dev/null +++ b/gstreamer-analytics/src/auto/mod.rs @@ -0,0 +1,7 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git) +// DO NOT EDIT + +mod flags; +pub use self::flags::RelTypes; diff --git a/gstreamer-analytics/src/auto/versions.txt b/gstreamer-analytics/src/auto/versions.txt new file mode 100644 index 000000000..62039a28e --- /dev/null +++ b/gstreamer-analytics/src/auto/versions.txt @@ -0,0 +1,3 @@ +Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) +from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-analytics/src/classification.rs b/gstreamer-analytics/src/classification.rs new file mode 100644 index 000000000..d7166ad6a --- /dev/null +++ b/gstreamer-analytics/src/classification.rs @@ -0,0 +1,212 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use glib::translate::*; + +use crate::relation_meta::*; + +#[derive(Debug)] +pub enum AnalyticsClassificationMtd {} + +mod sealed { + pub trait Sealed {} + impl Sealed for T {} +} + +pub trait AnalyticsRelationMetaClassificationExt: sealed::Sealed { + fn add_one_cls_mtd( + &mut self, + confidence_level: f32, + class_quark: glib::Quark, + ) -> Result, glib::BoolError>; + + fn add_cls_mtd( + &mut self, + confidence_levels: &[f32], + class_quarks: &[glib::Quark], + ) -> Result, glib::BoolError>; +} + +impl<'a> AnalyticsRelationMetaClassificationExt + for gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone> +{ + #[doc(alias = "gst_analytics_relation_meta_add_one_cls_mtd")] + fn add_one_cls_mtd( + &mut self, + confidence_level: f32, + class_quark: glib::Quark, + ) -> Result, glib::BoolError> { + unsafe { + let mut mtd = std::mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::gst_analytics_relation_meta_add_one_cls_mtd( + self.as_mut_ptr(), + confidence_level, + class_quark.into_glib(), + mtd.as_mut_ptr(), + )); + let id = mtd.assume_init().id; + + if ret { + Ok(AnalyticsMtdRef::from_meta(self.as_ref(), id)) + } else { + Err(glib::bool_error!("Couldn't add more data")) + } + } + } + + #[doc(alias = "gst_analytics_relation_meta_add_cls_mtd")] + fn add_cls_mtd( + &mut self, + confidence_levels: &[f32], + class_quarks: &[glib::Quark], + ) -> Result, glib::BoolError> { + let length = std::cmp::min(confidence_levels.len(), class_quarks.len()); + unsafe { + let mut mtd = std::mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::gst_analytics_relation_meta_add_cls_mtd( + self.as_mut_ptr(), + length, + mut_override(confidence_levels.as_ptr()), + class_quarks.as_ptr() as *mut _, + mtd.as_mut_ptr(), + )); + let id = mtd.assume_init().id; + + if ret { + Ok(AnalyticsMtdRef::from_meta(self.as_ref(), id)) + } else { + Err(glib::bool_error!("Couldn't add more data")) + } + } + } +} + +unsafe impl AnalyticsMtd for AnalyticsClassificationMtd { + #[doc(alias = "gst_analytics_cls_mtd_get_mtd_type")] + fn mtd_type() -> ffi::GstAnalyticsMtdType { + unsafe { ffi::gst_analytics_cls_mtd_get_mtd_type() } + } +} + +unsafe fn from(t: ffi::GstAnalyticsMtd) -> ffi::GstAnalyticsClsMtd { + std::mem::transmute(t) +} + +impl<'a> AnalyticsMtdRef<'a, AnalyticsClassificationMtd> { + #[doc(alias = "gst_analytics_cls_mtd_get_length")] + pub fn len(&self) -> usize { + unsafe { + let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self)); + ffi::gst_analytics_cls_mtd_get_length(&mut mtd) + } + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[doc(alias = "gst_analytics_cls_mtd_get_level")] + pub fn level(&self, index: usize) -> f32 { + assert!(index < self.len()); + + unsafe { + let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self)); + ffi::gst_analytics_cls_mtd_get_level(&mut mtd, index) + } + } + + #[doc(alias = "gst_analytics_cls_mtd_get_quark")] + pub fn quark(&self, index: usize) -> glib::Quark { + assert!(index < self.len()); + + unsafe { + let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self)); + from_glib(ffi::gst_analytics_cls_mtd_get_quark(&mut mtd, index)) + } + } + + pub fn iterate(&self) -> AnalyticsClassificationIterator { + AnalyticsClassificationIterator { + mtd: self, + index: 0, + length: self.len(), + } + } +} + +pub struct AnalyticsClassificationIterator<'a> { + mtd: &'a AnalyticsMtdRef<'a, AnalyticsClassificationMtd>, + index: usize, + length: usize, +} + +impl<'a> Iterator for AnalyticsClassificationIterator<'a> { + type Item = (glib::Quark, f32); + + fn next(&mut self) -> Option { + if self.index == self.length { + None + } else { + let ret = Some((self.mtd.quark(self.index), self.mtd.level(self.index))); + self.index += 1; + ret + } + } +} + +#[cfg(test)] +mod tests { + use crate::*; + + #[test] + fn one_class() { + gst::init().unwrap(); + + assert_eq!(AnalyticsClassificationMtd::type_name(), "classification"); + + let mut buf = gst::Buffer::new(); + let mut meta = AnalyticsRelationMeta::add(buf.make_mut()); + + assert!(meta.is_empty()); + + let cls = meta + .add_one_cls_mtd(0.7, glib::Quark::from_str("class1")) + .unwrap(); + + assert_eq!(cls.len(), 1); + assert_eq!(cls.level(0), 0.7); + assert_eq!(cls.quark(0), glib::Quark::from_str("class1")); + } + + #[test] + fn many_classes() { + gst::init().unwrap(); + + assert_eq!(AnalyticsClassificationMtd::type_name(), "classification"); + + let mut buf = gst::Buffer::new(); + let mut meta = AnalyticsRelationMeta::add(buf.make_mut()); + + assert!(meta.is_empty()); + + let classes = [ + glib::Quark::from_str("a"), + glib::Quark::from_str("b"), + glib::Quark::from_str("c"), + glib::Quark::from_str("d"), + ]; + let levels = [0.1, 0.2, 0.3, 0.4]; + + let cls = meta.add_cls_mtd(&levels, &classes).unwrap(); + + assert_eq!(cls.len(), 4); + for i in 0..4usize { + assert_eq!(cls.level(i), levels[i]); + assert_eq!(cls.quark(i), classes[i]); + } + + for (i, (q, l)) in cls.iterate().enumerate() { + assert_eq!(l, levels[i]); + assert_eq!(q, classes[i]); + } + } +} diff --git a/gstreamer-analytics/src/lib.rs b/gstreamer-analytics/src/lib.rs new file mode 100644 index 000000000..f22f66ce1 --- /dev/null +++ b/gstreamer-analytics/src/lib.rs @@ -0,0 +1,36 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +#![cfg_attr(docsrs, feature(doc_cfg))] +#![allow(clippy::missing_safety_doc)] +#![doc = include_str!("../README.md")] + +pub use ffi; +pub use glib; +pub use gst; + +macro_rules! skip_assert_initialized { + () => {}; +} + +mod auto; +pub use crate::auto::*; + +mod relation_meta; +pub use crate::relation_meta::*; + +mod object_detection; +pub use crate::object_detection::*; + +mod tracking; +pub use crate::tracking::*; + +mod classification; +pub use crate::classification::*; + +// Re-export all the traits in a prelude module, so that applications +// can always "use gst_app::prelude::*" without getting conflicts +pub mod prelude { + pub use crate::classification::AnalyticsRelationMetaClassificationExt; + pub use crate::object_detection::AnalyticsRelationMetaODExt; + pub use crate::tracking::AnalyticsRelationMetaTrackingExt; +} diff --git a/gstreamer-analytics/src/object_detection.rs b/gstreamer-analytics/src/object_detection.rs new file mode 100644 index 000000000..050efabd8 --- /dev/null +++ b/gstreamer-analytics/src/object_detection.rs @@ -0,0 +1,171 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use glib::translate::*; + +use crate::relation_meta::*; + +#[derive(Debug)] +pub enum AnalyticsODMtd {} + +mod sealed { + pub trait Sealed {} + impl Sealed for T {} +} + +pub trait AnalyticsRelationMetaODExt: sealed::Sealed { + fn add_od_mtd( + &mut self, + type_: glib::Quark, + x: i32, + y: i32, + w: i32, + h: i32, + loc_conf_lvl: f32, + ) -> Result, glib::BoolError>; +} + +impl<'a> AnalyticsRelationMetaODExt + for gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone> +{ + #[doc(alias = "gst_analytics_relation_meta_add_od_mtd")] + fn add_od_mtd( + &mut self, + type_: glib::Quark, + x: i32, + y: i32, + w: i32, + h: i32, + loc_conf_lvl: f32, + ) -> Result, glib::BoolError> { + unsafe { + let mut mtd = std::mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::gst_analytics_relation_meta_add_od_mtd( + self.as_mut_ptr(), + type_.into_glib(), + x, + y, + w, + h, + loc_conf_lvl, + mtd.as_mut_ptr(), + )); + let id = mtd.assume_init().id; + + if ret { + Ok(AnalyticsMtdRef::from_meta(self.as_ref(), id)) + } else { + Err(glib::bool_error!("Couldn't add more data")) + } + } + } +} + +#[derive(Default, Debug)] +pub struct AnalyticsODLocation { + x: i32, + y: i32, + w: i32, + h: i32, + loc_conf_lvl: f32, +} + +unsafe impl AnalyticsMtd for AnalyticsODMtd { + #[doc(alias = "gst_analytics_od_mtd_get_mtd_type")] + fn mtd_type() -> ffi::GstAnalyticsMtdType { + unsafe { ffi::gst_analytics_od_mtd_get_mtd_type() } + } +} + +unsafe fn from(t: ffi::GstAnalyticsMtd) -> ffi::GstAnalyticsODMtd { + std::mem::transmute(t) +} + +impl<'a> AnalyticsMtdRef<'a, AnalyticsODMtd> { + #[doc(alias = "gst_analytics_od_mtd_get_obj_type")] + pub fn obj_type(&self) -> glib::Quark { + unsafe { + let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self)); + let type_ = ffi::gst_analytics_od_mtd_get_obj_type(&mut mtd); + glib::Quark::from_glib(type_) + } + } + + #[doc(alias = "gst_analytics_od_mtd_get_location")] + pub fn location(&self) -> Result { + let mut loc = AnalyticsODLocation::default(); + + let success = unsafe { + let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self)); + ffi::gst_analytics_od_mtd_get_location( + &mut mtd, + &mut loc.x, + &mut loc.y, + &mut loc.w, + &mut loc.h, + &mut loc.loc_conf_lvl, + ) + }; + + if success != 0 { + Ok(loc) + } else { + Err(glib::bool_error!("Could retrieve location")) + } + } + + #[doc(alias = "gst_analytics_od_mtd_get_confidence_lvl")] + pub fn confidence_level(&self) -> f32 { + unsafe { + let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self)); + let mut lvl: f32 = 0.0; + ffi::gst_analytics_od_mtd_get_confidence_lvl(&mut mtd, &mut lvl); + lvl + } + } +} + +#[cfg(test)] +mod tests { + use crate::*; + + #[test] + fn object_detection() { + gst::init().unwrap(); + + assert_eq!(AnalyticsODMtd::type_name(), "object-detection"); + + let mut buf = gst::Buffer::new(); + let mut meta = AnalyticsRelationMeta::add(buf.make_mut()); + + assert!(meta.is_empty()); + + let od = meta + .add_od_mtd(glib::Quark::from_str("blb"), 0, 1, 10, 20, 0.8) + .unwrap(); + + assert_eq!(od.obj_type(), glib::Quark::from_str("blb")); + + let loc = od.location().unwrap(); + + assert_eq!(loc.x, 0); + assert_eq!(loc.y, 1); + assert_eq!(loc.w, 10); + assert_eq!(loc.h, 20); + assert_eq!(loc.loc_conf_lvl, 0.8); + let meta = buf.meta::().unwrap(); + + assert!(meta.mtd::(1).is_none()); + + let meta2 = buf.meta::().unwrap(); + let od2 = meta2.mtd::(0).unwrap(); + + assert_eq!(od2.obj_type(), glib::Quark::from_str("blb")); + let loc = od2.location().unwrap(); + + assert_eq!(loc.x, 0); + assert_eq!(loc.y, 1); + assert_eq!(loc.w, 10); + assert_eq!(loc.h, 20); + assert_eq!(loc.loc_conf_lvl, 0.8); + } +} diff --git a/gstreamer-analytics/src/relation_meta.rs b/gstreamer-analytics/src/relation_meta.rs new file mode 100644 index 000000000..03e70349e --- /dev/null +++ b/gstreamer-analytics/src/relation_meta.rs @@ -0,0 +1,706 @@ +// 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 { + 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 { + let mut array = std::ptr::null_mut::(); + 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 Sealed for T {} +} + +pub trait AnalyticsMetaRefExt<'a>: sealed::Sealed { + #[doc(alias = "gst_analytics_relation_meta_get_mtd")] + fn mtd(&self, an_meta_id: u32) -> Option>; + fn iter(&'a self) -> AnalyticsMtdIter; + fn iter_direct_related( + &'a self, + an_meta_id: u32, + rel_type: RelTypes, + ) -> AnalyticsMtdIter; +} + +impl<'a> AnalyticsMetaRefExt<'a> for gst::MetaRef<'a, AnalyticsRelationMeta> { + fn mtd(&self, an_meta_id: u32) -> Option> { + 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(&'a self) -> AnalyticsMtdIter<'a, T> { + AnalyticsMtdIter::new(self) + } + fn iter_direct_related( + &'a self, + an_meta_id: u32, + rel_type: RelTypes, + ) -> AnalyticsMtdIter { + 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( + self, + ) -> Result, 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(&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(&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(&'a mut self, an_meta_id: u32) + -> Option>; + + fn iter_mut(&'a mut self) -> AnalyticsMtdIterMut; + fn iter_direct_related_mut( + &'a mut self, + an_meta_id: u32, + rel_type: RelTypes, + ) -> AnalyticsMtdIterMut; +} + +impl<'a> AnalyticsMetaRefMutExt<'a> + for gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone> +{ + fn mtd_mut( + &'a mut self, + an_meta_id: u32, + ) -> Option> { + 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(&'a mut self) -> AnalyticsMtdIterMut { + AnalyticsMtdIterMut::new(self) + } + fn iter_direct_related_mut( + &'a mut self, + an_meta_id: u32, + rel_type: RelTypes, + ) -> AnalyticsMtdIterMut { + 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 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> 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> 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, + } + + 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 { + 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(), ¶ms); + + 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::().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::().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::().count()); + assert_eq!(meta.len(), meta.iter::().count()); + for mtd in meta.iter::() { + assert_eq!(mtd.obj_type(), glib::Quark::from_str("blb")) + } + + assert_eq!(meta.len(), meta.iter::().count()); + for mtd in meta.iter::() { + if let Ok(mtd) = mtd.downcast::() { + assert_eq!(mtd.obj_type(), glib::Quark::from_str("blb")) + } + } + + assert_eq!( + meta.iter_direct_related::(od1_id, crate::RelTypes::IS_PART_OF) + .count(), + 1 + ); + assert_eq!( + meta.iter_direct_related::(od2_id, crate::RelTypes::IS_PART_OF) + .count(), + 1 + ); + assert_eq!( + meta.iter_direct_related::(od3_id, crate::RelTypes::IS_PART_OF) + .count(), + 0 + ); + assert_eq!( + meta.iter_direct_related::(od1_id, crate::RelTypes::CONTAIN) + .count(), + 0 + ); + + assert_eq!( + meta.iter_direct_related::(od1_id, crate::RelTypes::CONTAIN) + .count(), + 0 + ); + for mtd in meta.iter_direct_related::(od1_id, crate::RelTypes::IS_PART_OF) { + assert_eq!(mtd.obj_type(), glib::Quark::from_str("blb")) + } + + let mut meta = buf.make_mut().meta_mut::().unwrap(); + assert_eq!(meta.len(), meta.iter_mut::().count()); + + let mut meta = buf.make_mut().meta_mut::().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::() { + item.set_lost().unwrap(); + } + } +} diff --git a/gstreamer-analytics/src/tracking.rs b/gstreamer-analytics/src/tracking.rs new file mode 100644 index 000000000..c8820726c --- /dev/null +++ b/gstreamer-analytics/src/tracking.rs @@ -0,0 +1,158 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use glib::translate::*; + +use crate::relation_meta::*; + +#[derive(Debug)] +pub enum AnalyticsTrackingMtd {} + +mod sealed { + pub trait Sealed {} + impl Sealed for T {} +} + +pub trait AnalyticsRelationMetaTrackingExt: sealed::Sealed { + fn add_tracking_mtd( + &mut self, + tracking_id: u64, + tracking_first_seen: gst::ClockTime, + ) -> Result, glib::BoolError>; +} + +impl<'a> AnalyticsRelationMetaTrackingExt + for gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone> +{ + #[doc(alias = "gst_analytics_relation_meta_add_tracking_mtd")] + fn add_tracking_mtd( + &mut self, + tracking_id: u64, + tracking_first_seen: gst::ClockTime, + ) -> Result, glib::BoolError> { + unsafe { + let mut mtd = std::mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::gst_analytics_relation_meta_add_tracking_mtd( + self.as_mut_ptr(), + tracking_id, + tracking_first_seen.into_glib(), + mtd.as_mut_ptr(), + )); + let id = mtd.assume_init().id; + + if ret { + Ok(AnalyticsMtdRef::from_meta(self.as_ref(), id)) + } else { + Err(glib::bool_error!("Couldn't add more data")) + } + } + } +} + +unsafe impl AnalyticsMtd for AnalyticsTrackingMtd { + #[doc(alias = "gst_analytics_tracking_mtd_get_mtd_type")] + fn mtd_type() -> ffi::GstAnalyticsMtdType { + unsafe { ffi::gst_analytics_tracking_mtd_get_mtd_type() } + } +} + +unsafe fn from(t: ffi::GstAnalyticsMtd) -> ffi::GstAnalyticsTrackingMtd { + std::mem::transmute(t) +} + +impl<'a> AnalyticsMtdRef<'a, AnalyticsTrackingMtd> { + #[doc(alias = "gst_analytics_tracking_mtd_get_info")] + pub fn info(&self) -> (u64, gst::ClockTime, gst::ClockTime, bool) { + let mut tracking_id: u64 = 0; + let mut tracking_first_seen: u64 = 0; + let mut tracking_last_seen: u64 = 0; + let mut tracking_lost: i32 = 0; + + unsafe { + let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self)); + ffi::gst_analytics_tracking_mtd_get_info( + &mut mtd, + &mut tracking_id, + &mut tracking_first_seen, + &mut tracking_last_seen, + &mut tracking_lost, + ); + }; + + ( + tracking_id, + gst::ClockTime::from_nseconds(tracking_first_seen), + gst::ClockTime::from_nseconds(tracking_last_seen), + tracking_lost != 0, + ) + } +} + +impl<'a> AnalyticsMtdRefMut<'a, AnalyticsTrackingMtd> { + #[doc(alias = "gst_analytics_tracking_mtd_update_last_seen")] + pub fn update_last_seen(&mut self, last_seen: gst::ClockTime) -> Result<(), glib::BoolError> { + let ret: bool = unsafe { + let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self)); + from_glib(ffi::gst_analytics_tracking_mtd_update_last_seen( + &mut mtd, + last_seen.into_glib(), + )) + }; + assert!(ret); + Ok(()) + } + + #[doc(alias = "gst_analytics_tracking_mtd_set_lost")] + pub fn set_lost(&mut self) -> Result<(), glib::BoolError> { + let ret: bool = unsafe { + let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self)); + from_glib(ffi::gst_analytics_tracking_mtd_set_lost(&mut mtd)) + }; + assert!(ret); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::*; + + #[test] + fn tracking() { + gst::init().unwrap(); + + assert_eq!(AnalyticsTrackingMtd::type_name(), "object-tracking"); + + let mut buf = gst::Buffer::new(); + let mut meta = AnalyticsRelationMeta::add(buf.make_mut()); + + assert!(meta.is_empty()); + + let track = meta + .add_tracking_mtd(10, gst::ClockTime::from_seconds(10)) + .unwrap(); + + let (tracking_id, tracking_first_seen, tracking_last_seen, tracking_lost) = track.info(); + + assert_eq!(tracking_id, 10); + assert_eq!(tracking_first_seen, gst::ClockTime::from_seconds(10)); + assert_eq!(tracking_last_seen, gst::ClockTime::from_seconds(10)); + assert!(!tracking_lost); + + let track_id = track.id(); + + let mut tracking_mut = meta.mtd_mut::(track_id).unwrap(); + + tracking_mut + .update_last_seen(gst::ClockTime::from_seconds(20)) + .unwrap(); + tracking_mut.set_lost().unwrap(); + + let tracking: AnalyticsMtdRef<_> = tracking_mut.into(); + let (tracking_id, tracking_first_seen, tracking_last_seen, tracking_lost) = tracking.info(); + + assert_eq!(tracking_id, 10); + assert_eq!(tracking_first_seen, gst::ClockTime::from_seconds(10)); + assert_eq!(tracking_last_seen, gst::ClockTime::from_seconds(20)); + assert!(tracking_lost); + } +} diff --git a/gstreamer-analytics/sys/CHANGELOG.md b/gstreamer-analytics/sys/CHANGELOG.md new file mode 120000 index 000000000..d6a7bdb06 --- /dev/null +++ b/gstreamer-analytics/sys/CHANGELOG.md @@ -0,0 +1 @@ +../../gstreamer/CHANGELOG.md \ No newline at end of file diff --git a/gstreamer-analytics/sys/COPYRIGHT b/gstreamer-analytics/sys/COPYRIGHT new file mode 120000 index 000000000..8b0161cc9 --- /dev/null +++ b/gstreamer-analytics/sys/COPYRIGHT @@ -0,0 +1 @@ +../../COPYRIGHT \ No newline at end of file diff --git a/gstreamer-analytics/sys/Cargo.toml b/gstreamer-analytics/sys/Cargo.toml new file mode 100644 index 000000000..3ee48db99 --- /dev/null +++ b/gstreamer-analytics/sys/Cargo.toml @@ -0,0 +1,57 @@ +[build-dependencies] +system-deps = "6" + +[dependencies] +libc = "0.2" + +[dependencies.glib-sys] +workspace = true + +[dependencies.gstreamer-sys] +workspace = true + +[dev-dependencies] +shell-words = "1.0.0" +tempfile = "3" + +[lib] +name = "gstreamer_analytics_sys" + +[package] +authors = ["Olivier CrĂȘte ::std::fmt::Result { + f.debug_struct(&format!("GstAnalyticsClsMtd @ {self:p}")) + .field("id", &self.id) + .field("meta", &self.meta) + .finish() + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct GstAnalyticsMtd { + pub id: c_uint, + pub meta: *mut GstAnalyticsRelationMeta, +} + +impl ::std::fmt::Debug for GstAnalyticsMtd { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("GstAnalyticsMtd @ {self:p}")) + .field("id", &self.id) + .field("meta", &self.meta) + .finish() + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct GstAnalyticsMtdImpl { + pub name: *const c_char, + pub mtd_meta_transform: Option< + unsafe extern "C" fn( + *mut gst::GstBuffer, + *mut GstAnalyticsMtd, + *mut gst::GstBuffer, + glib::GQuark, + gpointer, + ) -> gboolean, + >, + pub _reserved: [gpointer; 20], +} + +impl ::std::fmt::Debug for GstAnalyticsMtdImpl { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("GstAnalyticsMtdImpl @ {self:p}")) + .field("name", &self.name) + .field("mtd_meta_transform", &self.mtd_meta_transform) + .field("_reserved", &self._reserved) + .finish() + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct GstAnalyticsODMtd { + pub id: c_uint, + pub meta: *mut GstAnalyticsRelationMeta, +} + +impl ::std::fmt::Debug for GstAnalyticsODMtd { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("GstAnalyticsODMtd @ {self:p}")) + .field("id", &self.id) + .field("meta", &self.meta) + .finish() + } +} + +#[repr(C)] +pub struct _GstAnalyticsRelationMeta { + _data: [u8; 0], + _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>, +} + +pub type GstAnalyticsRelationMeta = _GstAnalyticsRelationMeta; + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct GstAnalyticsRelationMetaInitParams { + pub initial_relation_order: size_t, + pub initial_buf_size: size_t, +} + +impl ::std::fmt::Debug for GstAnalyticsRelationMetaInitParams { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("GstAnalyticsRelationMetaInitParams @ {self:p}")) + .field("initial_relation_order", &self.initial_relation_order) + .field("initial_buf_size", &self.initial_buf_size) + .finish() + } +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct GstAnalyticsTrackingMtd { + pub id: c_uint, + pub meta: *mut GstAnalyticsRelationMeta, +} + +impl ::std::fmt::Debug for GstAnalyticsTrackingMtd { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct(&format!("GstAnalyticsTrackingMtd @ {self:p}")) + .field("id", &self.id) + .field("meta", &self.meta) + .finish() + } +} + +#[link(name = "gstanalytics-1.0")] +extern "C" { + + //========================================================================= + // GstAnalyticsClsMtd + //========================================================================= + pub fn gst_analytics_cls_mtd_get_index_by_quark( + handle: *mut GstAnalyticsClsMtd, + quark: glib::GQuark, + ) -> c_int; + pub fn gst_analytics_cls_mtd_get_length(handle: *mut GstAnalyticsClsMtd) -> size_t; + pub fn gst_analytics_cls_mtd_get_level( + handle: *mut GstAnalyticsClsMtd, + index: size_t, + ) -> c_float; + pub fn gst_analytics_cls_mtd_get_quark( + handle: *mut GstAnalyticsClsMtd, + index: size_t, + ) -> glib::GQuark; + pub fn gst_analytics_cls_mtd_get_mtd_type() -> GstAnalyticsMtdType; + + //========================================================================= + // GstAnalyticsMtd + //========================================================================= + pub fn gst_analytics_mtd_get_id(instance: *mut GstAnalyticsMtd) -> c_uint; + pub fn gst_analytics_mtd_get_mtd_type(instance: *mut GstAnalyticsMtd) -> GstAnalyticsMtdType; + pub fn gst_analytics_mtd_get_size(instance: *mut GstAnalyticsMtd) -> size_t; + pub fn gst_analytics_mtd_type_get_name(type_: GstAnalyticsMtdType) -> *const c_char; + + //========================================================================= + // GstAnalyticsODMtd + //========================================================================= + pub fn gst_analytics_od_mtd_get_confidence_lvl( + instance: *mut GstAnalyticsODMtd, + loc_conf_lvl: *mut c_float, + ) -> gboolean; + pub fn gst_analytics_od_mtd_get_location( + instance: *mut GstAnalyticsODMtd, + x: *mut c_int, + y: *mut c_int, + w: *mut c_int, + h: *mut c_int, + loc_conf_lvl: *mut c_float, + ) -> gboolean; + pub fn gst_analytics_od_mtd_get_obj_type(handle: *mut GstAnalyticsODMtd) -> glib::GQuark; + pub fn gst_analytics_od_mtd_get_mtd_type() -> GstAnalyticsMtdType; + + //========================================================================= + // GstAnalyticsRelationMeta + //========================================================================= + pub fn gst_analytics_relation_meta_add_cls_mtd( + instance: *mut GstAnalyticsRelationMeta, + length: size_t, + confidence_levels: *mut c_float, + class_quarks: *mut glib::GQuark, + cls_mtd: *mut GstAnalyticsClsMtd, + ) -> gboolean; + pub fn gst_analytics_relation_meta_add_mtd( + meta: *mut GstAnalyticsRelationMeta, + impl_: *const GstAnalyticsMtdImpl, + size: size_t, + rlt_mtd: *mut GstAnalyticsMtd, + ) -> gpointer; + pub fn gst_analytics_relation_meta_add_od_mtd( + instance: *mut GstAnalyticsRelationMeta, + type_: glib::GQuark, + x: c_int, + y: c_int, + w: c_int, + h: c_int, + loc_conf_lvl: c_float, + od_mtd: *mut GstAnalyticsODMtd, + ) -> gboolean; + pub fn gst_analytics_relation_meta_add_one_cls_mtd( + instance: *mut GstAnalyticsRelationMeta, + confidence_level: c_float, + class_quark: glib::GQuark, + cls_mtd: *mut GstAnalyticsClsMtd, + ) -> gboolean; + pub fn gst_analytics_relation_meta_add_tracking_mtd( + instance: *mut GstAnalyticsRelationMeta, + tracking_id: u64, + tracking_first_seen: gst::GstClockTime, + trk_mtd: *mut GstAnalyticsTrackingMtd, + ) -> gboolean; + pub fn gst_analytics_relation_meta_exist( + rmeta: *mut GstAnalyticsRelationMeta, + an_meta_first_id: c_uint, + an_meta_second_id: c_uint, + max_relation_span: c_int, + cond_types: GstAnalyticsRelTypes, + relations_path: *mut *mut glib::GArray, + ) -> gboolean; + pub fn gst_analytics_relation_meta_get_cls_mtd( + meta: *mut GstAnalyticsRelationMeta, + an_meta_id: c_uint, + rlt: *mut GstAnalyticsClsMtd, + ) -> gboolean; + pub fn gst_analytics_relation_meta_get_direct_related( + meta: *mut GstAnalyticsRelationMeta, + an_meta_id: c_uint, + relation_type: GstAnalyticsRelTypes, + type_: GstAnalyticsMtdType, + state: *mut gpointer, + rlt_mtd: *mut GstAnalyticsMtd, + ) -> gboolean; + pub fn gst_analytics_relation_meta_get_mtd( + meta: *mut GstAnalyticsRelationMeta, + an_meta_id: c_uint, + type_: GstAnalyticsMtdType, + rlt: *mut GstAnalyticsMtd, + ) -> gboolean; + pub fn gst_analytics_relation_meta_get_mtd_data( + meta: *mut GstAnalyticsRelationMeta, + an_meta_id: c_uint, + ) -> gpointer; + pub fn gst_analytics_relation_meta_get_od_mtd( + meta: *mut GstAnalyticsRelationMeta, + an_meta_id: c_uint, + rlt: *mut GstAnalyticsODMtd, + ) -> gboolean; + pub fn gst_analytics_relation_meta_get_relation( + meta: *mut GstAnalyticsRelationMeta, + an_meta_first_id: c_uint, + an_meta_second_id: c_uint, + ) -> GstAnalyticsRelTypes; + pub fn gst_analytics_relation_meta_get_tracking_mtd( + meta: *mut GstAnalyticsRelationMeta, + an_meta_id: c_uint, + rlt: *mut GstAnalyticsTrackingMtd, + ) -> gboolean; + pub fn gst_analytics_relation_meta_iterate( + meta: *mut GstAnalyticsRelationMeta, + state: *mut gpointer, + type_: GstAnalyticsMtdType, + rlt_mtd: *mut GstAnalyticsMtd, + ) -> gboolean; + pub fn gst_analytics_relation_meta_set_relation( + meta: *mut GstAnalyticsRelationMeta, + type_: GstAnalyticsRelTypes, + an_meta_first_id: c_uint, + an_meta_second_id: c_uint, + ) -> gboolean; + pub fn gst_analytics_relation_meta_get_info() -> *const gst::GstMetaInfo; + + //========================================================================= + // GstAnalyticsTrackingMtd + //========================================================================= + pub fn gst_analytics_tracking_mtd_get_info( + instance: *mut GstAnalyticsTrackingMtd, + tracking_id: *mut u64, + tracking_first_seen: *mut gst::GstClockTime, + tracking_last_seen: *mut gst::GstClockTime, + tracking_lost: *mut gboolean, + ) -> gboolean; + pub fn gst_analytics_tracking_mtd_set_lost(instance: *mut GstAnalyticsTrackingMtd) -> gboolean; + pub fn gst_analytics_tracking_mtd_update_last_seen( + instance: *mut GstAnalyticsTrackingMtd, + last_seen: gst::GstClockTime, + ) -> gboolean; + pub fn gst_analytics_tracking_mtd_get_mtd_type() -> GstAnalyticsMtdType; + + //========================================================================= + // Other functions + //========================================================================= + pub fn gst_buffer_add_analytics_relation_meta( + buffer: *mut gst::GstBuffer, + ) -> *mut GstAnalyticsRelationMeta; + pub fn gst_buffer_add_analytics_relation_meta_full( + buffer: *mut gst::GstBuffer, + init_params: *mut GstAnalyticsRelationMetaInitParams, + ) -> *mut GstAnalyticsRelationMeta; + pub fn gst_buffer_get_analytics_relation_meta( + buffer: *mut gst::GstBuffer, + ) -> *mut GstAnalyticsRelationMeta; + pub fn gst_analytics_relation_get_length(instance: *mut GstAnalyticsRelationMeta) -> size_t; + pub fn gst_analytics_relation_meta_api_get_type() -> GType; + +} diff --git a/gstreamer-analytics/sys/tests/abi.rs b/gstreamer-analytics/sys/tests/abi.rs new file mode 100644 index 000000000..b8ff0248e --- /dev/null +++ b/gstreamer-analytics/sys/tests/abi.rs @@ -0,0 +1,273 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git) +// DO NOT EDIT + +#![cfg(unix)] + +use gstreamer_analytics_sys::*; +use std::env; +use std::error::Error; +use std::ffi::OsString; +use std::mem::{align_of, size_of}; +use std::path::Path; +use std::process::{Command, Stdio}; +use std::str; +use tempfile::Builder; + +static PACKAGES: &[&str] = &["gstreamer-analytics-1.0"]; + +#[derive(Clone, Debug)] +struct Compiler { + pub args: Vec, +} + +impl Compiler { + pub fn new() -> Result> { + let mut args = get_var("CC", "cc")?; + args.push("-Wno-deprecated-declarations".to_owned()); + // For _Generic + args.push("-std=c11".to_owned()); + // For %z support in printf when using MinGW. + args.push("-D__USE_MINGW_ANSI_STDIO".to_owned()); + args.extend(get_var("CFLAGS", "")?); + args.extend(get_var("CPPFLAGS", "")?); + args.extend(pkg_config_cflags(PACKAGES)?); + Ok(Self { args }) + } + + pub fn compile(&self, src: &Path, out: &Path) -> Result<(), Box> { + let mut cmd = self.to_command(); + cmd.arg(src); + cmd.arg("-o"); + cmd.arg(out); + let status = cmd.spawn()?.wait()?; + if !status.success() { + return Err(format!("compilation command {cmd:?} failed, {status}").into()); + } + Ok(()) + } + + fn to_command(&self) -> Command { + let mut cmd = Command::new(&self.args[0]); + cmd.args(&self.args[1..]); + cmd + } +} + +fn get_var(name: &str, default: &str) -> Result, Box> { + match env::var(name) { + Ok(value) => Ok(shell_words::split(&value)?), + Err(env::VarError::NotPresent) => Ok(shell_words::split(default)?), + Err(err) => Err(format!("{name} {err}").into()), + } +} + +fn pkg_config_cflags(packages: &[&str]) -> Result, Box> { + if packages.is_empty() { + return Ok(Vec::new()); + } + let pkg_config = env::var_os("PKG_CONFIG").unwrap_or_else(|| OsString::from("pkg-config")); + let mut cmd = Command::new(pkg_config); + cmd.arg("--cflags"); + cmd.args(packages); + cmd.stderr(Stdio::inherit()); + let out = cmd.output()?; + if !out.status.success() { + let (status, stdout) = (out.status, String::from_utf8_lossy(&out.stdout)); + return Err(format!("command {cmd:?} failed, {status:?}\nstdout: {stdout}").into()); + } + let stdout = str::from_utf8(&out.stdout)?; + Ok(shell_words::split(stdout.trim())?) +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +struct Layout { + size: usize, + alignment: usize, +} + +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] +struct Results { + /// Number of successfully completed tests. + passed: usize, + /// Total number of failed tests (including those that failed to compile). + failed: usize, +} + +impl Results { + fn record_passed(&mut self) { + self.passed += 1; + } + fn record_failed(&mut self) { + self.failed += 1; + } + fn summary(&self) -> String { + format!("{} passed; {} failed", self.passed, self.failed) + } + fn expect_total_success(&self) { + if self.failed == 0 { + println!("OK: {}", self.summary()); + } else { + panic!("FAILED: {}", self.summary()); + }; + } +} + +#[test] +fn cross_validate_constants_with_c() { + let mut c_constants: Vec<(String, String)> = Vec::new(); + + for l in get_c_output("constant").unwrap().lines() { + let (name, value) = l.split_once(';').expect("Missing ';' separator"); + c_constants.push((name.to_owned(), value.to_owned())); + } + + let mut results = Results::default(); + + for ((rust_name, rust_value), (c_name, c_value)) in + RUST_CONSTANTS.iter().zip(c_constants.iter()) + { + if rust_name != c_name { + results.record_failed(); + eprintln!("Name mismatch:\nRust: {rust_name:?}\nC: {c_name:?}"); + continue; + } + + if rust_value != c_value { + results.record_failed(); + eprintln!( + "Constant value mismatch for {rust_name}\nRust: {rust_value:?}\nC: {c_value:?}", + ); + continue; + } + + results.record_passed(); + } + + results.expect_total_success(); +} + +#[test] +fn cross_validate_layout_with_c() { + let mut c_layouts = Vec::new(); + + for l in get_c_output("layout").unwrap().lines() { + let (name, value) = l.split_once(';').expect("Missing first ';' separator"); + let (size, alignment) = value.split_once(';').expect("Missing second ';' separator"); + let size = size.parse().expect("Failed to parse size"); + let alignment = alignment.parse().expect("Failed to parse alignment"); + c_layouts.push((name.to_owned(), Layout { size, alignment })); + } + + let mut results = Results::default(); + + for ((rust_name, rust_layout), (c_name, c_layout)) in RUST_LAYOUTS.iter().zip(c_layouts.iter()) + { + if rust_name != c_name { + results.record_failed(); + eprintln!("Name mismatch:\nRust: {rust_name:?}\nC: {c_name:?}"); + continue; + } + + if rust_layout != c_layout { + results.record_failed(); + eprintln!("Layout mismatch for {rust_name}\nRust: {rust_layout:?}\nC: {c_layout:?}",); + continue; + } + + results.record_passed(); + } + + results.expect_total_success(); +} + +fn get_c_output(name: &str) -> Result> { + let tmpdir = Builder::new().prefix("abi").tempdir()?; + let exe = tmpdir.path().join(name); + let c_file = Path::new("tests").join(name).with_extension("c"); + + let cc = Compiler::new().expect("configured compiler"); + cc.compile(&c_file, &exe)?; + + let mut cmd = Command::new(exe); + cmd.stderr(Stdio::inherit()); + let out = cmd.output()?; + if !out.status.success() { + let (status, stdout) = (out.status, String::from_utf8_lossy(&out.stdout)); + return Err(format!("command {cmd:?} failed, {status:?}\nstdout: {stdout}").into()); + } + + Ok(String::from_utf8(out.stdout)?) +} + +const RUST_LAYOUTS: &[(&str, Layout)] = &[ + ( + "GstAnalyticsClsMtd", + Layout { + size: size_of::(), + alignment: align_of::(), + }, + ), + ( + "GstAnalyticsMtd", + Layout { + size: size_of::(), + alignment: align_of::(), + }, + ), + ( + "GstAnalyticsMtdImpl", + Layout { + size: size_of::(), + alignment: align_of::(), + }, + ), + ( + "GstAnalyticsMtdType", + Layout { + size: size_of::(), + alignment: align_of::(), + }, + ), + ( + "GstAnalyticsODMtd", + Layout { + size: size_of::(), + alignment: align_of::(), + }, + ), + ( + "GstAnalyticsRelTypes", + Layout { + size: size_of::(), + alignment: align_of::(), + }, + ), + ( + "GstAnalyticsRelationMetaInitParams", + Layout { + size: size_of::(), + alignment: align_of::(), + }, + ), + ( + "GstAnalyticsTrackingMtd", + Layout { + size: size_of::(), + alignment: align_of::(), + }, + ), +]; + +const RUST_CONSTANTS: &[(&str, &str)] = &[ + ("GST_ANALYTICS_MTD_TYPE_ANY", "0"), + ("(guint) GST_ANALYTICS_REL_TYPE_ANY", "2147483647"), + ("(guint) GST_ANALYTICS_REL_TYPE_CONTAIN", "4"), + ("(guint) GST_ANALYTICS_REL_TYPE_IS_PART_OF", "2"), + ("(guint) GST_ANALYTICS_REL_TYPE_LAST", "16"), + ("(guint) GST_ANALYTICS_REL_TYPE_NONE", "0"), + ("(guint) GST_ANALYTICS_REL_TYPE_RELATE_TO", "8"), + ("GST_AN_RELATION_META_TAG", "GST-ANALYSIS-RELATION-META-TAG"), + ("GST_INF_RELATION_SPAN", "-1"), +]; diff --git a/gstreamer-analytics/sys/tests/constant.c b/gstreamer-analytics/sys/tests/constant.c new file mode 100644 index 000000000..9a44a7343 --- /dev/null +++ b/gstreamer-analytics/sys/tests/constant.c @@ -0,0 +1,42 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git) +// DO NOT EDIT + +#include "manual.h" +#include + +#define PRINT_CONSTANT(CONSTANT_NAME) \ + printf("%s;", #CONSTANT_NAME); \ + printf(_Generic((CONSTANT_NAME), \ + char *: "%s", \ + const char *: "%s", \ + char: "%c", \ + signed char: "%hhd", \ + unsigned char: "%hhu", \ + short int: "%hd", \ + unsigned short int: "%hu", \ + int: "%d", \ + unsigned int: "%u", \ + long: "%ld", \ + unsigned long: "%lu", \ + long long: "%lld", \ + unsigned long long: "%llu", \ + float: "%f", \ + double: "%f", \ + long double: "%ld"), \ + CONSTANT_NAME); \ + printf("\n"); + +int main() { + PRINT_CONSTANT(GST_ANALYTICS_MTD_TYPE_ANY); + PRINT_CONSTANT((guint) GST_ANALYTICS_REL_TYPE_ANY); + PRINT_CONSTANT((guint) GST_ANALYTICS_REL_TYPE_CONTAIN); + PRINT_CONSTANT((guint) GST_ANALYTICS_REL_TYPE_IS_PART_OF); + PRINT_CONSTANT((guint) GST_ANALYTICS_REL_TYPE_LAST); + PRINT_CONSTANT((guint) GST_ANALYTICS_REL_TYPE_NONE); + PRINT_CONSTANT((guint) GST_ANALYTICS_REL_TYPE_RELATE_TO); + PRINT_CONSTANT(GST_AN_RELATION_META_TAG); + PRINT_CONSTANT(GST_INF_RELATION_SPAN); + return 0; +} diff --git a/gstreamer-analytics/sys/tests/layout.c b/gstreamer-analytics/sys/tests/layout.c new file mode 100644 index 000000000..6739517b3 --- /dev/null +++ b/gstreamer-analytics/sys/tests/layout.c @@ -0,0 +1,20 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git) +// DO NOT EDIT + +#include "manual.h" +#include +#include + +int main() { + printf("%s;%zu;%zu\n", "GstAnalyticsClsMtd", sizeof(GstAnalyticsClsMtd), alignof(GstAnalyticsClsMtd)); + printf("%s;%zu;%zu\n", "GstAnalyticsMtd", sizeof(GstAnalyticsMtd), alignof(GstAnalyticsMtd)); + printf("%s;%zu;%zu\n", "GstAnalyticsMtdImpl", sizeof(GstAnalyticsMtdImpl), alignof(GstAnalyticsMtdImpl)); + printf("%s;%zu;%zu\n", "GstAnalyticsMtdType", sizeof(GstAnalyticsMtdType), alignof(GstAnalyticsMtdType)); + printf("%s;%zu;%zu\n", "GstAnalyticsODMtd", sizeof(GstAnalyticsODMtd), alignof(GstAnalyticsODMtd)); + printf("%s;%zu;%zu\n", "GstAnalyticsRelTypes", sizeof(GstAnalyticsRelTypes), alignof(GstAnalyticsRelTypes)); + printf("%s;%zu;%zu\n", "GstAnalyticsRelationMetaInitParams", sizeof(GstAnalyticsRelationMetaInitParams), alignof(GstAnalyticsRelationMetaInitParams)); + printf("%s;%zu;%zu\n", "GstAnalyticsTrackingMtd", sizeof(GstAnalyticsTrackingMtd), alignof(GstAnalyticsTrackingMtd)); + return 0; +} diff --git a/gstreamer-analytics/sys/tests/manual.h b/gstreamer-analytics/sys/tests/manual.h new file mode 100644 index 000000000..cf6ba3fa5 --- /dev/null +++ b/gstreamer-analytics/sys/tests/manual.h @@ -0,0 +1,3 @@ +// Feel free to edit this file, it won't be regenerated by gir generator unless removed. + +#include \ No newline at end of file diff --git a/gstreamer-analytics/tests/check_gir.rs b/gstreamer-analytics/tests/check_gir.rs new file mode 100644 index 000000000..2ccf5ff05 --- /dev/null +++ b/gstreamer-analytics/tests/check_gir.rs @@ -0,0 +1,8 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +#[test] +fn check_gir_file() { + let res = gir_format_check::check_gir_file("Gir.toml"); + println!("{res}"); + assert_eq!(res.nb_errors, 0); +} diff --git a/gstreamer-app/src/auto/versions.txt b/gstreamer-app/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-app/src/auto/versions.txt +++ b/gstreamer-app/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-app/sys/src/auto/versions.txt b/gstreamer-app/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-app/sys/src/auto/versions.txt +++ b/gstreamer-app/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-audio/src/auto/versions.txt b/gstreamer-audio/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-audio/src/auto/versions.txt +++ b/gstreamer-audio/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-audio/sys/src/auto/versions.txt b/gstreamer-audio/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-audio/sys/src/auto/versions.txt +++ b/gstreamer-audio/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-base/src/auto/versions.txt b/gstreamer-base/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-base/src/auto/versions.txt +++ b/gstreamer-base/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-base/sys/src/auto/versions.txt b/gstreamer-base/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-base/sys/src/auto/versions.txt +++ b/gstreamer-base/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-check/src/auto/versions.txt b/gstreamer-check/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-check/src/auto/versions.txt +++ b/gstreamer-check/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-check/sys/src/auto/versions.txt b/gstreamer-check/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-check/sys/src/auto/versions.txt +++ b/gstreamer-check/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-controller/src/auto/versions.txt b/gstreamer-controller/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-controller/src/auto/versions.txt +++ b/gstreamer-controller/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-controller/sys/src/auto/versions.txt b/gstreamer-controller/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-controller/sys/src/auto/versions.txt +++ b/gstreamer-controller/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-editing-services/src/auto/versions.txt b/gstreamer-editing-services/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-editing-services/src/auto/versions.txt +++ b/gstreamer-editing-services/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-editing-services/sys/src/auto/versions.txt b/gstreamer-editing-services/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-editing-services/sys/src/auto/versions.txt +++ b/gstreamer-editing-services/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-gl/egl/src/auto/versions.txt b/gstreamer-gl/egl/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-gl/egl/src/auto/versions.txt +++ b/gstreamer-gl/egl/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-gl/egl/sys/src/auto/versions.txt b/gstreamer-gl/egl/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-gl/egl/sys/src/auto/versions.txt +++ b/gstreamer-gl/egl/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-gl/src/auto/versions.txt b/gstreamer-gl/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-gl/src/auto/versions.txt +++ b/gstreamer-gl/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-gl/sys/src/auto/versions.txt b/gstreamer-gl/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-gl/sys/src/auto/versions.txt +++ b/gstreamer-gl/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-gl/wayland/src/auto/versions.txt b/gstreamer-gl/wayland/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-gl/wayland/src/auto/versions.txt +++ b/gstreamer-gl/wayland/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-gl/wayland/sys/src/auto/versions.txt b/gstreamer-gl/wayland/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-gl/wayland/sys/src/auto/versions.txt +++ b/gstreamer-gl/wayland/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-gl/x11/src/auto/versions.txt b/gstreamer-gl/x11/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-gl/x11/src/auto/versions.txt +++ b/gstreamer-gl/x11/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-gl/x11/sys/src/auto/versions.txt b/gstreamer-gl/x11/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-gl/x11/sys/src/auto/versions.txt +++ b/gstreamer-gl/x11/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-mpegts/src/auto/versions.txt b/gstreamer-mpegts/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-mpegts/src/auto/versions.txt +++ b/gstreamer-mpegts/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-mpegts/sys/src/auto/versions.txt b/gstreamer-mpegts/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-mpegts/sys/src/auto/versions.txt +++ b/gstreamer-mpegts/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-net/src/auto/versions.txt b/gstreamer-net/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-net/src/auto/versions.txt +++ b/gstreamer-net/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-net/sys/src/auto/versions.txt b/gstreamer-net/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-net/sys/src/auto/versions.txt +++ b/gstreamer-net/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-pbutils/src/auto/versions.txt b/gstreamer-pbutils/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-pbutils/src/auto/versions.txt +++ b/gstreamer-pbutils/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-pbutils/sys/src/auto/versions.txt b/gstreamer-pbutils/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-pbutils/sys/src/auto/versions.txt +++ b/gstreamer-pbutils/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-play/src/auto/versions.txt b/gstreamer-play/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-play/src/auto/versions.txt +++ b/gstreamer-play/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-play/sys/src/auto/versions.txt b/gstreamer-play/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-play/sys/src/auto/versions.txt +++ b/gstreamer-play/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-player/src/auto/versions.txt b/gstreamer-player/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-player/src/auto/versions.txt +++ b/gstreamer-player/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-player/sys/src/auto/versions.txt b/gstreamer-player/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-player/sys/src/auto/versions.txt +++ b/gstreamer-player/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-rtp/src/auto/versions.txt b/gstreamer-rtp/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-rtp/src/auto/versions.txt +++ b/gstreamer-rtp/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-rtp/sys/src/auto/versions.txt b/gstreamer-rtp/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-rtp/sys/src/auto/versions.txt +++ b/gstreamer-rtp/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-rtsp-server/src/auto/versions.txt b/gstreamer-rtsp-server/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-rtsp-server/src/auto/versions.txt +++ b/gstreamer-rtsp-server/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-rtsp-server/sys/src/auto/versions.txt b/gstreamer-rtsp-server/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-rtsp-server/sys/src/auto/versions.txt +++ b/gstreamer-rtsp-server/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-rtsp/src/auto/versions.txt b/gstreamer-rtsp/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-rtsp/src/auto/versions.txt +++ b/gstreamer-rtsp/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-rtsp/sys/src/auto/versions.txt b/gstreamer-rtsp/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-rtsp/sys/src/auto/versions.txt +++ b/gstreamer-rtsp/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-sdp/src/auto/versions.txt b/gstreamer-sdp/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-sdp/src/auto/versions.txt +++ b/gstreamer-sdp/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-sdp/sys/src/auto/versions.txt b/gstreamer-sdp/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-sdp/sys/src/auto/versions.txt +++ b/gstreamer-sdp/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-tag/sys/src/auto/versions.txt b/gstreamer-tag/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-tag/sys/src/auto/versions.txt +++ b/gstreamer-tag/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-validate/src/auto/versions.txt b/gstreamer-validate/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-validate/src/auto/versions.txt +++ b/gstreamer-validate/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-validate/sys/src/auto/versions.txt b/gstreamer-validate/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-validate/sys/src/auto/versions.txt +++ b/gstreamer-validate/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-video/src/auto/versions.txt b/gstreamer-video/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-video/src/auto/versions.txt +++ b/gstreamer-video/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-video/sys/src/auto/versions.txt b/gstreamer-video/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-video/sys/src/auto/versions.txt +++ b/gstreamer-video/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-webrtc/src/auto/versions.txt b/gstreamer-webrtc/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-webrtc/src/auto/versions.txt +++ b/gstreamer-webrtc/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer-webrtc/sys/src/auto/versions.txt b/gstreamer-webrtc/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer-webrtc/sys/src/auto/versions.txt +++ b/gstreamer-webrtc/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer/src/auto/versions.txt b/gstreamer/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer/src/auto/versions.txt +++ b/gstreamer/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b) diff --git a/gstreamer/sys/src/auto/versions.txt b/gstreamer/sys/src/auto/versions.txt index d1f2879ae..62039a28e 100644 --- a/gstreamer/sys/src/auto/versions.txt +++ b/gstreamer/sys/src/auto/versions.txt @@ -1,3 +1,3 @@ Generated by gir (https://github.com/gtk-rs/gir @ 5975266da3b0) from gir-files (https://github.com/gtk-rs/gir-files @ fe8258109e60) -from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 3f9f549accb7) +from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 63e90a30193b)