Compare commits

..

108 commits
main ... 0.21

Author SHA1 Message Date
Sebastian Dröge
6359c2ddf0 gstreamer: Fix gstreamer-sys versioned dependency 2023-12-18 11:05:08 +02:00
Sebastian Dröge
8017fa541a Update CHANGELOG.md for 0.21.3 2023-12-18 11:03:13 +02:00
Sebastian Dröge
9f7eae9693 Update versions to 0.21.3 2023-12-18 11:03:07 +02:00
Sebastian Dröge
8c286faaa6 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:58:36 +02:00
Sebastian Dröge
0f6bbcfb6c gstreamer: memory: Fix assertions for copy_range/resize/share functions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:57:40 +02:00
Olivier Crête
35ce5d1494 gstreamer: meta: Implement Clone trait on MetaRef
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:57:30 +02:00
Sebastian Dröge
42c028672f gstreamer: formatted values: Implement ClockTime::absdiff() and on related types
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/494

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:57:21 +02:00
Sebastian Dröge
2871edeca7 Update to pretty-hex 0.4
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:57:14 +02:00
Sebastian Dröge
5c8c29f7e4 examples: Add a few more docs/comments to the subclass/virtual methods example
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:57:10 +02:00
Sebastian Dröge
593de5c551 examples: Add an example that shows how to write subclasses with virtual methods
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:57:04 +02:00
Sebastian Dröge
02f4e7dad0 gstreamer: audiofilter: Add parent_allowed_caps()
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:56:52 +02:00
Dave Patrick Caberto
9f3ae6aa77 pbutils: make element_properties mod public
This makes the builders accessible/nameable.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:56:37 +02:00
Sebastian Dröge
ef84e3e71b examples: Update to windows 0.52
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:56:22 +02:00
Sebastian Dröge
bd3a053ff1 Update versions of all autogenerated files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:56:16 +02:00
Sebastian Dröge
d1be4756b0 net: Add new PtpClock::init_full() function
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:56:16 +02:00
Philippe Normand
80eaa01ce8 gstreamer-editing-services: Add bindings for FrameCompositionMeta
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:56:16 +02:00
Philippe Normand
7ea168a6a0 gst-gir-files: Update submodule for GES FrameCompositionMeta
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:53:50 +02:00
Bilal Elmoussaoui
eedac4642c ci/docs: Add missing cfg docsrs
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:53:40 +02:00
Sebastian Dröge
48ee57c63f ci: Update to Rust 1.74
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:53:34 +02:00
Sebastian Dröge
e982c07255 Update to itertool 0.12
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:53:24 +02:00
Sebastian Dröge
fc3fb363e7 examples: play: Set message bus to flushing before dropping the Play reference
Otherwise there might be pending messages on the bus that keep a
reference to the `Play` instance alive, and neither the bus nor the
`Play` are ever going to be freed then.

See also https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/489
and https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3107.

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/493

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1366>
2023-12-18 09:53:19 +02:00
Sebastian Dröge
70ee948623 Update Cargo.lock 2023-11-11 15:55:15 +02:00
Sebastian Dröge
25e13209db Update versions to 0.21.2 2023-11-11 15:55:15 +02:00
Sebastian Dröge
c0a4545c83 Update CHANGELOG.md for 0.21.2 2023-11-11 15:41:37 +02:00
Sebastian Dröge
408e97ad70 allocators: Ignore init_once() function correctly
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:44:08 +02:00
Sebastian Dröge
a4c3a484cf gl: Update serde serialization tests for new flags/enum variants
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:40:28 +02:00
Sebastian Dröge
db82a4d591 ci: Update image version for rebuild
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:40:28 +02:00
Sebastian Dröge
7324d27869 video: Add VIDEO_FORMATS_ANY and iterator over the formats
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:40:28 +02:00
Sebastian Dröge
12fd38a33e allocator: Generate new ShmAllocator
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:40:28 +02:00
Sebastian Dröge
01c4151870 Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:40:28 +02:00
Sebastian Dröge
36f13a8007 Update some Gir.toml configuration
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:40:28 +02:00
Sebastian Dröge
905a0b6887 Update gst-gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:40:28 +02:00
Marijn Suijten
6b95762ea7 examples/glupload: Upgrade to glutin 0.31
Glutin completely detached from `winit` in the `0.30` upgrade, concerning
itself exclusively with OpenGL and WSI APIs around it and leaving any
windowing system interop to the `raw-window-handle` crate specifically
designed for this purpose.

This untanglement massively cleans up and simplifies the `glutin`
codebase, and expands on surfaceless rendering as well as drawing to
simple views (textures) on the screen as is common on Android, without
having control over the entire "window" and event loop.

Some winit boilerplate is however still provided as part of the
`glutin-winit` crate.  Most of the `glutin`+`winit` flow in this
`glupload` example is adopted from `glutin`'s example, following
platform-specific initialization sequences that heavily clutter the code
(only creating a window upfront on Windows, only forcing transparency on
macOS, and trying various fallback attributes to create a context).

At the same time `winit`'s `Event::Resumed` and `Event::Suspended`
event strategy is adopted: this event was previously for Android and
iOS exclusively - where window handles come and go at the merit of
the OS, rather than existing for the lifetime of the application -
but is now emitted on all platforms for consistency.  A `Surface` (via
`RawWindowHandle`) is only available and usable after `Event::Resumed`,
where we can create a GL surface and "current" the context on that
surface for rendering.  This is where the `GstPipeline` will be set
to `Playing` so that data starts flowing.  The inverse should happen in
`Event::Suspended` where the `Surface` has to be given up again after
un-currenting, before giving control back to the OS to free the rest of
the resources.  This will however be implemented when Android is brought
online for these examples.

Finally, now that the `gst-gl-egl` and `gst-gl-x11` features turn on
the relevant features in `glutin` and `winit`, it is now possible to
easily test `x11` on Wayland (over XWayland) without even unsetting
`WAYLAND_DISPLAY`, by simply compiling the whole stack without EGL/
Wayland support (on the previous example `winit` would always default to
a Wayland handle, while `glupload` could only create `GstGLDisplayX11`).

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:40:28 +02:00
Marijn Suijten
cb40917ac9 examples/glupload: Pass actual program handle to glGetProgramiv()
This is what you get with an untyped API.  `glGetError()` further down
the line was returning `GL_INVALID_OPERATION` and failing other calls
after `load()` in the `glutin 0.31` upgrade.  This turns out to be
[returned by `glGetProgramiv`] when the `program` that is passed in
does not refer to a program object.  Which was the case here, where the
fragment shader identifier was passed in instead.

Just in case we insert a few extra asserts that check the result of
`glGetError()` to catch such issues earlier on in the chain, instead of
postponing them and falsely accusing code that runs later.

[returned by `glGetProgramiv`]: https://registry.khronos.org/OpenGL-Refpages/es2.0/xhtml/glGetProgramiv.xml#errors

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:34:42 +02:00
Marijn Suijten
4c0f03d5fd examples/glupload: Remove Wayland display integration
`GstGLDisplayWayland` calls GstGLDisplayEGL::from_gl_display()` under
the hood (which calls `GstGLDisplayEGL::from_native()`, which calls
`eglGetPlatformDisplay()`) to retrieve the underlying `EGLDisplay`
handle, which thus far seems to be the same value as `glutin`.  However,
newer `glutin 0.31` passes attributes to this function resulting in a
different handle, causing all kinds of trouble further down the line
when sharing resources between `glutin` and `gstreamer-rs` that both
operate on a distinct `EGLDisplay`.

Furthermore `GstGLDisplayEGL` thinks that it uniquely owns the
handle returned by `eglGetPlatformDisplay()` and _does not_ set
`.foreign_display = TRUE` (which `GstGLDisplayEGL::with_egl_display()`
would), causing it to call `eglTerminate()` as soon as the
`GstGLDisplay` is destroyed, leaving `glutin` dysfunctional.

To solve all of this, simply remove this wrongly-behaving class from the
example as it is not suitable for sharing an `EGLDisplay` with `glutin`.

It might however be interesting to create a different example that
showcases how to use raw window handles instead of EGL/GLX handles,
however only Wayland and any platform on EGL like Android, via
`GstGLDisplayEGL::from_native()`, support this.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:34:42 +02:00
Marijn Suijten
07d9fba822 examples/glupload: Sanity-check that the EGL display via Wayland equals glutin
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:34:42 +02:00
Marijn Suijten
8e4a561a41 examples: Return anyhow::Result out of main()
It is annoying to see only a single line of error when debugging a chain
of (e.g. `anyhow::Context::context()`-created) errors, and have a
zero exit-code while at it.

Instead Rust supports returning a `Result` type straight from main which
is `Debug`- instead of `Display`-printed, so that - in the case of
`anyhow::Error` - all nested (via `.source()`) `Error`s are printed in
backtrace-like form, and the exit code is appropriately non-zero.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 11:34:42 +02:00
Marijn Suijten
40637647b9 gl/egl: Appropriately mark display functions as manual
Two functions were manually implemented but not marked as such, leaving
unneeded "TODO call ffi:xxx" markers in the codebase.  Also improve the
aliases on the manual implementations.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 10:52:08 +02:00
Marijn Suijten
9b92261c42 gl: Provide raw handle() getter function on GLDisplay
Having access to the raw handle is useful when sharing the display
and context with an existing application.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1344>
2023-11-11 10:52:08 +02:00
Sebastian Dröge
a97de245c9 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1342>
2023-11-10 09:48:16 +02:00
Sebastian Dröge
5abf146212 utils: streamproducer: Don't use gst_element_send_event() in another place
It can cause deadlocks thanks to taking the state lock.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1342>
2023-11-10 09:47:53 +02:00
Sebastian Dröge
763cddfba6 deny: Add override for duplicated toml_edit dependency
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1342>
2023-11-10 09:47:46 +02:00
Sebastian Dröge
df223af719 element: Add catch_panic_future() helper function for subclasses
This allows wrapping a future in a way that panics are converted to
error messages on the object.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1342>
2023-11-10 09:47:36 +02:00
Sebastian Dröge
27380d237c gstreamer: meta: Add MetaRef::copy() for copying a meta between buffers
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1342>
2023-11-10 09:47:29 +02:00
Sebastian Dröge
cb150485b1 gstreamer: meta: Add as_meta_ref() to MetaRefMut
This reduces code duplication between `MetaRef` and `MetaRefMut`.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1342>
2023-11-10 09:47:24 +02:00
Sebastian Dröge
7d77858bc8 gstreamer: meta: Give returned tags array an arbitrary lifetime
The tags are statically stored.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1342>
2023-11-10 09:47:12 +02:00
Sebastian Dröge
437ec48ae1 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
03c4721aa3 Use let-else instead of match for weak reference upgrades
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
0a82caa706 tutorials: Use async-channel instead of the glib MainContext channel
The latter will be removed in favour of using async code in the future,
and async code generally allows for more flexible message handling than the
callback based MainContext channel.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
470b727252 gstreamer: meta: Move has_tag() and tags() getters to MetaRef
On `MetaAPI` only the static meta API type is known and based on that
it's not possible to work with the tags of a specific meta instance's
API.

As the methods take a `&self` anyway they would be expected to check the
value at hand instead.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
8027269c7b gstreamer: Simplify MetaAPIExt trait implementation
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
6f52f3e4fa gstreamer: meta: Add upcast_ref() function to go from a specific to a generic meta
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
db2b39d382 gstreamer: meta: Remove useless API on Meta that can't be called anyway
`Meta` only exists inside a `MetaRef` / `MetaRefMut` and that already
provides exactly the same functions for all meta types.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
66e822dbf7 gstreamer: meta: Add some more AsRef and AsMut impls
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
c5262fa69f gstreamer: format: Implement some more conversion traits
Specifically, `From<$formatted_type> for $inner` and
`TryFrom<$formatted_type> for usize` for some types.

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/492

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
08ce9f5b2f gstreamer: Implement Default trait for AllocationParams
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
François Laignel
de87e6061e video: fix big endian video format order
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
c2b5341b8f gstreamer: Add accessors for PadProbeDatas on PadProbeInfo
And make use of it in examples and other code.

This allows to simplify usage a bit in most cases.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
43096963de gstreamer: Simplify Element::element_class() implementation a bit
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Sebastian Dröge
3b30546461 gstreamer: Add DeviceProviderClassExt extension trait for class methods
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
Bilal Elmoussaoui
7975383e96 docs/gstreamer: Embed docs for ElementClass functions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
François Laignel
d3e54789fe video: fix visibility for VideoVBIEncoder::try_new
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 11:09:35 +02:00
François Laignel
f2a5960c36 gst-video: bindings for VideoVBIEncoder & VideoVBIParser
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 10:46:30 +02:00
François Laignel
b1c7d225b1 gst-video: generate vertical blanking interval related bindings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 10:46:23 +02:00
Sebastian Dröge
08efe21002 examples: Updates to memmap2 0.9
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 10:46:18 +02:00
Sebastian Dröge
e531c7f565 ci: Update to Rust 1.73
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1337>
2023-11-03 10:46:10 +02:00
Sebastian Dröge
7622ceb03a ci: Don't run cargo update as part of the CI
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1334>
2023-11-02 15:35:28 +02:00
Sebastian Dröge
bc69e3dafd Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1334>
2023-11-02 15:07:41 +02:00
Sebastian Dröge
7b6ae13008 Update gir to latest 0.18 branch
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1334>
2023-11-02 15:07:11 +02:00
Sebastian Dröge
71bbcc00e2 Depend on 0.21.1 of the -sys crates where necessary 2023-10-04 10:24:59 +03:00
Sebastian Dröge
7d5f8e95bf gl: Don't autogenerate GL buffer pool configuration functions
These need manual bindings.
2023-10-04 10:24:59 +03:00
Sebastian Dröge
c407ce825d Update CHANGELOG.md for 0.21.1 2023-10-04 10:17:15 +03:00
Sebastian Dröge
11699fda0f Update Cargo.lock 2023-10-04 10:13:54 +03:00
Sebastian Dröge
4e9b155b90 Update versions to 0.21.1 2023-10-04 10:13:26 +03:00
Sebastian Dröge
66a0e36e22 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:47:43 +03:00
Sebastian Dröge
f525e7cea7 Drop 0.20 docs to reduce disk usage requirements
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/482

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:43:12 +03:00
Sebastian Dröge
6a41f4b9b5 ci: Build 0.21 docs and drop 0.19 docs
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:43:12 +03:00
Sebastian Dröge
44facc5a82 Regenerate with latest gir / gir-files / gst-gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:42:05 +03:00
Sebastian Dröge
1a4a725793 Update gir-files to latest 0.18 branch
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:40:10 +03:00
Sebastian Dröge
e1fd8b36c8 Update gir to latest 0.18 branch
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:39:54 +03:00
Sebastian Dröge
73a6aa1f26 Fix various new 1.73 clippy warnings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:39:42 +03:00
Guillaume Desmottes
6c6384e9cd gst-utils: prevent dead lock when requesting key unit
Sending the UpstreamForceKeyUnitEvent using gst_element_send_event()
internally takes the state lock. If appsink is pre-rolling we are also
holding the preroll lock.

This may result in a dead lock with the thread doing the state change as
this one takes the state lock and then the pre-roll lock.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:39:37 +03:00
Sebastian Dröge
3c7ace5451 gst: Add CustomMeta::register_simple()
As a wrapper around the 1.20 `gst_meta_register_custom()` instead of the
new 1.24 convenience function to make it available to more versions.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:39:31 +03:00
Sebastian Dröge
fcad4e5aa3 app: Add max-bytes and max-time setters to the AppSink builder
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:39:25 +03:00
Sebastian Dröge
8c384e387a Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:39:18 +03:00
Sebastian Dröge
f8893ec6fb video: Fix ordering of video formats according to latest libgstvideo
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:39:12 +03:00
Sebastian Dröge
acae1d6037 ci: Update to Rust 1.72.1
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:39:05 +03:00
Kalev Lember
4cefb512cd Add COPYRIGHT and LICENSE files as links into all gstreamer-gl crates
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:38:49 +03:00
Sebastian Dröge
ee176b9b07 examples: Update to memmap2 0.8
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:38:44 +03:00
Arun Raghavan
ac5eeb7259 Minor copy-pasto fix for gstreamer-validate description
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:38:37 +03:00
Sebastian Dröge
f5dc2578fa ci: Run cargo-deny on the whole workspace with all features enabled
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:38:30 +03:00
Sebastian Dröge
2507d8262f deny: Update and skip examples / tutorials
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:38:25 +03:00
Sebastian Dröge
8c40e8b5b8 ci: Regenerate images to get new version of cargo-deny
The new version denies dependencies that include binary executables /
libraries.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:38:18 +03:00
Sebastian Dröge
411b1802ba Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:38:05 +03:00
Sebastian Dröge
c38dd726a7 Update indentation for rustfmt 1.72
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:37:36 +03:00
Sebastian Dröge
682d0a1ac6 ci: Update to Rust 1.72
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:37:31 +03:00
Sebastian Dröge
d10b1b2722 Fix/silence various 1.72 clippy warnings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:37:08 +03:00
Sebastian Dröge
b0e5419d7d examples: Update to windows 0.51
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:36:53 +03:00
Sebastian Dröge
fd40a98f8c examples: Update to uds 0.4
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:36:45 +03:00
Tim-Philipp Müller
f53b78a0cb tutorials: update old gstreamer-sdk media links
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1318>
2023-10-03 19:36:39 +03:00
Sebastian Dröge
5022d85b83 Switch to resolver = "2" for the workspace 2023-08-09 10:35:39 +03:00
Sebastian Dröge
639dbcd6bb Add Cargo.lock 2023-08-08 19:54:53 +03:00
Sebastian Dröge
7f773090ce Update CHANGELOG.md for 0.21.0 2023-08-08 19:23:40 +03:00
Sebastian Dröge
cee6d20ad8 Add version = "0.21" to all local dependencies 2023-08-08 18:15:44 +03:00
Sebastian Dröge
9d8fbb7d7c Regenerate with 0.18 gir / gir-files 2023-08-08 17:51:48 +03:00
Sebastian Dröge
214f050a24 gir-files: Update to 0.18 branch 2023-08-08 17:51:23 +03:00
Sebastian Dröge
4988cc7bb2 gir: Update to 0.18 branch 2023-08-08 17:51:19 +03:00
Sebastian Dröge
5b928af1f5 Update dependencies to gtk-rs-core 0.18 branch 2023-08-08 17:51:16 +03:00
591 changed files with 5175 additions and 15048 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
target/
**/*.rs.bk
Cargo.lock

View file

@ -56,7 +56,7 @@ variables:
# latest release must be at the top
# (only relevant on main branch)
RELEASES:
0.22=0.22
0.21=0.21
stages:
- "trigger"
@ -73,7 +73,6 @@ trigger:
stage: 'trigger'
variables:
GIT_STRATEGY: none
tags: [ 'placeholder-job' ]
script:
- echo "Trigger job done, now running the pipeline."
rules:
@ -142,7 +141,6 @@ trigger:
libpango1.0-dev libcairo2-dev libjson-glib-dev libgdk-pixbuf-2.0-dev
libtiff-dev libpng-dev libjpeg-dev libepoxy-dev libsass-dev sassc
libcsound64-dev llvm clang nasm libsodium-dev libwebp-dev
libflac-dev
FDO_DISTRIBUTION_EXEC: >-
bash ci/install-gst.sh &&
bash ci/install-dav1d.sh &&
@ -313,7 +311,6 @@ test nightly sys:
rustfmt:
extends: .img-stable
stage: "lint"
tags: [ 'placeholder-job' ]
script:
- cargo fmt --version
- cargo fmt -- --color=always --check
@ -324,7 +321,6 @@ rustfmt:
check commits:
extends: .img-stable
stage: "lint"
tags: [ 'placeholder-job' ]
script:
- ci-fairy check-commits --textwidth 0 --no-signed-off-by
needs:
@ -334,7 +330,6 @@ check commits:
typos:
extends: .img-stable
stage: "lint"
tags: [ 'placeholder-job' ]
script:
- typos
needs:
@ -363,7 +358,6 @@ deny:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
script:
- cargo update --color=always
- cargo deny --color=always --workspace --all-features check all
gir-checks:
@ -371,7 +365,6 @@ gir-checks:
GIT_SUBMODULE_STRATEGY: recursive
extends: .img-stable
stage: 'extras'
tags: [ 'placeholder-job' ]
needs:
- job: 'build-stable'
artifacts: false
@ -388,7 +381,6 @@ outdated:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
script:
- cargo update --color=always
- cargo outdated --color=always --root-deps-only --exit-code 1 -v
coverage:
@ -514,6 +506,7 @@ pages:
# We also don't need a CONTEXT_DIR var as its also
# hardcoded to be windows-docker/
DOCKERFILE: 'ci/windows-docker/Dockerfile'
GST_UPSTREAM_BRANCH: 'main'
tags:
- 'windows'
- 'shell'

1021
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,6 @@ resolver = "2"
default-members = [
"gstreamer/sys",
"gstreamer-analytics/sys",
"gstreamer-app/sys",
"gstreamer-audio/sys",
"gstreamer-base/sys",
@ -23,7 +22,6 @@ default-members = [
"gstreamer-video/sys",
"gstreamer-webrtc/sys",
"gstreamer",
"gstreamer-analytics",
"gstreamer-app",
"gstreamer-audio",
"gstreamer-base",
@ -39,7 +37,6 @@ default-members = [
"gstreamer-rtsp",
"gstreamer-rtsp-server",
"gstreamer-sdp",
"gstreamer-tag",
"gstreamer-validate",
"gstreamer-video",
"gstreamer-webrtc",
@ -49,7 +46,6 @@ default-members = [
members = [
"gstreamer/sys",
"gstreamer-analytics/sys",
"gstreamer-app/sys",
"gstreamer-audio/sys",
"gstreamer-base/sys",
@ -74,7 +70,6 @@ members = [
"gstreamer-webrtc/sys",
"gstreamer-allocators/sys",
"gstreamer",
"gstreamer-analytics",
"gstreamer-app",
"gstreamer-audio",
"gstreamer-base",
@ -94,7 +89,6 @@ members = [
"gstreamer-rtsp",
"gstreamer-rtsp-server",
"gstreamer-sdp",
"gstreamer-tag",
"gstreamer-validate",
"gstreamer-video",
"gstreamer-webrtc",
@ -105,48 +99,3 @@ members = [
]
exclude = ["gir"]
[workspace.package]
version = "0.23.0"
categories = ["api-bindings", "multimedia"]
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
homepage = "https://gstreamer.freedesktop.org"
edition = "2021"
rust-version = "1.70"
[workspace.dependencies]
gio = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
gio-sys = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
glib-sys = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
gobject-sys = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
cairo-rs = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
pango = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
pangocairo = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "master" }
gstreamer-audio-sys = { path = "./gstreamer-audio/sys"}
gstreamer-base-sys = { path = "./gstreamer-base/sys"}
gstreamer-gl-sys = { path = "./gstreamer-gl/sys"}
gstreamer-net-sys = { path = "./gstreamer-net/sys"}
gstreamer-pbutils-sys = { path = "./gstreamer-pbutils/sys"}
gstreamer-rtsp-sys = { path = "./gstreamer-rtsp/sys"}
gstreamer-sdp-sys = { path = "./gstreamer-sdp/sys"}
gstreamer-sys = { path = "./gstreamer/sys"}
gstreamer-video-sys = { path = "./gstreamer-video/sys"}
ges = { package = "gstreamer-editing-services", path = "./gstreamer-editing-services" }
gst = { package = "gstreamer", path = "./gstreamer" }
gst-allocators = { package = "gstreamer-allocators", path = "./gstreamer-allocators" }
gst-app = { package = "gstreamer-app", path = "./gstreamer-app" }
gst-audio = { package = "gstreamer-audio", path = "./gstreamer-audio" }
gst-base = { package = "gstreamer-base", path = "./gstreamer-base" }
gst-check = { package = "gstreamer-check", path = "./gstreamer-check" }
gst-gl = { package = "gstreamer-gl", path = "./gstreamer-gl" }
gst-gl-egl = { package = "gstreamer-gl-egl", path = "./gstreamer-gl/egl" }
gst-gl-x11 = { package = "gstreamer-gl-x11", path = "./gstreamer-gl/x11" }
gst-net = { package = "gstreamer-net", path = "./gstreamer-net" }
gst-pbutils = { package = "gstreamer-pbutils", path = "./gstreamer-pbutils" }
gst-play = { package = "gstreamer-play", path = "./gstreamer-play" }
gst-player = { package = "gstreamer-player", path = "./gstreamer-player" }
gst-rtsp = { package = "gstreamer-rtsp", path = "./gstreamer-rtsp" }
gst-rtsp-server = { package = "gstreamer-rtsp-server", path = "./gstreamer-rtsp-server" }
gst-sdp = { package = "gstreamer-sdp", path = "./gstreamer-sdp" }
gst-video = { package = "gstreamer-video", path = "./gstreamer-video" }

View file

@ -1,7 +1,4 @@
variables:
GST_RS_IMG_TAG: "2024-05-10.0"
GST_RS_STABLE: "1.78.0"
GST_RS_IMG_TAG: "2023-11-16.0"
GST_RS_STABLE: "1.74.0"
GST_RS_MSRV: "1.70.0"
# The branch we use to build GStreamer from in the docker images
# Ex. main, 1.24, my-test-branch
GST_UPSTREAM_BRANCH: 'main'

View file

@ -1,6 +1,6 @@
set -e
RELEASE=1.4.1
RELEASE=1.1.0
git clone https://code.videolan.org/videolan/dav1d.git --branch $RELEASE
cd dav1d

View file

@ -2,8 +2,6 @@
set -e
DEFAULT_BRANCH="$GST_UPSTREAM_BRANCH"
pip3 install meson==1.1.1 --break-system-packages
# gstreamer-rs already has a 'gstreamer' directory so don't clone there
@ -11,7 +9,7 @@ pushd .
cd ..
git clone https://gitlab.freedesktop.org/gstreamer/gstreamer.git \
--depth 1 \
--branch "$DEFAULT_BRANCH"
--branch main
cd gstreamer

View file

@ -5,7 +5,7 @@ source ./ci/env.sh
set -e
export CARGO_HOME='/usr/local/cargo'
RUSTUP_VERSION=1.27.1
RUSTUP_VERSION=1.26.0
RUST_VERSION=$1
RUST_IMAGE_FULL=$2
RUST_ARCH="x86_64-unknown-linux-gnu"
@ -26,26 +26,20 @@ if [ "$RUST_IMAGE_FULL" = "1" ]; then
rustup component add clippy-preview
rustup component add rustfmt
cargo install --locked --force cargo-deny
cargo install --locked --force cargo-outdated
cargo install --locked --force typos-cli --version "1.19.0"
cargo install --force cargo-deny
cargo install --force cargo-outdated
cargo install --force typos-cli
# Coverage tools
rustup component add llvm-tools-preview
cargo install --locked --force grcov
cargo install --force grcov
fi
if [ "$RUST_VERSION" = "nightly" ]; then
# FIXME: Don't build cargo-c with --locked for now because otherwise a
# version of ahash is used that doesn't build on nightly anymore
cargo install cargo-c --version 0.9.22+cargo-0.72
else
cargo install --locked cargo-c --version 0.9.22+cargo-0.72
fi
cargo install cargo-c --version 0.9.22+cargo-0.72
if [ "$RUST_VERSION" = "nightly" ]; then
rustup component add rustfmt --toolchain nightly
# Documentation tools
cargo install --locked --force rustdoc-stripper
cargo install --force rustdoc-stripper
fi

View file

@ -11,10 +11,13 @@ get_features() {
crate=$1
case "$crate" in
gstreamer-audio|gstreamer-editing-services|gstreamer-gl|gstreamer-pbutils|gstreamer-rtp|gstreamer-rtsp|gstreamer-video|gstreamer)
echo "--features=serde,v1_26"
echo "--features=serde,v1_24"
;;
gstreamer-validate)
echo ""
;;
*)
echo "--features=v1_26"
echo "--features=v1_24"
;;
esac
}

View file

@ -13,14 +13,11 @@ for crate in gstreamer*/sys gstreamer-gl/*/sys; do
done
for crate in gstreamer/sys \
gstreamer-allocators/sys \
gstreamer-analytics/sys \
gstreamer-app/sys \
gstreamer-audio/sys \
gstreamer-base/sys \
gstreamer-check/sys \
gstreamer-controller/sys \
gstreamer-editing-services/sys \
gstreamer-gl/sys \
gstreamer-gl/egl/sys \
gstreamer-gl/wayland/sys \
@ -28,14 +25,11 @@ for crate in gstreamer/sys \
gstreamer-mpegts/sys \
gstreamer-net/sys \
gstreamer-pbutils/sys \
gstreamer-play/sys \
gstreamer-player/sys \
gstreamer-rtp/sys \
gstreamer-rtsp-server/sys \
gstreamer-rtsp/sys \
gstreamer-sdp/sys \
gstreamer-tag/sys \
gstreamer-validate/sys \
gstreamer-video/sys \
gstreamer-webrtc/sys; do
echo "Testing $crate with --all-features)"

View file

@ -16,7 +16,8 @@
# 'gstreamer-gl/egl',
# 'gstreamer-gl/wayland',
# 'gstreamer-gl/x11',
'gstreamer-mpegts',
# only has sys
# 'gstreamer-mpegts',
'gstreamer-mpegts/sys',
'gstreamer-net',
'gstreamer-pbutils',
@ -25,7 +26,8 @@
'gstreamer-rtsp',
'gstreamer-rtsp-server',
'gstreamer-sdp',
'gstreamer-tag',
# only has sys
# 'gstreamer-tag',
'gstreamer-tag/sys',
'gstreamer-video',
'gstreamer-webrtc',

View file

@ -2,9 +2,11 @@
FROM "registry.freedesktop.org/gstreamer/gstreamer/amd64/windows:2023-07-17.0-main"
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
# Make sure any failure in PowerShell is fatal
ENV ErrorActionPreference='Stop'
SHELL ["powershell","-NoLogo", "-NonInteractive", "-Command"]
ARG DEFAULT_BRANCH="1.24"
ARG DEFAULT_BRANCH="main"
ARG RUST_VERSION="invalid"
RUN choco install -y pkgconfiglite nasm llvm openssl
@ -19,4 +21,4 @@ RUN C:\install_dav1d.ps1
RUN Invoke-WebRequest -Uri https://win.rustup.rs/x86_64 -OutFile C:\rustup-init.exe
RUN C:\rustup-init.exe -y --profile minimal --default-toolchain $env:RUST_VERSION
RUN cargo install --locked cargo-c --version 0.9.22+cargo-0.72
RUN cargo install cargo-c --version 0.9.22+cargo-0.72

View file

@ -1,7 +1,7 @@
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
# Download gstreamer and all its subprojects
git clone -b 1.4.1 --depth 1 https://code.videolan.org/videolan/dav1d.git C:\dav1d
git clone -b 1.1.0 --depth 1 https://code.videolan.org/videolan/dav1d.git C:\dav1d
if (!$?) {
Write-Host "Failed to clone dav1d"
Exit 1

View file

@ -1,11 +1,9 @@
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
# Make sure powershell exits on errors
$ErrorActionPreference = "Stop"
# Download gstreamer and all its subprojects
git clone -b $env:DEFAULT_BRANCH --depth 1 https://gitlab.freedesktop.org/gstreamer/gstreamer.git C:\gstreamer
if (!$?) {
Write-Host "Failed to clone gstreamer"
Exit 1
}
Set-Location C:\gstreamer
@ -15,10 +13,6 @@ Move-Item C:/subprojects/* C:\gstreamer\subprojects
# Update the subprojects cache
Write-Output "Running meson subproject reset"
meson subprojects update --reset
if (!$?) {
Write-Host "Failed to update gstreamer subprojects"
Exit 1
}
$MESON_ARGS = @(`
"--prefix=C:\gst-install", `
@ -48,24 +42,9 @@ echo "subproject('gtk')" >> meson.build
Write-Output "Building gstreamer"
meson setup --vsenv $MESON_ARGS _build
if (!$?) {
type "_build\meson-logs\meson-log.txt"
Write-Host "Failed to run meson setup, see log above"
Exit 1
}
Write-Output "Compiling gstreamer"
meson compile -C _build
if (!$?) {
Write-Host "Failed to run meson compile"
Exit 1
}
# meson install does a spurious rebuild sometimes that then fails
meson install --no-rebuild -C _build
if (!$?) {
Write-Host "Failed to run meson install"
Exit 1
}
cd c:\
Remove-Item -LiteralPath "C:\gstreamer" -Force -Recurse

View file

@ -23,15 +23,20 @@ multiple-versions = "deny"
wildcards = "allow"
highlight = "all"
# proc-macro-crate depends on an older version of toml_edit
# https://github.com/bkchr/proc-macro-crate/pull/50
[[bans.skip]]
name = "toml_edit"
version = "0.21"
[sources]
unknown-registry = "deny"
unknown-git = "deny"
allow-git = [
"https://github.com/gtk-rs/gtk-rs-core",
]
# Various crates depend on an older version of syn
[[bans.skip]]
name = "syn"
version = "1.0"
# proc-macro-crate depends on an older version of toml_edit
# https://github.com/bkchr/proc-macro-crate/pull/41
[[bans.skip]]
name = "toml_edit"
version = "0.20"

View file

@ -1,33 +1,33 @@
[package]
name = "examples"
version.workspace = true
version = "0.21.3"
license = "MIT"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
edition.workspace = true
rust-version.workspace = true
edition = "2021"
rust-version = "1.70"
[dependencies]
glib.workspace = true
gst.workspace = true
gst-gl = { workspace = true, optional = true }
gst-gl-egl = { workspace = true, optional = true }
gst-gl-x11 = { workspace = true, optional = true }
gst-app.workspace = true
gst-audio.workspace = true
gst-base.workspace = true
gst-video.workspace = true
gst-pbutils.workspace = true
gst-play = { workspace = true, optional = true }
gst-player = { workspace = true, optional = true }
ges = { workspace = true, optional = true }
gst-sdp = { workspace = true, optional = true }
gst-rtsp = { workspace = true, optional = true }
gst-rtsp-server = { workspace = true, optional = true }
gst-allocators = { workspace = true, optional = true }
gio = { workspace = true, optional = true }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.18", version = "0.18" }
gst = { package = "gstreamer", path = "../gstreamer", version = "0.21" }
gst-gl = { package = "gstreamer-gl", path = "../gstreamer-gl", version = "0.21", optional = true }
gst-gl-egl = { package = "gstreamer-gl-egl", path = "../gstreamer-gl/egl", version = "0.21", optional = true }
gst-gl-x11 = { package = "gstreamer-gl-x11", path = "../gstreamer-gl/x11", version = "0.21", optional = true }
gst-app = { package = "gstreamer-app", path = "../gstreamer-app", version = "0.21" }
gst-audio = { package = "gstreamer-audio", path = "../gstreamer-audio", version = "0.21" }
gst-base = { package = "gstreamer-base", path = "../gstreamer-base", version = "0.21" }
gst-video = { package = "gstreamer-video", path = "../gstreamer-video", version = "0.21" }
gst-pbutils = { package = "gstreamer-pbutils", path = "../gstreamer-pbutils", version = "0.21" }
gst-play = { package = "gstreamer-play", path = "../gstreamer-play", version = "0.21", optional = true }
gst-player = { package = "gstreamer-player", path = "../gstreamer-player", version = "0.21", optional = true }
ges = { package = "gstreamer-editing-services", path = "../gstreamer-editing-services", version = "0.21", optional = true }
gst-sdp = { package = "gstreamer-sdp", path = "../gstreamer-sdp", version = "0.21", optional = true }
gst-rtsp = { package = "gstreamer-rtsp", path = "../gstreamer-rtsp", version = "0.21", optional = true }
gst-rtsp-server = { package = "gstreamer-rtsp-server", path = "../gstreamer-rtsp-server", version = "0.21", optional = true }
gst-allocators = { package = "gstreamer-allocators", path = "../gstreamer-allocators", version = "0.21", optional = true }
gio = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.18", version = "0.18", optional = true }
anyhow = "1.0"
byte-slice-cast = "1"
cairo-rs = { workspace = true, features=["use_glib"], optional = true }
cairo-rs = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.18", version = "0.18", features=["use_glib"], optional = true }
derive_more = "0.99.5"
futures = "0.3"
glutin = { version = "0.31", optional = true, default-features = false }
@ -35,17 +35,15 @@ glutin-winit = { version = "0.4", optional = true, default-features = false }
image = { version = "0.24", optional = true, default-features = false, features = ["png", "jpeg"] }
memfd = { version = "0.6", optional = true }
memmap2 = { version = "0.9", optional = true }
pango = { workspace = true, optional = true }
pangocairo = { workspace = true, optional = true }
pango = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.18", version = "0.18", optional = true }
pangocairo = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.18", version = "0.18", optional = true }
raw-window-handle = { version = "0.5", optional = true }
uds = { version = "0.4", optional = true }
winit = { version = "0.29", optional = true, default-features = false, features = ["rwh_05"] }
atomic_refcell = "0.1"
data-encoding = "2.0"
once_cell = "1"
[target.'cfg(windows)'.dependencies]
windows = { version = "0.56", features=["Win32_Graphics_Direct3D11",
windows = { version = "0.52", features=["Win32_Graphics_Direct3D11",
"Win32_Foundation", "Win32_Graphics_Direct3D", "Win32_Graphics_Dxgi",
"Win32_Graphics_Dxgi_Common", "Win32_Graphics_Direct2D",
"Win32_Graphics_Direct2D_Common", "Win32_Graphics_DirectWrite",
@ -53,7 +51,6 @@ windows = { version = "0.56", features=["Win32_Graphics_Direct3D11",
[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.25"
objc = "0.2.7"
[build-dependencies]
gl_generator = { version = "0.14", optional = true }
@ -136,10 +133,6 @@ required-features = ["rtsp-server"]
name = "rtsp-server-subclass"
required-features = ["rtsp-server"]
[[bin]]
name = "rtsp-server-custom-auth"
required-features = ["rtsp-server", "gst-rtsp-server/v1_22"]
[[bin]]
name = "tagsetter"
@ -204,6 +197,3 @@ required-features = ["cairo-rs", "gst-video/v1_18"]
[[bin]]
name = "d3d11videosink"
required-features = ["windows"]
[[bin]]
name = "audio_multichannel_interleave"

View file

@ -13,7 +13,6 @@
use anyhow::Error;
use derive_more::{Display, Error};
use gst::prelude::*;
use gst_video::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;

View file

@ -1,153 +0,0 @@
// This example demonstrates how to mix multiple audio
// streams into a single output using the audiomixer element.
// In this case, we're mixing 4 stereo streams into a single 8 channel output.
use gst::prelude::*;
use std::env;
#[path = "../examples-common.rs"]
mod examples_common;
const TRACKS: i32 = 4;
fn create_source_and_link(pipeline: &gst::Pipeline, mixer: &gst::Element, track_number: i32) {
let freq = ((track_number + 1) * 1000) as f64;
let audiosrc = gst::ElementFactory::make("audiotestsrc")
.property("freq", freq)
.property("num-buffers", 2000)
.build()
.unwrap();
let caps = gst_audio::AudioCapsBuilder::new().channels(2).build();
let capsfilter = gst::ElementFactory::make("capsfilter")
.property("caps", &caps)
.build()
.unwrap();
pipeline.add_many([&audiosrc, &capsfilter]).unwrap();
gst::Element::link_many([&audiosrc, &capsfilter]).unwrap();
let src_pad = capsfilter.static_pad("src").unwrap();
let mixer_pad = mixer.request_pad_simple("sink_%u").unwrap();
// audiomixer expects a mix-matrix set on each input pad,
// indicating which output channels our input should appear in.
// Rows => input channels, columns => output channels.
// Here each input channel will appear in exactly one output channel.
let mut mix_matrix: Vec<Vec<f32>> = vec![];
for i in 0..TRACKS {
if i == track_number {
mix_matrix.push(vec![1.0, 0.0]);
mix_matrix.push(vec![0.0, 1.0]);
} else {
mix_matrix.push(vec![0.0, 0.0]);
mix_matrix.push(vec![0.0, 0.0]);
}
}
let mut audiomixer_config = gst_audio::AudioConverterConfig::new();
audiomixer_config.set_mix_matrix(&mix_matrix);
mixer_pad.set_property("converter-config", audiomixer_config);
src_pad.link(&mixer_pad).unwrap();
}
fn example_main() {
gst::init().unwrap();
let args: Vec<_> = env::args().collect();
let output_file = if args.len() == 2 {
&args[1]
} else {
println!("Usage: audiomixer <output file>");
std::process::exit(-1);
};
let pipeline = gst::Pipeline::new();
let audiomixer = gst::ElementFactory::make("audiomixer").build().unwrap();
// Using an arbitrary layout of 4 stereo pairs.
let positions = [
gst_audio::AudioChannelPosition::FrontLeft,
gst_audio::AudioChannelPosition::FrontRight,
gst_audio::AudioChannelPosition::RearLeft,
gst_audio::AudioChannelPosition::RearRight,
gst_audio::AudioChannelPosition::SideLeft,
gst_audio::AudioChannelPosition::SideRight,
gst_audio::AudioChannelPosition::TopFrontLeft,
gst_audio::AudioChannelPosition::TopFrontRight,
];
let mask = gst_audio::AudioChannelPosition::positions_to_mask(&positions, true).unwrap();
let caps = gst_audio::AudioCapsBuilder::new()
.channels(positions.len() as i32)
.channel_mask(mask)
.build();
let capsfilter = gst::ElementFactory::make("capsfilter")
.property("caps", &caps)
.build()
.unwrap();
let audioconvert = gst::ElementFactory::make("audioconvert").build().unwrap();
let audioresample = gst::ElementFactory::make("audioresample").build().unwrap();
let wavenc = gst::ElementFactory::make("wavenc").build().unwrap();
let sink = gst::ElementFactory::make("filesink")
.property("location", output_file)
.build()
.unwrap();
pipeline
.add_many([
&audiomixer,
&capsfilter,
&audioconvert,
&audioresample,
&wavenc,
&sink,
])
.unwrap();
gst::Element::link_many([
&audiomixer,
&capsfilter,
&audioconvert,
&audioresample,
&wavenc,
&sink,
])
.unwrap();
for i in 0..TRACKS {
create_source_and_link(&pipeline, &audiomixer, i);
}
let bus = pipeline.bus().expect("Pipeline without bus");
pipeline
.set_state(gst::State::Playing)
.expect("Unable to start pipeline");
for msg in bus.iter_timed(gst::ClockTime::NONE) {
use gst::MessageView;
match msg.view() {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
eprintln!(
"Error from {:?}: {} ({:?})",
msg.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
break;
}
_ => (),
}
}
pipeline
.set_state(gst::State::Null)
.expect("Unable to change pipeline state to NULL");
}
fn main() {
// tutorials_common::run is only required to set up the application environment on macOS
// (but not necessary in normal Cocoa applications where this is set up automatically)
examples_common::run(example_main);
}

View file

@ -10,6 +10,7 @@ mod examples_common;
// Our custom compositor element is defined in this module.
mod cairo_compositor {
use glib::once_cell::sync::Lazy;
use gst_base::subclass::prelude::*;
use gst_video::{prelude::*, subclass::prelude::*};
@ -56,16 +57,15 @@ mod cairo_compositor {
// In this case a single property for configuring the background color of the
// composition.
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: std::sync::OnceLock<Vec<glib::ParamSpec>> =
std::sync::OnceLock::new();
PROPERTIES.get_or_init(|| {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![glib::ParamSpecUInt::builder("background-color")
.nick("Background Color")
.blurb("Background color as 0xRRGGBB")
.default_value(Settings::default().background_color)
.build()]
})
});
&PROPERTIES
}
// Called by the application whenever the value of a property should be changed.
@ -100,24 +100,20 @@ mod cairo_compositor {
// gst-inspect-1.0 and can also be programmatically retrieved from the gst::Registry
// after initial registration without having to load the plugin in memory.
fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
static ELEMENT_METADATA: std::sync::OnceLock<gst::subclass::ElementMetadata> =
std::sync::OnceLock::new();
Some(ELEMENT_METADATA.get_or_init(|| {
static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
gst::subclass::ElementMetadata::new(
"Cairo Compositor",
"Compositor/Video",
"Cairo based compositor",
"Sebastian Dröge <sebastian@centricular.com>",
)
}))
});
Some(&*ELEMENT_METADATA)
}
fn pad_templates() -> &'static [gst::PadTemplate] {
static PAD_TEMPLATES: std::sync::OnceLock<Vec<gst::PadTemplate>> =
std::sync::OnceLock::new();
PAD_TEMPLATES.get_or_init(|| {
static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
// Create pad templates for our sink and source pad. These are later used for
// actually creating the pads and beforehand already provide information to
// GStreamer about all possible pads that could exist for this type.
@ -152,7 +148,9 @@ mod cairo_compositor {
)
.unwrap(),
]
})
});
PAD_TEMPLATES.as_ref()
}
// Notify via the child proxy interface whenever a new pad is added or removed.
@ -459,10 +457,7 @@ mod cairo_compositor {
// In this case there are various properties for defining the position and otherwise
// the appearance of the stream corresponding to this pad.
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: std::sync::OnceLock<Vec<glib::ParamSpec>> =
std::sync::OnceLock::new();
PROPERTIES.get_or_init(|| {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![
glib::ParamSpecDouble::builder("alpha")
.nick("Alpha")
@ -500,7 +495,9 @@ mod cairo_compositor {
.default_value(Settings::default().ypos)
.build(),
]
})
});
PROPERTIES.as_ref()
}
// Called by the application whenever the value of a property should be changed.

View file

@ -48,7 +48,7 @@ fn example_main() {
let main_loop = glib::MainLoop::new(None, false);
// This creates a pipeline by parsing the gst-launch pipeline syntax.
let pipeline = gst::parse::launch(
let pipeline = gst::parse_launch(
"audiotestsrc name=src ! queue max-size-time=2000000000 ! fakesink name=sink sync=true",
)
.unwrap();

View file

@ -71,6 +71,7 @@ mod custom_meta {
mod imp {
use std::{mem, ptr};
use glib::once_cell::sync::Lazy;
use glib::translate::*;
pub(super) struct CustomMetaParams {
@ -86,10 +87,8 @@ mod custom_meta {
// Function to register the meta API and get a type back.
pub(super) fn custom_meta_api_get_type() -> glib::Type {
static TYPE: std::sync::OnceLock<glib::Type> = std::sync::OnceLock::new();
*TYPE.get_or_init(|| unsafe {
let t = glib::Type::from_glib(gst::ffi::gst_meta_api_type_register(
static TYPE: Lazy<glib::Type> = Lazy::new(|| unsafe {
let t = from_glib(gst::ffi::gst_meta_api_type_register(
b"MyCustomMetaAPI\0".as_ptr() as *const _,
// We provide no tags here as our meta is just a label and does
// not refer to any specific aspect of the buffer.
@ -99,7 +98,9 @@ mod custom_meta {
assert_ne!(t, glib::Type::INVALID);
t
})
});
*TYPE
}
// Initialization function for our meta. This needs to ensure all fields are correctly
@ -156,24 +157,21 @@ mod custom_meta {
unsafe impl Send for MetaInfo {}
unsafe impl Sync for MetaInfo {}
static META_INFO: std::sync::OnceLock<MetaInfo> = std::sync::OnceLock::new();
static META_INFO: Lazy<MetaInfo> = Lazy::new(|| unsafe {
MetaInfo(
ptr::NonNull::new(gst::ffi::gst_meta_register(
custom_meta_api_get_type().into_glib(),
b"MyCustomMeta\0".as_ptr() as *const _,
mem::size_of::<CustomMeta>(),
Some(custom_meta_init),
Some(custom_meta_free),
Some(custom_meta_transform),
) as *mut gst::ffi::GstMetaInfo)
.expect("Failed to register meta API"),
)
});
META_INFO
.get_or_init(|| unsafe {
MetaInfo(
ptr::NonNull::new(gst::ffi::gst_meta_register(
custom_meta_api_get_type().into_glib(),
b"MyCustomMeta\0".as_ptr() as *const _,
mem::size_of::<CustomMeta>(),
Some(custom_meta_init),
Some(custom_meta_free),
Some(custom_meta_transform),
) as *mut gst::ffi::GstMetaInfo)
.expect("Failed to register meta API"),
)
})
.0
.as_ptr()
META_INFO.0.as_ptr()
}
}
}

View file

@ -194,7 +194,7 @@ fn main() -> Result<()> {
let mut metrics = DWRITE_TEXT_METRICS::default();
layout.GetMetrics(&mut metrics).unwrap();
layout
.GetFontSize(0, &mut font_size, Some(&mut range))
.GetFontSize2(0, &mut font_size, Some(&mut range))
.unwrap();
if metrics.widthIncludingTrailingWhitespace >= desc.Width as f32 {

View file

@ -19,15 +19,15 @@ fn example_main() {
/* Disable stdout debug, then configure the debug ringbuffer and enable
* all debug */
gst::log::remove_default_log_function();
gst::debug_remove_default_log_function();
/* Keep 1KB of logs per thread, removing old threads after 10 seconds */
gst::log::add_ring_buffer_logger(1024, 10);
gst::debug_add_ring_buffer_logger(1024, 10);
/* Enable all debug categories */
gst::log::set_default_threshold(gst::DebugLevel::Log);
gst::debug_set_default_threshold(gst::DebugLevel::Log);
let mut context = gst::ParseContext::new();
let pipeline =
match gst::parse::launch_full(pipeline_str, Some(&mut context), gst::ParseFlags::empty()) {
match gst::parse_launch_full(pipeline_str, Some(&mut context), gst::ParseFlags::empty()) {
Ok(pipeline) => pipeline,
Err(err) => {
if let Some(gst::ParseError::NoSuchElement) = err.kind::<gst::ParseError>() {
@ -73,7 +73,7 @@ fn example_main() {
gst::error!(gst::CAT_DEFAULT, "Hi from the debug log ringbuffer example");
println!("Dumping debug logs\n");
for s in gst::log::ring_buffer_logger_get_logs().iter() {
for s in gst::debug_ring_buffer_logger_get_logs().iter() {
println!("{s}\n------------------");
}
}

View file

@ -30,7 +30,7 @@ fn example_main() {
let main_loop = glib::MainLoop::new(None, false);
// This creates a pipeline by parsing the gst-launch pipeline syntax.
let pipeline = gst::parse::launch("audiotestsrc ! fakesink").unwrap();
let pipeline = gst::parse_launch("audiotestsrc ! fakesink").unwrap();
let bus = pipeline.bus().unwrap();
pipeline

View file

@ -361,11 +361,11 @@ mod video_filter {
use std::{mem::ManuallyDrop, os::unix::prelude::FromRawFd};
use anyhow::Error;
use glib::once_cell::sync::Lazy;
use gst::{subclass::prelude::*, PadDirection, PadPresence, PadTemplate};
use gst_app::gst_base::subclass::BaseTransformMode;
use gst_video::{prelude::*, subclass::prelude::*, VideoFrameRef};
use gst_video::{subclass::prelude::*, VideoFrameRef};
use memmap2::MmapMut;
use once_cell::sync::Lazy;
static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
gst::DebugCategory::new(
@ -430,10 +430,7 @@ mod video_filter {
impl ElementImpl for FdMemoryFadeInVideoFilter {
fn pad_templates() -> &'static [PadTemplate] {
static PAD_TEMPLATES: std::sync::OnceLock<Vec<PadTemplate>> =
std::sync::OnceLock::new();
PAD_TEMPLATES.get_or_init(|| {
static PAD_TEMPLATES: Lazy<Vec<PadTemplate>> = Lazy::new(|| {
let caps = gst_video::VideoCapsBuilder::new()
.format(gst_video::VideoFormat::Bgra)
.build();
@ -443,7 +440,9 @@ mod video_filter {
PadTemplate::new("src", PadDirection::Src, PadPresence::Always, &caps)
.unwrap(),
]
})
});
PAD_TEMPLATES.as_ref()
}
}

View file

@ -42,7 +42,7 @@ fn example_main() {
gst::init().unwrap();
// Create a pipeline from the launch-syntax given on the cli.
let pipeline = gst::parse::launch(&pipeline_str).unwrap();
let pipeline = gst::parse_launch(&pipeline_str).unwrap();
let bus = pipeline.bus().unwrap();
pipeline

View file

@ -32,13 +32,13 @@ void main () {
mod mirror {
use std::sync::Mutex;
use glib::once_cell::sync::Lazy;
use gst_base::subclass::BaseTransformMode;
use gst_gl::{
prelude::*,
subclass::{prelude::*, GLFilterMode},
*,
};
use once_cell::sync::Lazy;
use super::{gl, FRAGMENT_SHADER};

View file

@ -42,7 +42,7 @@ fn example_main() {
gst::init().unwrap();
// Create a pipeline from the launch-syntax given on the cli.
let pipeline = gst::parse::launch(&pipeline_str).unwrap();
let pipeline = gst::parse_launch(&pipeline_str).unwrap();
let bus = pipeline.bus().unwrap();
pipeline

View file

@ -26,22 +26,19 @@ fn example_main() {
// Especially GUIs should probably handle this case, to tell users that they need to
// install the corresponding gstreamer plugins.
let mut context = gst::ParseContext::new();
let pipeline = match gst::parse::launch_full(
&pipeline_str,
Some(&mut context),
gst::ParseFlags::empty(),
) {
Ok(pipeline) => pipeline,
Err(err) => {
if let Some(gst::ParseError::NoSuchElement) = err.kind::<gst::ParseError>() {
println!("Missing element(s): {:?}", context.missing_elements());
} else {
println!("Failed to parse pipeline: {err}");
}
let pipeline =
match gst::parse_launch_full(&pipeline_str, Some(&mut context), gst::ParseFlags::empty()) {
Ok(pipeline) => pipeline,
Err(err) => {
if let Some(gst::ParseError::NoSuchElement) = err.kind::<gst::ParseError>() {
println!("Missing element(s): {:?}", context.missing_elements());
} else {
println!("Failed to parse pipeline: {err}");
}
process::exit(-1)
}
};
process::exit(-1)
}
};
let bus = pipeline.bus().unwrap();
pipeline

View file

@ -24,7 +24,7 @@ fn example_main() {
let main_loop = glib::MainLoop::new(None, false);
// Let GStreamer create a pipeline from the parsed launch syntax on the cli.
let pipeline = gst::parse::launch(&pipeline_str).unwrap();
let pipeline = gst::parse_launch(&pipeline_str).unwrap();
let bus = pipeline.bus().unwrap();
pipeline

View file

@ -22,7 +22,7 @@ fn example_main() {
// Parse the pipeline we want to probe from a static in-line string.
// Here we give our audiotestsrc a name, so we can retrieve that element
// from the resulting pipeline.
let pipeline = gst::parse::launch(&format!(
let pipeline = gst::parse_launch(&format!(
"audiotestsrc name=src ! audio/x-raw,format={},channels=1 ! fakesink",
gst_audio::AUDIO_FORMAT_S16
))

View file

@ -36,14 +36,14 @@ fn example_main() {
// For flags handling
// With flags, one can configure playbin's behavior such as whether it
// should play back contained video streams, or if it should render subtitles.
// let flags = playbin.property_value("flags");
// let flags_class = FlagsClass::with_type(flags.type_()).unwrap();
// let flags = playbin.get_property("flags").unwrap();
// let flags_class = FlagsClass::new(flags.type_()).unwrap();
// let flags = flags_class.builder_with_value(flags).unwrap()
// .unset_by_nick("text")
// .unset_by_nick("video")
// .build()
// .unwrap();
// playbin.set_property_from_value("flags", &flags);
// playbin.set_property_from_value("flags", &flags).unwrap();
// The playbin also provides any kind of metadata that it found in the played stream.
// For this, the playbin provides signals notifying about changes in the metadata.

View file

@ -28,7 +28,7 @@ fn example_main() {
let main_loop = glib::MainLoop::new(None, false);
// Let GStreamer create a pipeline from the parsed launch syntax on the cli.
let pipeline = gst::parse::launch(&pipeline_str).unwrap();
let pipeline = gst::parse_launch(&pipeline_str).unwrap();
let bus = pipeline.bus().unwrap();
pipeline

View file

@ -252,7 +252,11 @@ fn example_main() -> Result<(), Error> {
if let Some(element) = msg.src() {
if element == &pipeline && s.current() == gst::State::Playing {
eprintln!("PLAYING");
pipeline.debug_to_dot_file(gst::DebugGraphDetails::all(), "client-playing");
gst::debug_bin_to_dot_file(
&pipeline,
gst::DebugGraphDetails::all(),
"client-playing",
);
}
}
}

View file

@ -179,7 +179,11 @@ fn example_main() -> Result<(), Error> {
if let Some(element) = msg.src() {
if element == &pipeline && s.current() == gst::State::Playing {
eprintln!("PLAYING");
pipeline.debug_to_dot_file(gst::DebugGraphDetails::all(), "server-playing");
gst::debug_bin_to_dot_file(
&pipeline,
gst::DebugGraphDetails::all(),
"server-playing",
);
}
}
}

View file

@ -1,223 +0,0 @@
// This example demonstrates how to set up a rtsp server using GStreamer
// and extending the default auth module behaviour by subclassing RTSPAuth
// For this, the example creates a videotestsrc pipeline manually to be used
// by the RTSP server for providing data
#![allow(clippy::non_send_fields_in_send_ty)]
use anyhow::Error;
use derive_more::{Display, Error};
use gst_rtsp_server::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Could not get mount points")]
struct NoMountPoints;
fn main_loop() -> Result<(), Error> {
let main_loop = glib::MainLoop::new(None, false);
let server = gst_rtsp_server::RTSPServer::new();
// We create our custom auth module.
// The job of the auth module is to authenticate users and authorize
// factories access/construction.
let auth = auth::Auth::default();
server.set_auth(Some(&auth));
// Much like HTTP servers, RTSP servers have multiple endpoints that
// provide different streams. Here, we ask our server to give
// us a reference to his list of endpoints, so we can add our
// test endpoint, providing the pipeline from the cli.
let mounts = server.mount_points().ok_or(NoMountPoints)?;
// Next, we create a factory for the endpoint we want to create.
// The job of the factory is to create a new pipeline for each client that
// connects, or (if configured to do so) to reuse an existing pipeline.
let factory = gst_rtsp_server::RTSPMediaFactory::new();
// Here we tell the media factory the media we want to serve.
// This is done in the launch syntax. When the first client connects,
// the factory will use this syntax to create a new pipeline instance.
factory.set_launch("( videotestsrc ! vp8enc ! rtpvp8pay name=pay0 )");
// This setting specifies whether each connecting client gets the output
// of a new instance of the pipeline, or whether all connected clients share
// the output of the same pipeline.
// If you want to stream a fixed video you have stored on the server to any
// client, you would not set this to shared here (since every client wants
// to start at the beginning of the video). But if you want to distribute
// a live source, you will probably want to set this to shared, to save
// computing and memory capacity on the server.
factory.set_shared(true);
// Now we add a new mount-point and tell the RTSP server to serve the content
// provided by the factory we configured above, when a client connects to
// this specific path.
mounts.add_factory("/test", factory);
// Attach the server to our main context.
// A main context is the thing where other stuff is registering itself for its
// events (e.g. sockets, GStreamer bus, ...) and the main loop is something that
// polls the main context for its events and dispatches them to whoever is
// interested in them. In this example, we only do have one, so we can
// leave the context parameter empty, it will automatically select
// the default one.
let id = server.attach(None)?;
println!(
"Stream ready at rtsp://127.0.0.1:{}/test",
server.bound_port()
);
println!("user admin/password can access stream");
println!("user demo/demo passes authentication but receives 404");
println!("other users do not pass pass authentication and receive 401");
// Start the mainloop. From this point on, the server will start to serve
// our quality content to connecting clients.
main_loop.run();
id.remove();
Ok(())
}
// Our custom auth module
mod auth {
// In the imp submodule we include the actual implementation
mod imp {
use gst_rtsp::{RTSPHeaderField, RTSPStatusCode};
use gst_rtsp_server::{prelude::*, subclass::prelude::*, RTSPContext};
// This is the private data of our auth
#[derive(Default)]
pub struct Auth;
impl Auth {
// Simulate external auth validation and user extraction
// authorized users are admin/password and demo/demo
fn external_auth(&self, auth: &str) -> Option<String> {
if let Ok(decoded) = data_encoding::BASE64.decode(auth.as_bytes()) {
if let Ok(decoded) = std::str::from_utf8(&decoded) {
let tokens = decoded.split(':').collect::<Vec<_>>();
if tokens == vec!["admin", "password"] || tokens == vec!["demo", "demo"] {
return Some(tokens[0].into());
}
}
}
None
}
// Simulate external role check
// admin user can construct and access media factory
fn external_access_check(&self, user: &str) -> bool {
user == "admin"
}
}
// This trait registers our type with the GObject object system and
// provides the entry points for creating a new instance and setting
// up the class data
#[glib::object_subclass]
impl ObjectSubclass for Auth {
const NAME: &'static str = "RsRTSPAuth";
type Type = super::Auth;
type ParentType = gst_rtsp_server::RTSPAuth;
}
// Implementation of glib::Object virtual methods
impl ObjectImpl for Auth {}
// Implementation of gst_rtsp_server::RTSPAuth virtual methods
impl RTSPAuthImpl for Auth {
fn authenticate(&self, ctx: &RTSPContext) -> bool {
// authenticate should always be called with a valid context request
let req = ctx
.request()
.expect("Context without request. Should not happen !");
if let Some(auth_credentials) = req.parse_auth_credentials().first() {
if let Some(authorization) = auth_credentials.authorization() {
if let Some(user) = self.external_auth(authorization) {
// Update context token with authenticated username
ctx.set_token(
gst_rtsp_server::RTSPToken::builder()
.field("user", user)
.build(),
);
return true;
}
}
}
false
}
fn check(&self, ctx: &RTSPContext, role: &glib::GString) -> bool {
// We only check media factory access
if !role.starts_with("auth.check.media.factory") {
return true;
}
if ctx.token().is_none() {
// If we do not have a context token yet, check if there are any auth credentials in request
if !self.authenticate(ctx) {
// If there were no credentials, send a "401 Unauthorized" response
if let Some(resp) = ctx.response() {
resp.init_response(RTSPStatusCode::Unauthorized, ctx.request());
resp.add_header(
RTSPHeaderField::WwwAuthenticate,
"Basic realm=\"CustomRealm\"",
);
if let Some(client) = ctx.client() {
client.send_message(resp, ctx.session());
}
}
return false;
}
}
if let Some(token) = ctx.token() {
// If we already have a user token...
if self.external_access_check(&token.string("user").unwrap_or_default()) {
// grant access if user may access factory
return true;
} else {
// send a "404 Not Found" response if user may not access factory
if let Some(resp) = ctx.response() {
resp.init_response(RTSPStatusCode::NotFound, ctx.request());
if let Some(client) = ctx.client() {
client.send_message(resp, ctx.session());
}
}
}
}
false
}
}
}
// This here defines the public interface of our auth and implements
// the corresponding traits so that it behaves like any other RTSPAuth
glib::wrapper! {
pub struct Auth(ObjectSubclass<imp::Auth>) @extends gst_rtsp_server::RTSPAuth;
}
impl Default for Auth {
// Creates a new instance of our auth
fn default() -> Self {
glib::Object::new()
}
}
}
fn example_main() -> Result<(), Error> {
gst::init()?;
main_loop()
}
fn main() {
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -4,10 +4,11 @@
// send to the server. For this, the launch syntax pipeline, that is passed
// to this example's cli is spawned and the client's media is streamed into it.
use std::env;
use std::{env, ptr};
use anyhow::Error;
use derive_more::{Display, Error};
use glib::translate::*;
use gst_rtsp_server::prelude::*;
#[path = "../examples-common.rs"]
@ -44,9 +45,10 @@ fn main_loop() -> Result<(), Error> {
// Here we configure a method of authentication that we want the
// server to require from clients.
let auth = gst_rtsp_server::RTSPAuth::new();
let token = gst_rtsp_server::RTSPToken::builder()
.field(gst_rtsp_server::RTSP_TOKEN_MEDIA_FACTORY_ROLE, "user")
.build();
let token = gst_rtsp_server::RTSPToken::new(&[(
gst_rtsp_server::RTSP_TOKEN_MEDIA_FACTORY_ROLE,
&"user",
)]);
let basic = gst_rtsp_server::RTSPAuth::make_basic("user", "password");
// For proper authentication, we want to use encryption. And there's no
// encryption without a certificate!
@ -76,14 +78,24 @@ fn main_loop() -> Result<(), Error> {
W535W8UBbEg=-----END PRIVATE KEY-----",
)?;
// Bindable versions were added in b1f515178a363df0322d7adbd5754e1f6e2083c9
// This declares that the user "user" (once authenticated) has a role that
// allows them to access and construct media factories.
factory.add_role_from_structure(
&gst::Structure::builder("user")
.field(gst_rtsp_server::RTSP_PERM_MEDIA_FACTORY_ACCESS, true)
.field(gst_rtsp_server::RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, true)
.build(),
);
unsafe {
gst_rtsp_server::ffi::gst_rtsp_media_factory_add_role(
factory.to_glib_none().0,
"user".to_glib_none().0,
gst_rtsp_server::RTSP_PERM_MEDIA_FACTORY_ACCESS
.to_glib_none()
.0,
<bool as StaticType>::static_type().into_glib() as *const u8,
true.into_glib() as *const u8,
gst_rtsp_server::RTSP_PERM_MEDIA_FACTORY_CONSTRUCT.as_ptr() as *const u8,
<bool as StaticType>::static_type().into_glib() as *const u8,
true.into_glib() as *const u8,
ptr::null_mut::<u8>(),
);
}
auth.set_tls_certificate(Some(&cert));
auth.add_basic(basic.as_str(), &token);

View file

@ -19,6 +19,10 @@ mod examples_common;
#[display(fmt = "Could not get mount points")]
struct NoMountPoints;
#[derive(Debug, Display, Error)]
#[display(fmt = "Usage: {_0} LAUNCH_LINE")]
struct UsageError(#[error(not(source))] String);
fn main_loop() -> Result<(), Error> {
let main_loop = glib::MainLoop::new(None, false);
let server = server::Server::default();

View file

@ -17,8 +17,8 @@ mod examples_common;
// Our custom FIR filter element is defined in this module
mod fir_filter {
use byte_slice_cast::*;
use glib::once_cell::sync::Lazy;
use gst_base::subclass::prelude::*;
use once_cell::sync::Lazy;
// The debug category we use below for our filter
pub static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
@ -63,24 +63,20 @@ mod fir_filter {
// gst-inspect-1.0 and can also be programmatically retrieved from the gst::Registry
// after initial registration without having to load the plugin in memory.
fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
static ELEMENT_METADATA: std::sync::OnceLock<gst::subclass::ElementMetadata> =
std::sync::OnceLock::new();
Some(ELEMENT_METADATA.get_or_init(|| {
static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
gst::subclass::ElementMetadata::new(
"FIR Filter",
"Filter/Effect/Audio",
"A FIR audio filter",
"Sebastian Dröge <sebastian@centricular.com>",
)
}))
});
Some(&*ELEMENT_METADATA)
}
fn pad_templates() -> &'static [gst::PadTemplate] {
static PAD_TEMPLATES: std::sync::OnceLock<Vec<gst::PadTemplate>> =
std::sync::OnceLock::new();
PAD_TEMPLATES.get_or_init(|| {
static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
// Create pad templates for our sink and source pad. These are later used for
// actually creating the pads and beforehand already provide information to
// GStreamer about all possible pads that could exist for this type.
@ -111,7 +107,9 @@ mod fir_filter {
)
.unwrap(),
]
})
});
PAD_TEMPLATES.as_ref()
}
}

View file

@ -2,9 +2,8 @@
use std::{collections::VecDeque, sync::Mutex};
use glib::prelude::*;
use glib::{once_cell::sync::Lazy, prelude::*};
use gst_audio::subclass::prelude::*;
use once_cell::sync::Lazy;
use byte_slice_cast::*;
@ -153,14 +152,15 @@ impl BaseTransformImpl for IirFilter {
impl AudioFilterImpl for IirFilter {
fn allowed_caps() -> &'static gst::Caps {
static CAPS: std::sync::OnceLock<gst::Caps> = std::sync::OnceLock::new();
CAPS.get_or_init(|| {
static CAPS: Lazy<gst::Caps> = Lazy::new(|| {
// On both of pads we can only handle F32 mono at any sample rate.
gst_audio::AudioCapsBuilder::new_interleaved()
.format(gst_audio::AUDIO_FORMAT_F32)
.channels(1)
.build()
})
});
&CAPS
}
fn setup(&self, info: &gst_audio::AudioInfo) -> Result<(), gst::LoggableError> {

View file

@ -51,7 +51,7 @@ impl<T: IirFilterImpl> IirFilterImplExt for T {}
/// Class struct for `IirFilter`.
#[repr(C)]
pub struct Class {
parent: <<imp::IirFilter as ObjectSubclass>::ParentType as ObjectType>::GlibClassType,
parent: <<imp::IirFilter as ObjectSubclass>::ParentType as glib::ObjectType>::GlibClassType,
set_rate: fn(&IirFilter, rate: u32),
}

View file

@ -2,7 +2,7 @@
use std::sync::Mutex;
use glib::prelude::*;
use glib::{once_cell::sync::Lazy, prelude::*};
use gst::prelude::*;
use gst_audio::subclass::prelude::*;
@ -45,9 +45,7 @@ impl ObjectSubclass for Lowpass {
// Implementation of glib::Object virtual methods
impl ObjectImpl for Lowpass {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: std::sync::OnceLock<Vec<glib::ParamSpec>> = std::sync::OnceLock::new();
PROPERTIES.get_or_init(|| {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![glib::ParamSpecFloat::builder("cutoff")
.nick("Cutoff")
.blurb("Cutoff frequency in Hz")
@ -55,7 +53,9 @@ impl ObjectImpl for Lowpass {
.minimum(0.0)
.mutable_playing()
.build()]
})
});
PROPERTIES.as_ref()
}
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
@ -84,16 +84,16 @@ impl ElementImpl for Lowpass {
// gst-inspect-1.0 and can also be programmatically retrieved from the gst::Registry
// after initial registration without having to load the plugin in memory.
fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
static ELEMENT_METADATA: std::sync::OnceLock<gst::subclass::ElementMetadata> =
std::sync::OnceLock::new();
Some(ELEMENT_METADATA.get_or_init(|| {
static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
gst::subclass::ElementMetadata::new(
"Lowpass Filter",
"Filter/Effect/Audio",
"A Lowpass audio filter",
"Sebastian Dröge <sebastian@centricular.com>",
)
}))
});
Some(&*ELEMENT_METADATA)
}
}

View file

@ -42,7 +42,7 @@ fn example_main() -> Result<(), Error> {
// Parse the pipeline we want to probe from a static in-line string.
let mut context = gst::ParseContext::new();
let pipeline = match gst::parse::launch_full(
let pipeline = match gst::parse_launch_full(
"audiotestsrc wave=white-noise num-buffers=100 ! flacenc ! filesink location=test.flac",
Some(&mut context),
gst::ParseFlags::empty(),

View file

@ -10,7 +10,6 @@
use anyhow::Error;
use derive_more::{Display, Error};
use gst::{element_error, prelude::*};
use gst_video::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -27,7 +26,7 @@ fn create_pipeline(uri: String, out_path: std::path::PathBuf) -> Result<gst::Pip
gst::init()?;
// Create our pipeline from a pipeline description string.
let pipeline = gst::parse::launch(&format!(
let pipeline = gst::parse_launch(&format!(
"uridecodebin uri={uri} ! videoconvert ! appsink name=sink"
))?
.downcast::<gst::Pipeline>()

View file

@ -11,7 +11,7 @@ fn example_main() {
gst::init().unwrap();
// This creates a pipeline by parsing the gst-launch pipeline syntax.
let pipeline = gst::parse::launch(
let pipeline = gst::parse_launch(
"videotestsrc name=src ! video/x-raw,width=640,height=480 ! compositor0.sink_0 \
compositor ! video/x-raw,width=1280,height=720 ! videoconvert ! autovideosink",
)

View file

@ -83,7 +83,7 @@ fn example_main() {
gst::init().unwrap();
let pipeline = gst::parse::launch(&format!(
let pipeline = gst::parse_launch(&format!(
"compositor name=mix background=1 sink_0::xpos=0 sink_0::ypos=0 sink_0::zorder=0 sink_0::width={WIDTH} sink_0::height={HEIGHT} ! xvimagesink \
videotestsrc name=src ! video/x-raw,framerate=30/1,width={WIDTH},height={HEIGHT},pixel-aspect-ratio=1/1 ! queue ! mix.sink_0"
)).unwrap().downcast::<gst::Pipeline>().unwrap();

View file

@ -17,47 +17,13 @@ pub fn run<T, F: FnOnce() -> T + Send + 'static>(main: F) -> T
where
T: Send + 'static,
{
use std::{
ffi::c_void,
sync::mpsc::{channel, Sender},
thread,
};
use std::thread;
use cocoa::{
appkit::{NSApplication, NSWindow},
base::id,
delegate,
};
use objc::{
class, msg_send,
runtime::{Object, Sel},
sel, sel_impl,
};
use cocoa::appkit::NSApplication;
unsafe {
let app = cocoa::appkit::NSApp();
let (send, recv) = channel::<()>();
extern "C" fn on_finish_launching(this: &Object, _cmd: Sel, _notification: id) {
let send = unsafe {
let send_pointer = *this.get_ivar::<*const c_void>("send");
let boxed = Box::from_raw(send_pointer as *mut Sender<()>);
*boxed
};
send.send(()).unwrap();
}
let delegate = delegate!("AppDelegate", {
app: id = app,
send: *const c_void = Box::into_raw(Box::new(send)) as *const c_void,
(applicationDidFinishLaunching:) => on_finish_launching as extern fn(&Object, Sel, id)
});
app.setDelegate_(delegate);
let t = thread::spawn(move || {
// Wait for the NSApp to launch to avoid possibly calling stop_() too early
recv.recv().unwrap();
let t = thread::spawn(|| {
let res = main();
let app = cocoa::appkit::NSApp();

View file

@ -691,7 +691,7 @@ pub(crate) fn main_loop(app: App) -> Result<()> {
..
} = app;
let mut curr_frame: Option<gst_gl::GLVideoFrame<gst_gl::gl_video_frame::Readable>> = None;
let mut curr_frame: Option<gst_video::VideoFrame<gst_video::video_frame::Readable>> = None;
let mut running_state = None::<(
Gl,
@ -740,7 +740,7 @@ pub(crate) fn main_loop(app: App) -> Result<()> {
},
// Receive a frame
winit::event::Event::UserEvent(Message::Frame(info, buffer)) => {
if let Ok(frame) = gst_gl::GLVideoFrame::from_buffer_readable(buffer, &info) {
if let Ok(frame) = gst_video::VideoFrame::from_buffer_readable_gl(buffer, &info) {
curr_frame = Some(frame);
needs_redraw = true;
}
@ -808,7 +808,7 @@ pub(crate) fn main_loop(app: App) -> Result<()> {
if let Some(frame) = curr_frame.as_ref() {
let sync_meta = frame.buffer().meta::<gst_gl::GLSyncMeta>().unwrap();
sync_meta.wait(&shared_context);
if let Ok(texture) = frame.texture_id(0) {
if let Some(texture) = frame.texture_id(0) {
gl.draw_frame(texture as gl::types::GLuint);
}
}

2
gir

@ -1 +1 @@
Subproject commit 5223ce91b97a833b09d6cbd04bbeab1bf18112b7
Subproject commit 23d7c100187cb4767ef77e0e4b3a511cbfadf035

@ -1 +1 @@
Subproject commit 6cd7b656acd61172ab7f125a7059e4d0ecfc9637
Subproject commit 6415239ef4354633334410cfae108e64ae7ff708

@ -1 +1 @@
Subproject commit c988e03b5e99349efb8ffb6f502879ad4ddbc248
Subproject commit 62054dc7234dfe1499245ce19ac9454dcb5dd594

View file

@ -1,24 +1,23 @@
[package]
name = "gstreamer-allocators"
version = "0.21.3"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
categories = ["api-bindings", "multimedia"]
description = "Rust bindings for GStreamer Allocators library"
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
license = "MIT OR Apache-2.0"
readme = "README.md"
homepage = "https://gstreamer.freedesktop.org"
documentation = "https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer_allocators/"
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
edition = "2021"
rust-version = "1.70"
[dependencies]
libc = "0.2"
ffi = { package = "gstreamer-allocators-sys", path = "sys" }
glib.workspace = true
gst.workspace = true
once_cell = "1"
ffi = { package = "gstreamer-allocators-sys", path = "sys", version = "0.21" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.18", version = "0.18" }
gst = { package = "gstreamer", path = "../gstreamer", version = "0.21" }
[dev-dependencies]
gir-format-check = "0.1"
@ -30,7 +29,6 @@ v1_18 = ["gst/v1_18", "ffi/v1_18", "v1_16"]
v1_20 = ["gst/v1_20", "ffi/v1_20", "v1_18"]
v1_22 = ["gst/v1_22", "ffi/v1_22", "v1_20"]
v1_24 = ["gst/v1_24", "ffi/v1_24", "v1_22"]
v1_26 = ["gst/v1_26", "ffi/v1_26", "v1_24"]
[package.metadata.docs.rs]
all-features = true

View file

@ -41,7 +41,7 @@ pub use self::shm_allocator::ShmAllocator;
mod flags;
pub use self::flags::FdMemoryFlags;
pub(crate) mod functions;
pub mod functions;
mod constants;
pub use self::constants::ALLOCATOR_DMABUF;
@ -51,6 +51,7 @@ pub use self::constants::ALLOCATOR_FD;
pub use self::constants::ALLOCATOR_SHM;
pub use self::constants::CAPS_FEATURE_MEMORY_DMABUF;
pub(crate) mod traits {
#[doc(hidden)]
pub mod traits {
pub use super::phys_memory_allocator::PhysMemoryAllocatorExt;
}

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 5223ce91b97a)
from gir-files (https://github.com/gtk-rs/gir-files @ 6cd7b656acd6)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ c988e03b5e99)
Generated by gir (https://github.com/gtk-rs/gir @ 23d7c100187c)
from gir-files (https://github.com/gtk-rs/gir-files @ 6415239ef435)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 62054dc7234d)

View file

@ -1,7 +1,7 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use glib::once_cell::sync::Lazy;
use gst::CapsFeatures;
use once_cell::sync::Lazy;
pub static CAPS_FEATURES_MEMORY_DMABUF: Lazy<CapsFeatures> =
Lazy::new(|| CapsFeatures::new([crate::CAPS_FEATURE_MEMORY_DMABUF]));

View file

@ -3,7 +3,7 @@ use std::{
os::unix::prelude::{IntoRawFd, RawFd},
};
use glib::{prelude::*, translate::*};
use glib::{translate::*, Cast};
use gst::{Memory, MemoryRef};
#[cfg(feature = "v1_16")]

View file

@ -1,6 +1,6 @@
use std::{fmt, mem, os::unix::prelude::IntoRawFd};
use glib::{prelude::*, translate::*};
use glib::{translate::*, Cast};
use gst::{Memory, MemoryRef};
use crate::{DRMDumbAllocator, DmaBufMemory};

View file

@ -1,6 +1,6 @@
use std::{fmt, os::unix::prelude::RawFd};
use glib::{prelude::*, translate::*};
use glib::{translate::*, Cast};
use gst::{Memory, MemoryRef};
use crate::{FdAllocator, FdMemoryFlags};

View file

@ -56,8 +56,6 @@ pub use phys_memory::*;
pub mod prelude {
#[doc(hidden)]
pub use gst::prelude::*;
pub use crate::auto::traits::*;
}
pub mod subclass;

View file

@ -4,14 +4,22 @@ system-deps = "6"
[dependencies]
libc = "0.2"
[dependencies.glib-sys]
workspace = true
[dependencies.glib]
git = "https://github.com/gtk-rs/gtk-rs-core"
package = "glib-sys"
branch = "0.18"
version = "0.18"
[dependencies.gobject-sys]
workspace = true
[dependencies.gobject]
git = "https://github.com/gtk-rs/gtk-rs-core"
package = "gobject-sys"
branch = "0.18"
version = "0.18"
[dependencies.gstreamer-sys]
workspace = true
[dependencies.gst]
package = "gstreamer-sys"
path = "../../gstreamer/sys"
version = "0.21"
[dev-dependencies]
shell-words = "1.0.0"
@ -23,7 +31,6 @@ v1_18 = ["v1_16"]
v1_20 = ["v1_18"]
v1_22 = ["v1_20"]
v1_24 = ["v1_22"]
v1_26 = ["v1_24"]
[lib]
name = "gstreamer_allocators_sys"
@ -33,28 +40,15 @@ authors = ["Sebastian Dröge <sebastian@centricular.com>"]
build = "build.rs"
description = "FFI bindings to libgstallocators-1.0"
documentation = "https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer_allocators_sys/"
edition = "2021"
homepage = "https://gstreamer.freedesktop.org"
keywords = ["ffi", "gstreamer", "gnome", "multimedia"]
license = "MIT"
name = "gstreamer-allocators-sys"
readme = "README.md"
[package.version]
workspace = true
[package.categories]
workspace = true
[package.repository]
workspace = true
[package.homepage]
workspace = true
[package.edition]
workspace = true
[package.rust-version]
workspace = true
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
rust-version = "1.70"
version = "0.21.3"
[package.metadata.docs.rs]
all-features = true
@ -78,7 +72,4 @@ version = "1.20"
version = "1.22"
[package.metadata.system-deps.gstreamer_allocators_1_0.v1_24]
version = "1.24"
[package.metadata.system-deps.gstreamer_allocators_1_0.v1_26]
version = "1.25"
version = "1.23"

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 5223ce91b97a)
from gir-files (https://github.com/gtk-rs/gir-files @ 6cd7b656acd6)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ c988e03b5e99)
Generated by gir (https://github.com/gtk-rs/gir @ 23d7c100187c)
from gir-files (https://github.com/gtk-rs/gir-files @ 6415239ef435)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 62054dc7234d)

View file

@ -12,18 +12,11 @@
)]
#![cfg_attr(docsrs, feature(doc_cfg))]
use glib_sys as glib;
use gobject_sys as gobject;
use gstreamer_sys as gst;
#[allow(unused_imports)]
use libc::{
c_char, c_double, c_float, c_int, c_long, c_short, c_uchar, c_uint, c_ulong, c_ushort, c_void,
intptr_t, off_t, size_t, ssize_t, time_t, uintptr_t, FILE,
intptr_t, size_t, ssize_t, uintptr_t, FILE,
};
#[cfg(unix)]
#[allow(unused_imports)]
use libc::{dev_t, gid_t, pid_t, socklen_t, uid_t};
#[allow(unused_imports)]
use glib::{gboolean, gconstpointer, gpointer, GType};

View file

@ -11,7 +11,7 @@ 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::process::Command;
use std::str;
use tempfile::Builder;
@ -71,11 +71,9 @@ fn pkg_config_cflags(packages: &[&str]) -> Result<Vec<String>, Box<dyn Error>> {
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());
return Err(format!("command {cmd:?} returned {}", out.status).into());
}
let stdout = str::from_utf8(&out.stdout)?;
Ok(shell_words::split(stdout.trim())?)
@ -190,15 +188,13 @@ fn get_c_output(name: &str) -> Result<String, Box<dyn Error>> {
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());
let mut abi_cmd = Command::new(exe);
let output = abi_cmd.output()?;
if !output.status.success() {
return Err(format!("command {abi_cmd:?} failed, {output:?}").into());
}
Ok(String::from_utf8(out.stdout)?)
Ok(String::from_utf8(output.stdout)?)
}
const RUST_LAYOUTS: &[(&str, Layout)] = &[

View file

@ -1 +0,0 @@
../gstreamer/CHANGELOG.md

View file

@ -1 +0,0 @@
../COPYRIGHT

View file

@ -1,32 +0,0 @@
[package]
name = "gstreamer-analytics"
authors = ["Olivier Crête <olivier.crete@collabora.com>"]
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 = []
v1_26 = ["gst/v1_26", "ffi/v1_26"]
[package.metadata.docs.rs]
all-features = true
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"]

View file

@ -1,34 +0,0 @@
[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"

View file

@ -1 +0,0 @@
../LICENSE-APACHE

View file

@ -1 +0,0 @@
../LICENSE-MIT

View file

@ -1,214 +0,0 @@
# 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)
<a name="installation"/>
## 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.
<a name="installation-linux"/>
### 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.
<a name="installation-macos"/>
### 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.
<a name="installation-windows"/>
### 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/).
<a name="getting-started"/>
## 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.
<a name="license"/>
## 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
<a name="contribution"/>
## 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.

View file

@ -1,44 +0,0 @@
// 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<ffi::GstAnalyticsRelTypes> for RelTypes {
#[inline]
unsafe fn from_glib(value: ffi::GstAnalyticsRelTypes) -> Self {
skip_assert_initialized!();
Self::from_bits_truncate(value)
}
}

View file

@ -1,7 +0,0 @@
// 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;

View file

@ -1,3 +0,0 @@
Generated by gir (https://github.com/gtk-rs/gir @ 5223ce91b97a)
from gir-files (https://github.com/gtk-rs/gir-files @ 6cd7b656acd6)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ c988e03b5e99)

View file

@ -1,212 +0,0 @@
// 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<T: super::AnalyticsRelationMetaClassificationExt> Sealed for T {}
}
pub trait AnalyticsRelationMetaClassificationExt: sealed::Sealed {
fn add_one_cls_mtd(
&mut self,
confidence_level: f32,
class_quark: glib::Quark,
) -> Result<AnalyticsMtdRef<AnalyticsClassificationMtd>, glib::BoolError>;
fn add_cls_mtd(
&mut self,
confidence_levels: &[f32],
class_quarks: &[glib::Quark],
) -> Result<AnalyticsMtdRef<AnalyticsClassificationMtd>, 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<AnalyticsMtdRef<'a, AnalyticsClassificationMtd>, 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<AnalyticsMtdRef<'a, AnalyticsClassificationMtd>, 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<Self::Item> {
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]);
}
}
}

View file

@ -1,36 +0,0 @@
// 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;
}

View file

@ -1,175 +0,0 @@
// 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<T: super::AnalyticsRelationMetaODExt> 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<AnalyticsMtdRef<AnalyticsODMtd>, 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<AnalyticsMtdRef<AnalyticsODMtd>, 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(Clone, Copy, Default, Debug)]
pub struct AnalyticsODLocation {
pub x: i32,
pub y: i32,
pub w: i32,
pub h: i32,
pub 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) -> Option<glib::Quark> {
unsafe {
let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self));
let type_ = ffi::gst_analytics_od_mtd_get_obj_type(&mut mtd);
if type_ == 0 {
None
} else {
Some(glib::Quark::from_glib(type_))
}
}
}
#[doc(alias = "gst_analytics_od_mtd_get_location")]
pub fn location(&self) -> Result<AnalyticsODLocation, glib::BoolError> {
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().unwrap(), 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::<AnalyticsRelationMeta>().unwrap();
assert!(meta.mtd::<AnalyticsODMtd>(1).is_none());
let meta2 = buf.meta::<AnalyticsRelationMeta>().unwrap();
let od2 = meta2.mtd::<AnalyticsODMtd>(0).unwrap();
assert_eq!(od2.obj_type().unwrap(), 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);
}
}

View file

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

View file

@ -1,158 +0,0 @@
// 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<T: super::AnalyticsRelationMetaTrackingExt> Sealed for T {}
}
pub trait AnalyticsRelationMetaTrackingExt: sealed::Sealed {
fn add_tracking_mtd(
&mut self,
tracking_id: u64,
tracking_first_seen: gst::ClockTime,
) -> Result<AnalyticsMtdRef<AnalyticsTrackingMtd>, 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<AnalyticsMtdRef<AnalyticsTrackingMtd>, 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::<AnalyticsTrackingMtd>(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);
}
}

View file

@ -1 +0,0 @@
../../gstreamer/CHANGELOG.md

View file

@ -1 +0,0 @@
../../COPYRIGHT

View file

@ -1,61 +0,0 @@
[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 <olivier.crete@collabora.com"]
build = "build.rs"
description = "FFI bindings to libgstanalytics-1.0"
documentation = "https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer_analytics_sys/"
keywords = ["ffi", "gstreamer", "gnome", "multimedia"]
license = "MIT"
name = "gstreamer-analytics-sys"
readme = "README.md"
[package.version]
workspace = true
[package.categories]
workspace = true
[package.repository]
workspace = true
[package.homepage]
workspace = true
[package.edition]
workspace = true
[package.rust-version]
workspace = true
[package.metadata.docs.rs]
all-features = true
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"]
[package.metadata.system-deps.gstreamer_analytics_1_0]
name = "gstreamer-analytics-1.0"
version = "1.24"
[package.metadata.system-deps.gstreamer_analytics_1_0.v1_26]
version = "1.25"
[features]
v1_26 = []

View file

@ -1,48 +0,0 @@
[options]
girs_directories = ["../../gir-files", "../../gst-gir-files"]
library = "GstAnalytics"
version = "1.0"
min_cfg_version = "1.24"
work_mode = "sys"
single_version_file = true
external_libraries = [
"GLib",
]
manual = [
"GObject.Object",
"Gst.Element",
"Gst.MiniObject",
"Gst.Object",
]
[external_libraries]
gstreamer="Gst"
[[object]]
name = "GstAnalytics.RelationMeta"
status = "generate"
[[object.function]]
name = "relation_meta_api_get_type"
version = "1.24"
[[object]]
name = "GstAnalytics.ClsMtd"
status = "generate"
boxed_inline = true
[[object]]
name = "GstAnalytics.TrackingMtd"
status = "generate"
boxed_inline = true
[[object]]
name = "GstAnalytics.ODMtd"
status = "generate"
boxed_inline = true
[[object]]
name = "GstAnalytics.Mtd"
status = "generate"
boxed_inline = true

View file

@ -1 +0,0 @@
../../LICENSE-MIT

View file

@ -1,31 +0,0 @@
# gstreamer-sys [![crates.io](https://img.shields.io/crates/v/gstreamer-app-sys.svg)](https://crates.io/crates/gstreamer-app-sys) [![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) FFI bindings for Rust.
These bindings are providing unsafe FFI API that can be used to interface with
GStreamer. Generally they are meant to be used as the building block for
higher-level abstractions like:
* Bindings for GStreamer applications and plugins: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs
* Various GStreamer plugins written in Rust: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs
The bindings are 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.
## LICENSE
gstreamer-sys and all crates contained here are licensed under the MIT
license ([LICENSE](LICENSE) or http://opensource.org/licenses/MIT).
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 shall be licensed under the MIT license as above,
without any additional terms or conditions.

View file

@ -1,18 +0,0 @@
// 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(not(docsrs))]
use std::process;
#[cfg(docsrs)]
fn main() {} // prevent linking libraries to avoid documentation failure
#[cfg(not(docsrs))]
fn main() {
if let Err(s) = system_deps::Config::new().probe() {
println!("cargo:warning={s}");
process::exit(1);
}
}

View file

@ -1,3 +0,0 @@
Generated by gir (https://github.com/gtk-rs/gir @ 5223ce91b97a)
from gir-files (https://github.com/gtk-rs/gir-files @ 6cd7b656acd6)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ c988e03b5e99)

View file

@ -1,338 +0,0 @@
// 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
#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)]
#![allow(
clippy::approx_constant,
clippy::type_complexity,
clippy::unreadable_literal,
clippy::upper_case_acronyms
)]
#![cfg_attr(docsrs, feature(doc_cfg))]
use glib_sys as glib;
use gstreamer_sys as gst;
#[allow(unused_imports)]
use libc::{
c_char, c_double, c_float, c_int, c_long, c_short, c_uchar, c_uint, c_ulong, c_ushort, c_void,
intptr_t, off_t, size_t, ssize_t, time_t, uintptr_t, FILE,
};
#[cfg(unix)]
#[allow(unused_imports)]
use libc::{dev_t, gid_t, pid_t, socklen_t, uid_t};
#[allow(unused_imports)]
use glib::{gboolean, gconstpointer, gpointer, GType};
// Aliases
pub type GstAnalyticsMtdType = uintptr_t;
// Constants
pub const GST_INF_RELATION_SPAN: c_int = -1;
pub const GST_ANALYTICS_MTD_TYPE_ANY: c_int = 0;
// Flags
pub type GstAnalyticsRelTypes = c_uint;
pub const GST_ANALYTICS_REL_TYPE_NONE: GstAnalyticsRelTypes = 0;
pub const GST_ANALYTICS_REL_TYPE_IS_PART_OF: GstAnalyticsRelTypes = 2;
pub const GST_ANALYTICS_REL_TYPE_CONTAIN: GstAnalyticsRelTypes = 4;
pub const GST_ANALYTICS_REL_TYPE_RELATE_TO: GstAnalyticsRelTypes = 8;
pub const GST_ANALYTICS_REL_TYPE_LAST: GstAnalyticsRelTypes = 16;
pub const GST_ANALYTICS_REL_TYPE_ANY: GstAnalyticsRelTypes = 2147483647;
// Records
#[derive(Copy, Clone)]
#[repr(C)]
pub struct GstAnalyticsClsMtd {
pub id: c_uint,
pub meta: *mut GstAnalyticsRelationMeta,
}
impl ::std::fmt::Debug for GstAnalyticsClsMtd {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::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)
.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;
}

View file

@ -1,272 +0,0 @@
// 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<String>,
}
impl Compiler {
pub fn new() -> Result<Self, Box<dyn Error>> {
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<dyn Error>> {
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<Vec<String>, Box<dyn Error>> {
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<Vec<String>, Box<dyn Error>> {
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<String, Box<dyn Error>> {
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::<GstAnalyticsClsMtd>(),
alignment: align_of::<GstAnalyticsClsMtd>(),
},
),
(
"GstAnalyticsMtd",
Layout {
size: size_of::<GstAnalyticsMtd>(),
alignment: align_of::<GstAnalyticsMtd>(),
},
),
(
"GstAnalyticsMtdImpl",
Layout {
size: size_of::<GstAnalyticsMtdImpl>(),
alignment: align_of::<GstAnalyticsMtdImpl>(),
},
),
(
"GstAnalyticsMtdType",
Layout {
size: size_of::<GstAnalyticsMtdType>(),
alignment: align_of::<GstAnalyticsMtdType>(),
},
),
(
"GstAnalyticsODMtd",
Layout {
size: size_of::<GstAnalyticsODMtd>(),
alignment: align_of::<GstAnalyticsODMtd>(),
},
),
(
"GstAnalyticsRelTypes",
Layout {
size: size_of::<GstAnalyticsRelTypes>(),
alignment: align_of::<GstAnalyticsRelTypes>(),
},
),
(
"GstAnalyticsRelationMetaInitParams",
Layout {
size: size_of::<GstAnalyticsRelationMetaInitParams>(),
alignment: align_of::<GstAnalyticsRelationMetaInitParams>(),
},
),
(
"GstAnalyticsTrackingMtd",
Layout {
size: size_of::<GstAnalyticsTrackingMtd>(),
alignment: align_of::<GstAnalyticsTrackingMtd>(),
},
),
];
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_INF_RELATION_SPAN", "-1"),
];

View file

@ -1,41 +0,0 @@
// 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 <stdio.h>
#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_INF_RELATION_SPAN);
return 0;
}

View file

@ -1,20 +0,0 @@
// 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 <stdalign.h>
#include <stdio.h>
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;
}

View file

@ -1,3 +0,0 @@
// Feel free to edit this file, it won't be regenerated by gir generator unless removed.
#include <gst/analytics/analytics.h>

View file

@ -1,26 +1,26 @@
[package]
name = "gstreamer-app"
version = "0.21.3"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
categories = ["api-bindings", "multimedia"]
description = "Rust bindings for GStreamer App library"
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
license = "MIT OR Apache-2.0"
readme = "README.md"
homepage = "https://gstreamer.freedesktop.org"
documentation = "https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer_app/"
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
edition = "2021"
rust-version = "1.70"
[dependencies]
futures-core = "0.3"
futures-sink = "0.3"
libc = "0.2"
ffi = { package = "gstreamer-app-sys", path = "sys" }
glib.workspace = true
gst.workspace = true
gst-base.workspace = true
ffi = { package = "gstreamer-app-sys", path = "sys", version = "0.21.1" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.18", version = "0.18" }
gst = { package = "gstreamer", path = "../gstreamer", version = "0.21" }
gst-base = { package = "gstreamer-base", path = "../gstreamer-base", version = "0.21" }
[dev-dependencies]
futures-util = { version = "0.3", features = ["sink"] }
@ -34,7 +34,6 @@ v1_18 = ["gst/v1_18", "gst-base/v1_18", "ffi/v1_18", "v1_16"]
v1_20 = ["gst/v1_20", "gst-base/v1_20", "ffi/v1_20", "v1_18"]
v1_22 = ["gst/v1_22", "gst-base/v1_22", "ffi/v1_22", "v1_20"]
v1_24 = ["gst/v1_24", "gst-base/v1_24", "ffi/v1_24", "v1_22"]
v1_26 = ["gst/v1_26", "gst-base/v1_26", "ffi/v1_26", "v1_24"]
[package.metadata.docs.rs]
all-features = true

View file

@ -4,13 +4,13 @@ use std::{
mem, panic,
pin::Pin,
ptr,
sync::{Arc, Mutex},
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
},
task::{Context, Poll, Waker},
};
#[cfg(not(panic = "abort"))]
use std::sync::atomic::{AtomicBool, Ordering};
use futures_core::Stream;
use glib::{ffi::gpointer, prelude::*, translate::*};
@ -28,7 +28,6 @@ pub struct AppSinkCallbacks {
new_event: Option<Box<dyn FnMut(&AppSink) -> bool + Send + 'static>>,
propose_allocation:
Option<Box<dyn FnMut(&AppSink, &mut gst::query::Allocation) -> bool + Send + 'static>>,
#[cfg(not(panic = "abort"))]
panicked: AtomicBool,
callbacks: ffi::GstAppSinkCallbacks,
}
@ -72,14 +71,6 @@ impl AppSinkCallbacksBuilder {
}
}
pub fn eos_if_some<F: FnMut(&AppSink) + Send + 'static>(self, eos: Option<F>) -> Self {
if let Some(eos) = eos {
self.eos(eos)
} else {
self
}
}
pub fn new_preroll<
F: FnMut(&AppSink) -> Result<gst::FlowSuccess, gst::FlowError> + Send + 'static,
>(
@ -92,19 +83,6 @@ impl AppSinkCallbacksBuilder {
}
}
pub fn new_preroll_if_some<
F: FnMut(&AppSink) -> Result<gst::FlowSuccess, gst::FlowError> + Send + 'static,
>(
self,
new_preroll: Option<F>,
) -> Self {
if let Some(new_preroll) = new_preroll {
self.new_preroll(new_preroll)
} else {
self
}
}
pub fn new_sample<
F: FnMut(&AppSink) -> Result<gst::FlowSuccess, gst::FlowError> + Send + 'static,
>(
@ -117,19 +95,6 @@ impl AppSinkCallbacksBuilder {
}
}
pub fn new_sample_if_some<
F: FnMut(&AppSink) -> Result<gst::FlowSuccess, gst::FlowError> + Send + 'static,
>(
self,
new_sample: Option<F>,
) -> Self {
if let Some(new_sample) = new_sample {
self.new_sample(new_sample)
} else {
self
}
}
#[cfg(feature = "v1_20")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
pub fn new_event<F: FnMut(&AppSink) -> bool + Send + 'static>(self, new_event: F) -> Self {
@ -139,19 +104,6 @@ impl AppSinkCallbacksBuilder {
}
}
#[cfg(feature = "v1_20")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
pub fn new_event_if_some<F: FnMut(&AppSink) -> bool + Send + 'static>(
self,
new_event: Option<F>,
) -> Self {
if let Some(new_event) = new_event {
self.new_event(new_event)
} else {
self
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn propose_allocation<
@ -166,21 +118,6 @@ impl AppSinkCallbacksBuilder {
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn propose_allocation_if_some<
F: FnMut(&AppSink, &mut gst::query::Allocation) -> bool + Send + 'static,
>(
self,
propose_allocation: Option<F>,
) -> Self {
if let Some(propose_allocation) = propose_allocation {
self.propose_allocation(propose_allocation)
} else {
self
}
}
#[must_use = "Building the callbacks without using them has no effect"]
pub fn build(self) -> AppSinkCallbacks {
let have_eos = self.eos.is_some();
@ -195,7 +132,6 @@ impl AppSinkCallbacksBuilder {
new_sample: self.new_sample,
new_event: self.new_event,
propose_allocation: self.propose_allocation,
#[cfg(not(panic = "abort"))]
panicked: AtomicBool::new(false),
callbacks: ffi::GstAppSinkCallbacks {
eos: if have_eos { Some(trampoline_eos) } else { None },
@ -229,7 +165,6 @@ unsafe extern "C" fn trampoline_eos(appsink: *mut ffi::GstAppSink, callbacks: gp
let callbacks = callbacks as *mut AppSinkCallbacks;
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
#[cfg(not(panic = "abort"))]
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
@ -241,19 +176,12 @@ unsafe extern "C" fn trampoline_eos(appsink: *mut ffi::GstAppSink, callbacks: gp
match result {
Ok(result) => result,
Err(err) => {
#[cfg(panic = "abort")]
{
unreachable!("{err:?}");
}
#[cfg(not(panic = "abort"))]
{
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
}
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
}
}
}
@ -266,7 +194,6 @@ unsafe extern "C" fn trampoline_new_preroll(
let callbacks = callbacks as *mut AppSinkCallbacks;
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
#[cfg(not(panic = "abort"))]
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
@ -278,21 +205,14 @@ unsafe extern "C" fn trampoline_new_preroll(
match result {
Ok(result) => result,
Err(err) => {
#[cfg(panic = "abort")]
{
unreachable!("{err:?}");
}
#[cfg(not(panic = "abort"))]
{
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
gst::FlowReturn::Error
}
gst::FlowReturn::Error
}
}
} else {
@ -309,7 +229,6 @@ unsafe extern "C" fn trampoline_new_sample(
let callbacks = callbacks as *mut AppSinkCallbacks;
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
#[cfg(not(panic = "abort"))]
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
@ -321,21 +240,14 @@ unsafe extern "C" fn trampoline_new_sample(
match result {
Ok(result) => result,
Err(err) => {
#[cfg(panic = "abort")]
{
unreachable!("{err:?}");
}
#[cfg(not(panic = "abort"))]
{
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
gst::FlowReturn::Error
}
gst::FlowReturn::Error
}
}
} else {
@ -352,7 +264,6 @@ unsafe extern "C" fn trampoline_new_event(
let callbacks = callbacks as *mut AppSinkCallbacks;
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
#[cfg(not(panic = "abort"))]
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
@ -364,21 +275,14 @@ unsafe extern "C" fn trampoline_new_event(
match result {
Ok(result) => result,
Err(err) => {
#[cfg(panic = "abort")]
{
unreachable!("{err:?}");
}
#[cfg(not(panic = "abort"))]
{
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
false
}
false
}
}
} else {
@ -396,7 +300,6 @@ unsafe extern "C" fn trampoline_propose_allocation(
let callbacks = callbacks as *mut AppSinkCallbacks;
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
#[cfg(not(panic = "abort"))]
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSink> = from_glib_borrow(appsink);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
@ -414,20 +317,14 @@ unsafe extern "C" fn trampoline_propose_allocation(
match result {
Ok(result) => result,
Err(err) => {
#[cfg(panic = "abort")]
{
unreachable!("{err:?}");
}
#[cfg(not(panic = "abort"))]
{
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
false
}
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
false
}
}
} else {
@ -453,23 +350,23 @@ impl AppSink {
#[doc(alias = "gst_app_sink_set_callbacks")]
pub fn set_callbacks(&self, callbacks: AppSinkCallbacks) {
#[cfg(not(feature = "v1_18"))]
use glib::once_cell::sync::Lazy;
#[cfg(not(feature = "v1_18"))]
static SET_ONCE_QUARK: Lazy<glib::Quark> =
Lazy::new(|| glib::Quark::from_str("gstreamer-rs-app-sink-callbacks"));
unsafe {
let sink = self.to_glib_none().0;
#[cfg(not(feature = "v1_18"))]
{
static SET_ONCE_QUARK: std::sync::OnceLock<glib::Quark> =
std::sync::OnceLock::new();
let set_once_quark = SET_ONCE_QUARK
.get_or_init(|| glib::Quark::from_str("gstreamer-rs-app-sink-callbacks"));
// This is not thread-safe before 1.16.3, see
// https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/merge_requests/570
if gst::version() < (1, 16, 3, 0) {
if !glib::gobject_ffi::g_object_get_qdata(
sink as *mut _,
set_once_quark.into_glib(),
SET_ONCE_QUARK.into_glib(),
)
.is_null()
{
@ -478,7 +375,7 @@ impl AppSink {
glib::gobject_ffi::g_object_set_qdata(
sink as *mut _,
set_once_quark.into_glib(),
SET_ONCE_QUARK.into_glib(),
1 as *mut _,
);
}

View file

@ -4,13 +4,13 @@ use std::{
mem, panic,
pin::Pin,
ptr,
sync::{Arc, Mutex},
sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
},
task::{Context, Poll, Waker},
};
#[cfg(not(panic = "abort"))]
use std::sync::atomic::{AtomicBool, Ordering};
use futures_sink::Sink;
use glib::{
ffi::{gboolean, gpointer},
@ -25,7 +25,6 @@ pub struct AppSrcCallbacks {
need_data: Option<Box<dyn FnMut(&AppSrc, u32) + Send + 'static>>,
enough_data: Option<Box<dyn Fn(&AppSrc) + Send + Sync + 'static>>,
seek_data: Option<Box<dyn Fn(&AppSrc, u64) -> bool + Send + Sync + 'static>>,
#[cfg(not(panic = "abort"))]
panicked: AtomicBool,
callbacks: ffi::GstAppSrcCallbacks,
}
@ -61,17 +60,6 @@ impl AppSrcCallbacksBuilder {
}
}
pub fn need_data_if_some<F: FnMut(&AppSrc, u32) + Send + 'static>(
self,
need_data: Option<F>,
) -> Self {
if let Some(need_data) = need_data {
self.need_data(need_data)
} else {
self
}
}
pub fn enough_data<F: Fn(&AppSrc) + Send + Sync + 'static>(self, enough_data: F) -> Self {
Self {
enough_data: Some(Box::new(enough_data)),
@ -79,17 +67,6 @@ impl AppSrcCallbacksBuilder {
}
}
pub fn enough_data_if_some<F: Fn(&AppSrc) + Send + Sync + 'static>(
self,
enough_data: Option<F>,
) -> Self {
if let Some(enough_data) = enough_data {
self.enough_data(enough_data)
} else {
self
}
}
pub fn seek_data<F: Fn(&AppSrc, u64) -> bool + Send + Sync + 'static>(
self,
seek_data: F,
@ -100,17 +77,6 @@ impl AppSrcCallbacksBuilder {
}
}
pub fn seek_data_if_some<F: Fn(&AppSrc, u64) -> bool + Send + Sync + 'static>(
self,
seek_data: Option<F>,
) -> Self {
if let Some(seek_data) = seek_data {
self.seek_data(seek_data)
} else {
self
}
}
#[must_use = "Building the callbacks without using them has no effect"]
pub fn build(self) -> AppSrcCallbacks {
let have_need_data = self.need_data.is_some();
@ -121,7 +87,6 @@ impl AppSrcCallbacksBuilder {
need_data: self.need_data,
enough_data: self.enough_data,
seek_data: self.seek_data,
#[cfg(not(panic = "abort"))]
panicked: AtomicBool::new(false),
callbacks: ffi::GstAppSrcCallbacks {
need_data: if have_need_data {
@ -158,7 +123,6 @@ unsafe extern "C" fn trampoline_need_data(
let callbacks = callbacks as *mut AppSrcCallbacks;
let element: Borrowed<AppSrc> = from_glib_borrow(appsrc);
#[cfg(not(panic = "abort"))]
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSrc> = from_glib_borrow(appsrc);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
@ -170,19 +134,12 @@ unsafe extern "C" fn trampoline_need_data(
match result {
Ok(result) => result,
Err(err) => {
#[cfg(panic = "abort")]
{
unreachable!("{err:?}");
}
#[cfg(not(panic = "abort"))]
{
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
}
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
}
}
}
@ -192,7 +149,6 @@ unsafe extern "C" fn trampoline_enough_data(appsrc: *mut ffi::GstAppSrc, callbac
let callbacks = callbacks as *const AppSrcCallbacks;
let element: Borrowed<AppSrc> = from_glib_borrow(appsrc);
#[cfg(not(panic = "abort"))]
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSrc> = from_glib_borrow(appsrc);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
@ -204,19 +160,12 @@ unsafe extern "C" fn trampoline_enough_data(appsrc: *mut ffi::GstAppSrc, callbac
match result {
Ok(result) => result,
Err(err) => {
#[cfg(panic = "abort")]
{
unreachable!("{err:?}");
}
#[cfg(not(panic = "abort"))]
{
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
}
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
}
}
}
@ -230,7 +179,6 @@ unsafe extern "C" fn trampoline_seek_data(
let callbacks = callbacks as *const AppSrcCallbacks;
let element: Borrowed<AppSrc> = from_glib_borrow(appsrc);
#[cfg(not(panic = "abort"))]
if (*callbacks).panicked.load(Ordering::Relaxed) {
let element: Borrowed<AppSrc> = from_glib_borrow(appsrc);
gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None);
@ -242,21 +190,14 @@ unsafe extern "C" fn trampoline_seek_data(
match result {
Ok(result) => result,
Err(err) => {
#[cfg(panic = "abort")]
{
unreachable!("{err:?}");
}
#[cfg(not(panic = "abort"))]
{
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
(*callbacks).panicked.store(true, Ordering::Relaxed);
gst::subclass::post_panic_error_message(
element.upcast_ref(),
element.upcast_ref(),
Some(err),
);
false
}
false
}
}
} else {
@ -282,22 +223,22 @@ impl AppSrc {
#[doc(alias = "gst_app_src_set_callbacks")]
pub fn set_callbacks(&self, callbacks: AppSrcCallbacks) {
#[cfg(not(feature = "v1_18"))]
use glib::once_cell::sync::Lazy;
#[cfg(not(feature = "v1_18"))]
static SET_ONCE_QUARK: Lazy<glib::Quark> =
Lazy::new(|| glib::Quark::from_str("gstreamer-rs-app-src-callbacks"));
unsafe {
let src = self.to_glib_none().0;
#[cfg(not(feature = "v1_18"))]
{
static SET_ONCE_QUARK: std::sync::OnceLock<glib::Quark> =
std::sync::OnceLock::new();
let set_once_quark = SET_ONCE_QUARK
.get_or_init(|| glib::Quark::from_str("gstreamer-rs-app-src-callbacks"));
// This is not thread-safe before 1.16.3, see
// https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/merge_requests/570
if gst::version() < (1, 16, 3, 0) {
if !glib::gobject_ffi::g_object_get_qdata(
src as *mut _,
set_once_quark.into_glib(),
SET_ONCE_QUARK.into_glib(),
)
.is_null()
{
@ -306,7 +247,7 @@ impl AppSrc {
glib::gobject_ffi::g_object_set_qdata(
src as *mut _,
set_once_quark.into_glib(),
SET_ONCE_QUARK.into_glib(),
1 as *mut _,
);
}

View file

@ -8,7 +8,7 @@ use glib::{
signal::{connect_raw, SignalHandlerId},
translate::*,
};
use std::boxed::Box as Box_;
use std::{boxed::Box as Box_, mem::transmute};
glib::wrapper! {
#[doc(alias = "GstAppSink")]
@ -233,7 +233,7 @@ impl AppSink {
connect_raw(
self.as_ptr() as *mut _,
b"notify::buffer-list\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_buffer_list_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -259,7 +259,7 @@ impl AppSink {
connect_raw(
self.as_ptr() as *mut _,
b"notify::caps\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_caps_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -285,7 +285,7 @@ impl AppSink {
connect_raw(
self.as_ptr() as *mut _,
b"notify::drop\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_drop_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -311,7 +311,7 @@ impl AppSink {
connect_raw(
self.as_ptr() as *mut _,
b"notify::eos\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_eos_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -339,7 +339,7 @@ impl AppSink {
connect_raw(
self.as_ptr() as *mut _,
b"notify::max-buffers\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_max_buffers_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -369,7 +369,7 @@ impl AppSink {
connect_raw(
self.as_ptr() as *mut _,
b"notify::max-bytes\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_max_bytes_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -397,7 +397,7 @@ impl AppSink {
connect_raw(
self.as_ptr() as *mut _,
b"notify::max-time\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_max_time_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -425,7 +425,7 @@ impl AppSink {
connect_raw(
self.as_ptr() as *mut _,
b"notify::wait-on-eos\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_wait_on_eos_trampoline::<F> as *const (),
)),
Box_::into_raw(f),

View file

@ -12,7 +12,7 @@ use glib::{
signal::{connect_raw, SignalHandlerId},
translate::*,
};
use std::boxed::Box as Box_;
use std::{boxed::Box as Box_, mem::transmute};
glib::wrapper! {
#[doc(alias = "GstAppSrc")]
@ -297,7 +297,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::block\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_block_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -323,7 +323,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::caps\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_caps_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -353,7 +353,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::current-level-buffers\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_current_level_buffers_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -381,7 +381,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::current-level-bytes\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_current_level_bytes_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -411,7 +411,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::current-level-time\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_current_level_time_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -437,7 +437,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::duration\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_duration_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -463,7 +463,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::format\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_format_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -493,7 +493,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::handle-segment-change\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_handle_segment_change_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -519,7 +519,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::is-live\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_is_live_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -549,7 +549,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::leaky-type\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_leaky_type_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -579,7 +579,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::max-buffers\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_max_buffers_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -605,7 +605,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::max-bytes\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_max_bytes_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -633,7 +633,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::max-latency\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_max_latency_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -661,7 +661,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::max-time\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_max_time_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -689,7 +689,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::min-latency\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_min_latency_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -717,7 +717,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::min-percent\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_min_percent_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -743,7 +743,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::size\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_size_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
@ -771,7 +771,7 @@ impl AppSrc {
connect_raw(
self.as_ptr() as *mut _,
b"notify::stream-type\0".as_ptr() as *const _,
Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
Some(transmute::<_, unsafe extern "C" fn()>(
notify_stream_type_trampoline::<F> as *const (),
)),
Box_::into_raw(f),

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 5223ce91b97a)
from gir-files (https://github.com/gtk-rs/gir-files @ 6cd7b656acd6)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ c988e03b5e99)
Generated by gir (https://github.com/gtk-rs/gir @ 23d7c100187c)
from gir-files (https://github.com/gtk-rs/gir-files @ 6415239ef435)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 62054dc7234d)

View file

@ -4,14 +4,21 @@ system-deps = "6"
[dependencies]
libc = "0.2"
[dependencies.glib-sys]
workspace = true
[dependencies.glib]
package = "glib-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gstreamer-sys]
workspace = true
[dependencies.gst_base]
package = "gstreamer-base-sys"
path = "../../gstreamer-base/sys"
version = "0.21"
[dependencies.gstreamer-base-sys]
workspace = true
[dependencies.gst]
package = "gstreamer-sys"
path = "../../gstreamer/sys"
version = "0.21"
[dev-dependencies]
shell-words = "1.0.0"
@ -23,7 +30,6 @@ v1_18 = ["v1_16"]
v1_20 = ["v1_18"]
v1_22 = ["v1_20"]
v1_24 = ["v1_22"]
v1_26 = ["v1_24"]
[lib]
name = "gstreamer_app_sys"
@ -33,28 +39,15 @@ authors = ["Sebastian Dröge <sebastian@centricular.com>"]
build = "build.rs"
description = "FFI bindings to libgstapp-1.0"
documentation = "https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer_app_sys/"
homepage = "https://gstreamer.freedesktop.org"
keywords = ["ffi", "gstreamer", "gnome", "multimedia"]
license = "MIT"
name = "gstreamer-app-sys"
readme = "README.md"
[package.version]
workspace = true
[package.categories]
workspace = true
[package.repository]
workspace = true
[package.homepage]
workspace = true
[package.edition]
workspace = true
[package.rust-version]
workspace = true
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
version = "0.21.3"
edition = "2021"
rust-version = "1.70"
[package.metadata.docs.rs]
all-features = true
@ -78,7 +71,4 @@ version = "1.20"
version = "1.22"
[package.metadata.system-deps.gstreamer_app_1_0.v1_24]
version = "1.24"
[package.metadata.system-deps.gstreamer_app_1_0.v1_26]
version = "1.25"
version = "1.23"

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 5223ce91b97a)
from gir-files (https://github.com/gtk-rs/gir-files @ 6cd7b656acd6)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ c988e03b5e99)
Generated by gir (https://github.com/gtk-rs/gir @ 23d7c100187c)
from gir-files (https://github.com/gtk-rs/gir-files @ 6415239ef435)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 62054dc7234d)

View file

@ -12,18 +12,11 @@
)]
#![cfg_attr(docsrs, feature(doc_cfg))]
use glib_sys as glib;
use gstreamer_base_sys as gst_base;
use gstreamer_sys as gst;
#[allow(unused_imports)]
use libc::{
c_char, c_double, c_float, c_int, c_long, c_short, c_uchar, c_uint, c_ulong, c_ushort, c_void,
intptr_t, off_t, size_t, ssize_t, time_t, uintptr_t, FILE,
intptr_t, size_t, ssize_t, uintptr_t, FILE,
};
#[cfg(unix)]
#[allow(unused_imports)]
use libc::{dev_t, gid_t, pid_t, socklen_t, uid_t};
#[allow(unused_imports)]
use glib::{gboolean, gconstpointer, gpointer, GType};
@ -104,7 +97,7 @@ pub struct _GstAppSinkPrivate {
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
pub type GstAppSinkPrivate = _GstAppSinkPrivate;
pub type GstAppSinkPrivate = *mut _GstAppSinkPrivate;
#[derive(Copy, Clone)]
#[repr(C)]
@ -163,7 +156,7 @@ pub struct _GstAppSrcPrivate {
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
pub type GstAppSrcPrivate = _GstAppSrcPrivate;
pub type GstAppSrcPrivate = *mut _GstAppSrcPrivate;
// Classes
#[derive(Copy, Clone)]

Some files were not shown because too many files have changed in this diff Show more