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
289 changed files with 8282 additions and 1277 deletions

View file

@ -49,15 +49,14 @@ variables:
WINDOWS_RUST_STABLE_IMAGE: "$CI_REGISTRY_IMAGE/windows:$GST_RS_IMG_TAG-main-$GST_RS_STABLE"
WINDOWS_RUST_STABLE_UPSTREAM_IMAGE: "$CI_REGISTRY/$FDO_UPSTREAM_REPO/windows:$GST_RS_IMG_TAG-main-$GST_RS_STABLE"
RUST_DOCS_FLAGS: "--extern-html-root-url=muldiv=https://docs.rs/muldiv/1.0.0/muldiv/ -Z unstable-options --generate-link-to-definition"
RUST_DOCS_FLAGS: "--cfg docsrs --extern-html-root-url=muldiv=https://docs.rs/muldiv/1.0.0/muldiv/ -Z unstable-options --generate-link-to-definition"
NAMESPACE: gstreamer
# format is <branch>=<name>
# the name is used in the URL
# latest release must be at the top
# (only relevant on main branch)
RELEASES:
0.20=0.20
0.19=0.19
0.21=0.21
stages:
- "trigger"
@ -96,13 +95,6 @@ trigger:
before_script:
- source ./ci/env.sh
- mkdir .cargo && echo -e "[net]\ngit-fetch-with-cli = true" > .cargo/config
# If cargo exists assume we probably will want to update
# the lockfile
- |
if command -v cargo; then
cargo generate-lockfile --color=always
cargo update --color=always
fi
.debian:12-base:
extends: .debian:12
@ -366,7 +358,7 @@ deny:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
script:
- cargo deny --color=always check
- cargo deny --color=always --workspace --all-features check all
gir-checks:
variables:

3066
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,5 @@
[workspace]
resolver = "2"
default-members = [
"gstreamer/sys",

View file

@ -1,4 +1,4 @@
variables:
GST_RS_IMG_TAG: "2023-08-07.0"
GST_RS_STABLE: "1.71.1"
GST_RS_IMG_TAG: "2023-11-16.0"
GST_RS_STABLE: "1.74.0"
GST_RS_MSRV: "1.70.0"

View file

@ -23,7 +23,7 @@ done
if [ -n "$EXAMPLES_TUTORIALS" ]; then
# Keep in sync with examples/Cargo.toml
# List all features except windows/win32
EXAMPLES_FEATURES="--features=rtsp-server,rtsp-server-record,pango-cairo,overlay-composition,gl,gst-gl-x11,gst-gl-wayland,gst-gl-egl,allocators,gst-play,gst-player,ges,image,cairo-rs,gst-video/v1_18"
EXAMPLES_FEATURES="--features=rtsp-server,rtsp-server-record,pango-cairo,overlay-composition,gl,gst-gl-x11,gst-gl-egl,allocators,gst-play,gst-player,ges,image,cairo-rs,gst-video/v1_18"
cargo build --locked --color=always --manifest-path examples/Cargo.toml --bins --examples "$EXAMPLES_FEATURES"
cargo build --locked --color=always --manifest-path tutorials/Cargo.toml --bins --examples --all-features

View file

@ -34,7 +34,7 @@ done
# Keep in sync with examples/Cargo.toml
# List all features except windows/win32
EXAMPLES_FEATURES="--features=rtsp-server,rtsp-server-record,pango-cairo,overlay-composition,gl,gst-gl-x11,gst-gl-wayland,gst-gl-egl,allocators,gst-play,gst-player,ges,image,cairo-rs,gst-video/v1_18"
EXAMPLES_FEATURES="--features=rtsp-server,rtsp-server-record,pango-cairo,overlay-composition,gl,gst-gl-x11,gst-gl-egl,allocators,gst-play,gst-player,ges,image,cairo-rs,gst-video/v1_18"
# And also run over all the examples/tutorials
cargo clippy --locked --color=always --manifest-path examples/Cargo.toml --all-targets "$EXAMPLES_FEATURES" -- $CLIPPY_LINTS

View file

@ -1,3 +1,8 @@
exclude = [
"examples",
"tutorials",
]
[advisories]
db-path = "~/.cargo/advisory-db"
db-urls = ["https://github.com/rustsec/advisory-db"]
@ -8,16 +13,7 @@ ignore = []
[licenses]
unlicensed = "deny"
allow = [
"Apache-2.0",
]
deny = [
"GPL-1.0",
"GPL-2.0",
"GPL-3.0",
"AGPL-1.0",
"AGPL-3.0",
]
default = "deny"
copyleft = "deny"
allow-osi-fsf-free = "either"
confidence-threshold = 0.8
@ -27,14 +23,6 @@ multiple-versions = "deny"
wildcards = "allow"
highlight = "all"
# Various cocoa crates are in the middle of updating to newer versions
[[bans.skip]]
name = "foreign-types"
version = "0.3"
[[bans.skip]]
name = "foreign-types-shared"
version = "0.1"
[sources]
unknown-registry = "deny"
unknown-git = "deny"
@ -47,7 +35,8 @@ allow-git = [
name = "syn"
version = "1.0"
# Various crates depend on an older version of bitflags
# proc-macro-crate depends on an older version of toml_edit
# https://github.com/bkchr/proc-macro-crate/pull/41
[[bans.skip]]
name = "bitflags"
version = "1.0"
name = "toml_edit"
version = "0.20"

View file

@ -1,46 +1,49 @@
[package]
name = "examples"
version = "0.21.0"
version = "0.21.3"
license = "MIT"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
edition = "2021"
rust-version = "1.70"
[dependencies]
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../gstreamer" }
gst-gl = { package = "gstreamer-gl", path = "../gstreamer-gl", optional = true }
gst-gl-egl = { package = "gstreamer-gl-egl", path = "../gstreamer-gl/egl", optional = true }
gst-gl-wayland = { package = "gstreamer-gl-wayland", path = "../gstreamer-gl/wayland", optional = true }
gst-gl-x11 = { package = "gstreamer-gl-x11", path = "../gstreamer-gl/x11", optional = true }
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-video = { package = "gstreamer-video", path = "../gstreamer-video" }
gst-pbutils = { package = "gstreamer-pbutils", path = "../gstreamer-pbutils" }
gst-play = { package = "gstreamer-play", path = "../gstreamer-play", optional = true }
gst-player = { package = "gstreamer-player", path = "../gstreamer-player", optional = true }
ges = { package = "gstreamer-editing-services", path = "../gstreamer-editing-services", optional = true }
gst-sdp = { package = "gstreamer-sdp", path = "../gstreamer-sdp", optional = true }
gst-rtsp = { package = "gstreamer-rtsp", path = "../gstreamer-rtsp", optional = true }
gst-rtsp-server = { package = "gstreamer-rtsp-server", path = "../gstreamer-rtsp-server", optional = true }
gst-allocators = { package = "gstreamer-allocators", path = "../gstreamer-allocators", optional = true }
gio = { git = "https://github.com/gtk-rs/gtk-rs-core", 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 = { 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"
byte-slice-cast = "1"
cairo-rs = { git = "https://github.com/gtk-rs/gtk-rs-core", features=["use_glib"], optional = true }
pango = { git = "https://github.com/gtk-rs/gtk-rs-core", optional = true }
pangocairo = { git = "https://github.com/gtk-rs/gtk-rs-core", optional = true }
glutin = { version = "0.29", optional = true }
glutin = { version = "0.31", optional = true, default-features = false }
glutin-winit = { version = "0.4", optional = true, default-features = false }
image = { version = "0.24", optional = true, default-features = false, features = ["png", "jpeg"] }
memmap2 = { version = "0.7", optional = true }
memfd = { version = "0.6", optional = true }
uds = { version = "0.2", optional = true }
memmap2 = { version = "0.9", 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"
[target.'cfg(windows)'.dependencies]
windows = { version = "0.48", 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",
@ -58,10 +61,9 @@ rtsp-server = ["gst-rtsp-server", "gst-rtsp", "gst-sdp"]
rtsp-server-record = ["gst-rtsp-server", "gst-rtsp", "gio"]
pango-cairo = ["pango", "pangocairo", "cairo-rs"]
overlay-composition = ["pango", "pangocairo", "cairo-rs"]
gl = ["gst-gl", "gl_generator", "glutin"]
gst-gl-x11 = ["dep:gst-gl-x11"]
gst-gl-egl = ["dep:gst-gl-egl"]
gst-gl-wayland = ["dep:gst-gl-wayland"]
gl = ["dep:gst-gl", "dep:gl_generator", "dep:glutin", "dep:glutin-winit", "dep:winit", "dep:raw-window-handle"]
gst-gl-x11 = ["dep:gst-gl-x11", "glutin-winit?/glx"] # glx turns on x11
gst-gl-egl = ["dep:gst-gl-egl", "glutin-winit?/egl", "glutin-winit?/x11", "glutin-winit?/wayland"] # Use X11 or Wayland via EGL
allocators = ["gst-allocators", "memmap2", "memfd", "uds"]
[[bin]]

View file

@ -75,31 +75,33 @@ fn example_main() {
// Add a pad probe on the sink pad and catch the custom event we sent, then send
// an EOS event on the pipeline.
sinkpad.add_probe(gst::PadProbeType::EVENT_DOWNSTREAM, move |_, probe_info| {
match probe_info.data {
Some(gst::PadProbeData::Event(ref ev))
if ev.type_() == gst::EventType::CustomDownstream =>
{
if let Some(custom_event) = ExampleCustomEvent::parse(ev) {
if let Some(pipeline) = pipeline_weak.upgrade() {
if custom_event.send_eos {
/* Send EOS event to shut down the pipeline, but from an async callback, as we're
* in a pad probe blocking the stream thread here... */
println!("Got custom event with send_eos=true. Sending EOS");
let ev = gst::event::Eos::new();
let pipeline_weak = pipeline_weak.clone();
pipeline.call_async(move |_| {
if let Some(pipeline) = pipeline_weak.upgrade() {
pipeline.send_event(ev);
}
});
} else {
println!("Got custom event, with send_eos=false. Ignoring");
}
}
let Some(event) = probe_info.event() else {
return gst::PadProbeReturn::Ok;
};
let Some(custom_event) = ExampleCustomEvent::parse(event) else {
return gst::PadProbeReturn::Ok;
};
let Some(pipeline) = pipeline_weak.upgrade() else {
return gst::PadProbeReturn::Ok;
};
if custom_event.send_eos {
/* Send EOS event to shut down the pipeline, but from an async callback, as we're
* in a pad probe blocking the stream thread here... */
println!("Got custom event with send_eos=true. Sending EOS");
let ev = gst::event::Eos::new();
let pipeline_weak = pipeline_weak.clone();
pipeline.call_async(move |_| {
if let Some(pipeline) = pipeline_weak.upgrade() {
pipeline.send_event(ev);
}
}
_ => (),
});
} else {
println!("Got custom event, with send_eos=false. Ignoring");
}
gst::PadProbeReturn::Ok
});
@ -113,9 +115,8 @@ fn example_main() {
glib::timeout_add_seconds(2 + i as u32, move || {
// Here we temporarily retrieve a strong reference on the pipeline from the weak one
// we moved into this callback.
let pipeline = match pipeline_weak.upgrade() {
Some(pipeline) => pipeline,
None => return glib::ControlFlow::Break,
let Some(pipeline) = pipeline_weak.upgrade() else {
return glib::ControlFlow::Break;
};
println!("Sending custom event to the pipeline with send_eos={send_eos}");
let ev = ExampleCustomEvent::new(*send_eos);

View file

@ -305,19 +305,18 @@ fn main() -> Result<()> {
let sinkpad = videosink.static_pad("sink").unwrap();
let overlay_context_weak = Arc::downgrade(&overlay_context);
sinkpad.add_probe(gst::PadProbeType::BUFFER, move |_, probe_info| {
if let Some(gst::PadProbeData::Buffer(_)) = probe_info.data {
let overlay_context = overlay_context_weak.upgrade().unwrap();
let mut context = overlay_context.lock().unwrap();
context.timestamp_queue.push_back(SystemTime::now());
// Updates framerate per 10 frames
if context.timestamp_queue.len() >= 10 {
let now = context.timestamp_queue.back().unwrap();
let front = context.timestamp_queue.front().unwrap();
let duration = now.duration_since(*front).unwrap().as_millis() as f32;
context.avg_fps = 1000f32 * (context.timestamp_queue.len() - 1) as f32 / duration;
context.timestamp_queue.clear();
}
let overlay_context = overlay_context_weak.upgrade().unwrap();
let mut context = overlay_context.lock().unwrap();
context.timestamp_queue.push_back(SystemTime::now());
// Updates framerate per 10 frames
if context.timestamp_queue.len() >= 10 {
let now = context.timestamp_queue.back().unwrap();
let front = context.timestamp_queue.front().unwrap();
let duration = now.duration_since(*front).unwrap().as_millis() as f32;
context.avg_fps = 1000f32 * (context.timestamp_queue.len() - 1) as f32 / duration;
context.timestamp_queue.clear();
}
gst::PadProbeReturn::Ok
});

View file

@ -90,9 +90,8 @@ fn example_main() -> Result<(), Error> {
decodebin.connect_pad_added(move |dbin, src_pad| {
// Here we temporarily retrieve a strong reference on the pipeline from the weak one
// we moved into this callback.
let pipeline = match pipeline_weak.upgrade() {
Some(pipeline) => pipeline,
None => return,
let Some(pipeline) = pipeline_weak.upgrade() else {
return;
};
// Try to detect whether the raw stream decodebin provided us with

View file

@ -120,9 +120,8 @@ fn example_main() -> Result<(), Error> {
src.connect_pad_added(move |dbin, dbin_src_pad| {
// Here we temporarily retrieve a strong reference on the pipeline from the weak one
// we moved into this callback.
let pipeline = match pipeline_weak.upgrade() {
Some(pipeline) => pipeline,
None => return,
let Some(pipeline) = pipeline_weak.upgrade() else {
return;
};
let (is_audio, is_video) = {

View file

@ -55,9 +55,8 @@ fn example_main() {
glib::timeout_add_seconds(5, move || {
// Here we temporarily retrieve a strong reference on the pipeline from the weak one
// we moved into this callback.
let pipeline = match pipeline_weak.upgrade() {
Some(pipeline) => pipeline,
None => return glib::ControlFlow::Break,
let Some(pipeline) = pipeline_weak.upgrade() else {
return glib::ControlFlow::Break;
};
println!("sending eos");

View file

@ -1,5 +1,7 @@
#![allow(clippy::non_send_fields_in_send_ty)]
use anyhow::Result;
#[path = "../glupload.rs"]
mod glupload;
use glupload::*;
@ -161,14 +163,12 @@ mod mirror {
}
}
fn example_main() {
fn example_main() -> Result<()> {
gst::init().unwrap();
let glfilter = mirror::GLMirrorFilter::new(Some("foo"));
App::new(Some(glfilter.as_ref()))
.and_then(main_loop)
.unwrap_or_else(|e| eprintln!("Error! {e}"))
let glfilter = mirror::GLMirrorFilter::new(Some("Mirror filter"));
App::new(Some(glfilter.as_ref())).and_then(main_loop)
}
fn main() {
examples_common::run(example_main);
fn main() -> Result<()> {
examples_common::run(example_main)
}

View file

@ -1,5 +1,7 @@
#![allow(clippy::non_send_fields_in_send_ty)]
use anyhow::Result;
#[path = "../glupload.rs"]
mod glupload;
use glupload::*;
@ -7,12 +9,10 @@ use glupload::*;
#[path = "../examples-common.rs"]
pub mod examples_common;
fn example_main() {
App::new(None)
.and_then(main_loop)
.unwrap_or_else(|e| eprintln!("Error! {e}"))
fn example_main() -> Result<()> {
App::new(None).and_then(main_loop)
}
fn main() {
examples_common::run(example_main);
fn main() -> Result<()> {
examples_common::run(example_main)
}

View file

@ -92,18 +92,18 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
DWriteCreateFactory::<IDWriteFactory>(DWRITE_FACTORY_TYPE_SHARED).unwrap();
let text_format = dwrite_factory
.CreateTextFormat(
windows::w!("Arial"),
windows::core::w!("Arial"),
None,
DWRITE_FONT_WEIGHT_BOLD,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
32f32,
windows::w!("en-us"),
windows::core::w!("en-us"),
)
.unwrap();
let text_layout = dwrite_factory
.CreateTextLayout(
windows::w!("GStreamer").as_wide(),
windows::core::w!("GStreamer").as_wide(),
&text_format,
// Size will be updated later on "caps-changed" signal
800f32,

View file

@ -38,36 +38,38 @@ fn example_main() {
// This handler gets called for every buffer that passes the pad we probe.
src_pad.add_probe(gst::PadProbeType::BUFFER, |_, probe_info| {
// Interpret the data sent over the pad as one buffer
if let Some(gst::PadProbeData::Buffer(ref buffer)) = probe_info.data {
// At this point, buffer is only a reference to an existing memory region somewhere.
// When we want to access its content, we have to map it while requesting the required
// mode of access (read, read/write).
// This type of abstraction is necessary, because the buffer in question might not be
// on the machine's main memory itself, but rather in the GPU's memory.
// So mapping the buffer makes the underlying memory region accessible to us.
// See: https://gstreamer.freedesktop.org/documentation/plugin-development/advanced/allocation.html
let map = buffer.map_readable().unwrap();
let Some(buffer) = probe_info.buffer() else {
return gst::PadProbeReturn::Ok;
};
// We know what format the data in the memory region has, since we requested
// it by setting the appsink's caps. So what we do here is interpret the
// memory region we mapped as an array of signed 16 bit integers.
let samples = if let Ok(samples) = map.as_slice_of::<i16>() {
samples
} else {
return gst::PadProbeReturn::Ok;
};
// At this point, buffer is only a reference to an existing memory region somewhere.
// When we want to access its content, we have to map it while requesting the required
// mode of access (read, read/write).
// This type of abstraction is necessary, because the buffer in question might not be
// on the machine's main memory itself, but rather in the GPU's memory.
// So mapping the buffer makes the underlying memory region accessible to us.
// See: https://gstreamer.freedesktop.org/documentation/plugin-development/advanced/allocation.html
let map = buffer.map_readable().unwrap();
// For buffer (= chunk of samples), we calculate the root mean square:
let sum: f64 = samples
.iter()
.map(|sample| {
let f = f64::from(*sample) / f64::from(i16::MAX);
f * f
})
.sum();
let rms = (sum / (samples.len() as f64)).sqrt();
println!("rms: {rms}");
}
// We know what format the data in the memory region has, since we requested
// it by setting the appsink's caps. So what we do here is interpret the
// memory region we mapped as an array of signed 16 bit integers.
let samples = if let Ok(samples) = map.as_slice_of::<i16>() {
samples
} else {
return gst::PadProbeReturn::Ok;
};
// For buffer (= chunk of samples), we calculate the root mean square:
let sum: f64 = samples
.iter()
.map(|sample| {
let f = f64::from(*sample) / f64::from(i16::MAX);
f * f
})
.sum();
let rms = (sum / (samples.len() as f64)).sqrt();
println!("rms: {rms}");
gst::PadProbeReturn::Ok
});

View file

@ -37,6 +37,11 @@ fn main_loop(uri: &str) -> Result<(), Error> {
Err(_) => unreachable!(),
}
}
// Set the message bus to flushing to ensure that all pending messages are dropped and there
// are no further references to the play instance.
play.message_bus().set_flushing(true);
result.map_err(|e| e.into())
}

View file

@ -50,9 +50,8 @@ fn example_main() {
let timeout_id = glib::timeout_add_seconds(1, move || {
// Here we temporarily retrieve a strong reference on the pipeline from the weak one
// we moved into this callback.
let pipeline = match pipeline_weak.upgrade() {
Some(pipeline) => pipeline,
None => return glib::ControlFlow::Continue,
let Some(pipeline) = pipeline_weak.upgrade() else {
return glib::ControlFlow::Break;
};
//let pos = pipeline.query_position(gst::Format::Time).unwrap_or(-1);

View file

@ -203,9 +203,8 @@ fn example_main() -> Result<(), Error> {
let depay_weak = depay.downgrade();
rtpbin.connect_pad_added(move |rtpbin, src_pad| {
let depay = match depay_weak.upgrade() {
Some(depay) => depay,
None => return,
let Some(depay) = depay_weak.upgrade() else {
return;
};
match connect_rtpbin_srcpad(src_pad, &depay) {

View file

@ -0,0 +1,188 @@
// In the imp submodule we include the actual implementation
use std::{collections::VecDeque, sync::Mutex};
use glib::{once_cell::sync::Lazy, prelude::*};
use gst_audio::subclass::prelude::*;
use byte_slice_cast::*;
use atomic_refcell::AtomicRefCell;
// The debug category we use below for our filter
pub static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
gst::DebugCategory::new(
"rsiirfilter",
gst::DebugColorFlags::empty(),
Some("Rust IIR Filter"),
)
});
#[derive(Default)]
// This is the state of our filter
struct State {
a: Vec<f64>,
b: Vec<f64>,
x: VecDeque<f64>,
y: VecDeque<f64>,
}
// This is the private data of our filter
#[derive(Default)]
pub struct IirFilter {
coeffs: Mutex<Option<(Vec<f64>, Vec<f64>)>>,
state: AtomicRefCell<State>,
}
// 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 IirFilter {
const NAME: &'static str = "RsIirFilter";
const ABSTRACT: bool = true;
type Type = super::IirFilter;
type ParentType = gst_audio::AudioFilter;
type Class = super::Class;
// Here we set default implementations for all the virtual methods.
// This is mandatory for all virtual methods that are not `Option`s.
fn class_init(class: &mut Self::Class) {
class.set_rate = |obj, rate| obj.imp().set_rate_default(rate);
}
}
// Implementation of glib::Object virtual methods
impl ObjectImpl for IirFilter {}
impl GstObjectImpl for IirFilter {}
// Implementation of gst::Element virtual methods
impl ElementImpl for IirFilter {}
// Implementation of gst_base::BaseTransform virtual methods
impl BaseTransformImpl for IirFilter {
// Configure basetransform so that we are always running in-place,
// don't passthrough on same caps and also never call transform_ip
// in passthrough mode (which does not matter for us here).
//
// The way how our processing is implemented, in-place transformation
// is simpler.
const MODE: gst_base::subclass::BaseTransformMode =
gst_base::subclass::BaseTransformMode::AlwaysInPlace;
const PASSTHROUGH_ON_SAME_CAPS: bool = false;
const TRANSFORM_IP_ON_PASSTHROUGH: bool = false;
fn start(&self) -> Result<(), gst::ErrorMessage> {
self.parent_start()?;
*self.state.borrow_mut() = State::default();
Ok(())
}
fn stop(&self) -> Result<(), gst::ErrorMessage> {
self.parent_stop()?;
*self.state.borrow_mut() = State::default();
Ok(())
}
fn transform_ip(&self, buf: &mut gst::BufferRef) -> Result<gst::FlowSuccess, gst::FlowError> {
let mut state = self.state.borrow_mut();
// Update coefficients if new coefficients were set
{
let mut coeffs = self.coeffs.lock().unwrap();
if let Some((a, b)) = coeffs.take() {
state.x.clear();
state.y.clear();
if !a.is_empty() {
state.y.resize(a.len() - 1, 0.0);
}
if !b.is_empty() {
state.x.resize(b.len() - 1, 0.0);
}
state.a = a;
state.b = b;
}
}
if state.a.is_empty() | state.b.is_empty() {
return Ok(gst::FlowSuccess::Ok);
}
let mut map = buf.map_writable().map_err(|_| {
gst::error!(CAT, imp: self, "Failed to map buffer writable");
gst::FlowError::Error
})?;
let samples = map.as_mut_slice_of::<f32>().unwrap();
assert!(state.b.len() - 1 == state.x.len());
assert!(state.a.len() - 1 == state.y.len());
for sample in samples.iter_mut() {
let mut val = state.b[0] * *sample as f64;
for (b, x) in Iterator::zip(state.b.iter().skip(1), state.x.iter()) {
val += b * x;
}
for (a, y) in Iterator::zip(state.a.iter().skip(1), state.y.iter()) {
val -= a * y;
}
val /= state.a[0];
let _ = state.x.pop_back().unwrap();
state.x.push_front(*sample as f64);
let _ = state.y.pop_back().unwrap();
state.y.push_front(val);
*sample = val as f32;
}
Ok(gst::FlowSuccess::Ok)
}
}
impl AudioFilterImpl for IirFilter {
fn allowed_caps() -> &'static gst::Caps {
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> {
self.parent_setup(info)?;
gst::debug!(CAT, imp: self, "Rate changed to {}", info.rate());
let obj = self.obj();
(obj.class().as_ref().set_rate)(&obj, info.rate());
Ok(())
}
}
/// Wrappers for public methods and associated helper functions.
impl IirFilter {
pub(super) fn set_coeffs(&self, a: Vec<f64>, b: Vec<f64>) {
gst::debug!(CAT, imp: self, "Setting coefficients a: {a:?}, b: {b:?}");
*self.coeffs.lock().unwrap() = Some((a, b));
}
}
/// Default virtual method implementations.
impl IirFilter {
fn set_rate_default(&self, _rate: u32) {}
}

View file

@ -0,0 +1,86 @@
use gst::{prelude::*, subclass::prelude::*};
use gst_audio::subclass::prelude::*;
mod imp;
// This here defines the public interface of our element and implements
// the corresponding traits so that it behaves like any other gst::Element
//
// GObject
// ╰──GstObject
// ╰──GstElement
// ╰──GstBaseTransform
// ╰──GstAudioFilter
// ╰──IirFilter
glib::wrapper! {
pub struct IirFilter(ObjectSubclass<imp::IirFilter>) @extends gst_audio::AudioFilter, gst_base::BaseTransform, gst::Element, gst::Object;
}
/// Trait containing extension methods for `IirFilter`.
pub trait IirFilterExt: IsA<IirFilter> {
// Sets the coefficients by getting access to the private struct and simply setting them
fn set_coeffs(&self, a: Vec<f64>, b: Vec<f64>) {
self.upcast_ref::<IirFilter>().imp().set_coeffs(a, b)
}
}
impl<O: IsA<IirFilter>> IirFilterExt for O {}
/// Trait to implement in `IirFilter` subclasses.
pub trait IirFilterImpl: AudioFilterImpl {
/// Called whenever the sample rate is changing.
fn set_rate(&self, rate: u32) {
self.parent_set_rate(rate);
}
}
/// Trait containing extension methods for `IirFilterImpl`, specifically methods for chaining
/// up to the parent implementation of virtual methods.
pub trait IirFilterImplExt: IirFilterImpl {
fn parent_set_rate(&self, rate: u32) {
unsafe {
let data = Self::type_data();
let parent_class = &*(data.as_ref().parent_class() as *mut Class);
(parent_class.set_rate)(self.obj().unsafe_cast_ref(), rate)
}
}
}
impl<T: IirFilterImpl> IirFilterImplExt for T {}
/// Class struct for `IirFilter`.
#[repr(C)]
pub struct Class {
parent: <<imp::IirFilter as ObjectSubclass>::ParentType as glib::ObjectType>::GlibClassType,
set_rate: fn(&IirFilter, rate: u32),
}
unsafe impl ClassStruct for Class {
type Type = imp::IirFilter;
}
/// This allows directly using `Class` as e.g. `gst_audio::AudioFilterClass` or
/// `gst_base::BaseTransformClass` without having to cast.
impl std::ops::Deref for Class {
type Target = glib::Class<<<Self as ClassStruct>::Type as ObjectSubclass>::ParentType>;
fn deref(&self) -> &Self::Target {
unsafe { &*(&self.parent as *const _ as *const _) }
}
}
/// Overrides the virtual methods with the actual implementation of the subclass as is provided by
/// the subclass' implementation of the `Impl` trait.
unsafe impl<T: IirFilterImpl> IsSubclassable<T> for IirFilter {
fn class_init(class: &mut glib::Class<Self>) {
Self::parent_class_init::<T>(class);
let class = class.as_mut();
class.set_rate = |obj, rate| unsafe {
let imp = obj.unsafe_cast_ref::<T::Type>().imp();
imp.set_rate(rate);
};
}
}

View file

@ -0,0 +1,170 @@
// In the imp submodule we include the actual implementation
use std::sync::Mutex;
use glib::{once_cell::sync::Lazy, prelude::*};
use gst::prelude::*;
use gst_audio::subclass::prelude::*;
use crate::iirfilter::{IirFilterExt, IirFilterImpl};
// These are the property values of our filter
pub struct Settings {
cutoff: f32,
}
impl Default for Settings {
fn default() -> Self {
Settings { cutoff: 0.0 }
}
}
// This is the state of our filter
#[derive(Default)]
pub struct State {
rate: Option<u32>,
}
// This is the private data of our filter
#[derive(Default)]
pub struct Lowpass {
settings: Mutex<Settings>,
state: Mutex<State>,
}
// 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 Lowpass {
const NAME: &'static str = "RsLowpass";
type Type = super::Lowpass;
type ParentType = crate::iirfilter::IirFilter;
}
// Implementation of glib::Object virtual methods
impl ObjectImpl for Lowpass {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![glib::ParamSpecFloat::builder("cutoff")
.nick("Cutoff")
.blurb("Cutoff frequency in Hz")
.default_value(Settings::default().cutoff)
.minimum(0.0)
.mutable_playing()
.build()]
});
PROPERTIES.as_ref()
}
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
match pspec.name() {
"cutoff" => {
self.settings.lock().unwrap().cutoff = value.get().unwrap();
self.calculate_coeffs();
}
_ => unimplemented!(),
};
}
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"cutoff" => self.settings.lock().unwrap().cutoff.to_value(),
_ => unimplemented!(),
}
}
}
impl GstObjectImpl for Lowpass {}
// Implementation of gst::Element virtual methods
impl ElementImpl for Lowpass {
// The element specific metadata. This information is what is visible from
// 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: 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)
}
}
// Implementation of gst_base::BaseTransform virtual methods
impl BaseTransformImpl for Lowpass {
const MODE: gst_base::subclass::BaseTransformMode =
<<crate::iirfilter::IirFilter as glib::object::ObjectSubclassIs>::Subclass>::MODE;
const PASSTHROUGH_ON_SAME_CAPS: bool =
<<crate::iirfilter::IirFilter as glib::object::ObjectSubclassIs>::Subclass>::PASSTHROUGH_ON_SAME_CAPS;
const TRANSFORM_IP_ON_PASSTHROUGH: bool =
<<crate::iirfilter::IirFilter as glib::object::ObjectSubclassIs>::Subclass>::TRANSFORM_IP_ON_PASSTHROUGH;
fn start(&self) -> Result<(), gst::ErrorMessage> {
self.parent_start()?;
*self.state.lock().unwrap() = State::default();
Ok(())
}
}
// Implement of gst_audio::AudioFilter virtual methods
impl AudioFilterImpl for Lowpass {}
// Implement of IirFilter virtual methods
impl IirFilterImpl for Lowpass {
fn set_rate(&self, rate: u32) {
// Could call
// self.parent_set_rate(rate);
// here but chaining up is not necessary if the base class doesn't require that
// or if the behaviour of the parent class should be completely overridden.
self.state.lock().unwrap().rate = Some(rate);
self.calculate_coeffs();
}
}
impl Lowpass {
fn calculate_coeffs(&self) {
use std::f64;
let Some(rate) = self.state.lock().unwrap().rate else {
return;
};
let cutoff = self.settings.lock().unwrap().cutoff;
// See Audio EQ Cookbook
// https://www.w3.org/TR/audio-eq-cookbook
let cutoff = cutoff as f64 / rate as f64;
let omega = 2.0 * f64::consts::PI * cutoff;
let q = 1.0;
let alpha = f64::sin(omega) / (2.0 * q);
let mut b = vec![
(1.0 - f64::cos(omega)) / 2.0,
1.0 - f64::cos(omega),
(1.0 - f64::cos(omega) / 2.0),
];
let mut a = vec![1.0 + alpha, -2.0 * f64::cos(omega), 1.0 - alpha];
let a0 = a[0];
for a in &mut a {
*a /= a0;
}
for b in &mut b {
*b /= a0;
}
self.obj().set_coeffs(a, b);
}
}

View file

@ -0,0 +1,15 @@
mod imp;
// This here defines the public interface of our element and implements
// the corresponding traits so that it behaves like any other gst::Element
//
// GObject
// ╰──GstObject
// ╰──GstElement
// ╰──GstBaseTransform
// ╰──GstAudioFilter
// ╰──IirFilter
// ╰──Lowpass
glib::wrapper! {
pub struct Lowpass(ObjectSubclass<imp::Lowpass>) @extends crate::iirfilter::IirFilter, gst_audio::AudioFilter, gst_base::BaseTransform, gst::Element, gst::Object;
}

View file

@ -0,0 +1,66 @@
// This example implements a baseclass IirFilter, and a subclass Lowpass of that.
//
// The example shows how to provide and implement virtual methods, and how to provide non-virtual
// methods on the base class.
use gst::prelude::*;
mod iirfilter;
mod lowpass;
#[path = "../../examples-common.rs"]
mod examples_common;
fn example_main() {
gst::init().unwrap();
let pipeline = gst::Pipeline::new();
let src = gst::ElementFactory::make("audiotestsrc")
.property_from_str("wave", "white-noise")
.build()
.unwrap();
let filter = glib::Object::builder::<lowpass::Lowpass>()
.property("cutoff", 4000.0f32)
.build();
let conv = gst::ElementFactory::make("audioconvert").build().unwrap();
let sink = gst::ElementFactory::make("autoaudiosink").build().unwrap();
pipeline
.add_many([&src, filter.as_ref(), &conv, &sink])
.unwrap();
gst::Element::link_many([&src, filter.as_ref(), &conv, &sink]).unwrap();
let bus = pipeline.bus().unwrap();
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
for msg in bus.iter_timed(gst::ClockTime::NONE) {
use gst::MessageView;
match msg.view() {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
break;
}
_ => (),
}
}
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
}
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

@ -52,9 +52,8 @@ fn example_main() {
decodebin.connect_pad_added(move |_, src_pad| {
// Here we temporarily retrieve a strong reference on the pipeline from the weak one
// we moved into this callback.
let pipeline = match pipeline_weak.upgrade() {
Some(pipeline) => pipeline,
None => return,
let Some(pipeline) = pipeline_weak.upgrade() else {
return;
};
// In this example, we are only interested about parsing the ToC, so

View file

@ -96,7 +96,7 @@ fn example_main() {
mixer_src_pad.add_probe(gst::PadProbeType::EVENT_UPSTREAM, move |_, probe_info| {
let mixer_sink_pad = mixer_sink_pad_weak.upgrade().unwrap();
let Some(gst::PadProbeData::Event(ref ev)) = probe_info.data else {
let Some(ev) = probe_info.event() else {
return gst::PadProbeReturn::Ok;
};

View file

@ -1,15 +1,30 @@
// This example demonstrates how to output GL textures, within an
// EGL/X11 context provided by the application, and render those
// textures in the GL application.
//! This example demonstrates how to output GL textures, within an EGL/X11 context provided by the
//! application, and render those textures in the GL application.
//!
//! This example follow common patterns from `glutin`:
//! <https://github.com/rust-windowing/glutin/blob/master/glutin_examples/src/lib.rs>
// {videotestsrc} - { glsinkbin }
use std::{ffi::CStr, mem, ptr, sync};
use std::{
ffi::{CStr, CString},
mem,
num::NonZeroU32,
ptr,
};
use anyhow::Error;
use anyhow::{Context, Result};
use derive_more::{Display, Error};
use glutin::{
config::GetGlConfig as _,
context::AsRawContext as _,
display::{AsRawDisplay as _, GetGlDisplay as _},
prelude::*,
};
use glutin_winit::GlWindow as _;
use gst::element_error;
use gst_gl::prelude::*;
use raw_window_handle::HasRawWindowHandle as _;
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
@ -171,7 +186,7 @@ impl Gl {
}
}
fn resize(&self, size: glutin::dpi::PhysicalSize<u32>) {
fn resize(&self, size: winit::dpi::PhysicalSize<u32>) {
unsafe {
self.gl
.Viewport(0, 0, size.width as i32, size.height as i32);
@ -179,14 +194,17 @@ impl Gl {
}
}
fn load(gl_context: &glutin::WindowedContext<glutin::PossiblyCurrent>) -> Gl {
let gl = gl::Gl::load_with(|ptr| gl_context.get_proc_address(ptr) as *const _);
fn load(gl_display: &impl glutin::display::GlDisplay) -> Gl {
let gl = gl::Gl::load_with(|symbol| {
let symbol = CString::new(symbol).unwrap();
gl_display.get_proc_address(&symbol).cast()
});
let version = unsafe {
let data = CStr::from_ptr(gl.GetString(gl::VERSION) as *const _)
.to_bytes()
.to_vec();
String::from_utf8(data).unwrap()
let version = gl.GetString(gl::VERSION);
assert!(!version.is_null());
let version = CStr::from_ptr(version.cast());
version.to_string_lossy()
};
println!("OpenGL version {version}");
@ -206,9 +224,10 @@ fn load(gl_context: &glutin::WindowedContext<glutin::PossiblyCurrent>) -> Gl {
gl.LinkProgram(program);
{
let mut success: gl::types::GLint = 1;
gl.GetProgramiv(fs, gl::LINK_STATUS, &mut success);
assert!(success != 0);
let mut success = 1;
gl.GetProgramiv(program, gl::LINK_STATUS, &mut success);
assert_ne!(success, 0);
assert_eq!(gl.GetError(), 0);
}
let attr_position = gl.GetAttribLocation(program, b"a_position\0".as_ptr() as *const _);
@ -279,6 +298,8 @@ fn load(gl_context: &glutin::WindowedContext<glutin::PossiblyCurrent>) -> Gl {
gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0);
gl.BindBuffer(gl::ARRAY_BUFFER, 0);
assert_eq!(gl.GetError(), 0);
(
program,
attr_position,
@ -310,154 +331,199 @@ pub(crate) struct App {
pipeline: gst::Pipeline,
appsink: gst_app::AppSink,
bus: gst::Bus,
event_loop: glutin::event_loop::EventLoop<Message>,
windowed_context: glutin::WindowedContext<glutin::PossiblyCurrent>,
event_loop: winit::event_loop::EventLoop<Message>,
window: Option<winit::window::Window>,
not_current_gl_context: Option<glutin::context::NotCurrentContext>,
shared_context: gst_gl::GLContext,
}
impl App {
pub(crate) fn new(gl_element: Option<&gst::Element>) -> Result<App, Error> {
pub(crate) fn new(gl_element: Option<&gst::Element>) -> Result<App> {
gst::init()?;
let (pipeline, appsink) = App::create_pipeline(gl_element)?;
let bus = pipeline
.bus()
.expect("Pipeline without bus. Shouldn't happen!");
.context("Pipeline without bus. Shouldn't happen!")?;
let event_loop = glutin::event_loop::EventLoopBuilder::with_user_event().build();
let window = glutin::window::WindowBuilder::new().with_title("GL rendering");
let windowed_context = glutin::ContextBuilder::new()
.with_vsync(true)
.build_windowed(window, &event_loop)?;
let event_loop = winit::event_loop::EventLoopBuilder::with_user_event().build()?;
let windowed_context = unsafe { windowed_context.make_current().map_err(|(_, err)| err)? };
// Only Windows requires the window to be present before creating a `glutin::Display`. Other
// platforms don't really need one (and on Android, none exists until `Event::Resumed`).
let window_builder = cfg!(windows).then(|| {
winit::window::WindowBuilder::new()
.with_transparent(true)
.with_title("GL rendering")
});
#[cfg(any(feature = "gst-gl-x11", feature = "gst-gl-wayland"))]
let inner_window = windowed_context.window();
let display_builder =
glutin_winit::DisplayBuilder::new().with_window_builder(window_builder);
// XXX on macOS/cgl only one config can be queried at a time. If transparency is needed,
// add .with_transparency(true) to ConfigTemplateBuilder. EGL on X11 doesn't support
// transparency at all.
let template = glutin::config::ConfigTemplateBuilder::new().with_alpha_size(8);
let (window, gl_config) = display_builder
.build(&event_loop, template, |configs| {
configs
.reduce(|current, new_config| {
let prefer_transparency =
new_config.supports_transparency().unwrap_or(false)
& !current.supports_transparency().unwrap_or(false);
let shared_context: gst_gl::GLContext;
if cfg!(target_os = "linux") {
#[cfg(any(feature = "gst-gl-x11", feature = "gst-gl-wayland"))]
use glutin::platform::unix::WindowExtUnix;
use glutin::platform::{unix::RawHandle, ContextTraitExt};
let api = App::map_gl_api(windowed_context.get_api());
let (gl_context, gl_display, platform) = match unsafe { windowed_context.raw_handle() }
{
#[cfg(any(feature = "gst-gl-egl", feature = "gst-gl-wayland"))]
RawHandle::Egl(egl_context) => {
let mut gl_display = None;
#[cfg(feature = "gst-gl-egl")]
if let Some(display) = unsafe { windowed_context.get_egl_display() } {
gl_display = Some(
unsafe { gst_gl_egl::GLDisplayEGL::with_egl_display(display as usize) }
.unwrap()
.upcast::<gst_gl::GLDisplay>(),
)
};
#[cfg(feature = "gst-gl-wayland")]
if let Some(display) = inner_window.wayland_display() {
gl_display = Some(
unsafe {
gst_gl_wayland::GLDisplayWayland::with_display(display as usize)
}
.unwrap()
.upcast::<gst_gl::GLDisplay>(),
)
};
(
egl_context as usize,
gl_display.expect("Could not retrieve GLDisplay through EGL context and/or Wayland display"),
gst_gl::GLPlatform::EGL,
)
}
#[cfg(feature = "gst-gl-x11")]
RawHandle::Glx(glx_context) => {
let gl_display = if let Some(display) = inner_window.xlib_display() {
unsafe { gst_gl_x11::GLDisplayX11::with_display(display as usize) }.unwrap()
} else {
panic!("X11 window without X Display");
};
(
glx_context as usize,
gl_display.upcast::<gst_gl::GLDisplay>(),
gst_gl::GLPlatform::GLX,
)
}
#[allow(unreachable_patterns)]
handler => panic!("Unsupported platform: {handler:?}."),
};
shared_context =
unsafe { gst_gl::GLContext::new_wrapped(&gl_display, gl_context, platform, api) }
.unwrap();
shared_context
.activate(true)
.expect("Couldn't activate wrapped GL context");
shared_context.fill_info()?;
let gl_context = shared_context.clone();
let event_proxy = sync::Mutex::new(event_loop.create_proxy());
#[allow(clippy::single_match)]
bus.set_sync_handler(move |_, msg| {
match msg.view() {
gst::MessageView::NeedContext(ctxt) => {
let context_type = ctxt.context_type();
if context_type == *gst_gl::GL_DISPLAY_CONTEXT_TYPE {
if let Some(el) =
msg.src().map(|s| s.downcast_ref::<gst::Element>().unwrap())
{
let context = gst::Context::new(context_type, true);
context.set_gl_display(&gl_display);
el.set_context(&context);
}
if prefer_transparency || new_config.num_samples() > current.num_samples() {
new_config
} else {
current
}
if context_type == "gst.gl.app_context" {
if let Some(el) =
msg.src().map(|s| s.downcast_ref::<gst::Element>().unwrap())
{
let mut context = gst::Context::new(context_type, true);
{
let context = context.get_mut().unwrap();
let s = context.structure_mut();
s.set("context", &gl_context);
}
el.set_context(&context);
}
})
.unwrap()
})
.expect("Failed to build display");
println!(
"Picked a config with {} samples and transparency {}. Pixel format: {:?}",
gl_config.num_samples(),
gl_config.supports_transparency().unwrap_or(false),
gl_config.color_buffer_type()
);
println!("Config supports GL API(s) {:?}", gl_config.api());
// XXX The display could be obtained from any object created by it, so we can query it from
// the config.
let gl_display = gl_config.display();
let raw_gl_display = gl_display.raw_display();
println!("Using raw display connection {:?}", raw_gl_display);
let raw_window_handle = window.as_ref().map(|window| window.raw_window_handle());
// The context creation part. It can be created before surface and that's how
// it's expected in multithreaded + multiwindow operation mode, since you
// can send NotCurrentContext, but not Surface.
let context_attributes =
glutin::context::ContextAttributesBuilder::new().build(raw_window_handle);
// Since glutin by default tries to create OpenGL core context, which may not be
// present we should try gles.
let fallback_context_attributes = glutin::context::ContextAttributesBuilder::new()
.with_context_api(glutin::context::ContextApi::Gles(None))
.build(raw_window_handle);
// There are also some old devices that support neither modern OpenGL nor GLES.
// To support these we can try and create a 2.1 context.
let legacy_context_attributes = glutin::context::ContextAttributesBuilder::new()
.with_context_api(glutin::context::ContextApi::OpenGl(Some(
glutin::context::Version::new(2, 1),
)))
.build(raw_window_handle);
let not_current_gl_context = unsafe {
gl_display
.create_context(&gl_config, &context_attributes)
.or_else(|_| {
gl_display
.create_context(&gl_config, &fallback_context_attributes)
.or_else(|_| {
gl_display.create_context(&gl_config, &legacy_context_attributes)
})
})
}
.context("failed to create context")?;
let raw_gl_context = not_current_gl_context.raw_context();
println!("Using raw GL context {:?}", raw_gl_context);
#[cfg(not(target_os = "linux"))]
compile_error!("This example only has Linux support");
let api = App::map_gl_api(gl_config.api());
let (raw_gl_context, gst_gl_display, platform) = match (raw_gl_display, raw_gl_context) {
#[cfg(feature = "gst-gl-egl")]
(
glutin::display::RawDisplay::Egl(egl_display),
glutin::context::RawContext::Egl(egl_context),
) => {
let gl_display =
unsafe { gst_gl_egl::GLDisplayEGL::with_egl_display(egl_display as usize) }
.context("Failed to create GLDisplayEGL from raw `EGLDisplay`")?
.upcast::<gst_gl::GLDisplay>();
(egl_context as usize, gl_display, gst_gl::GLPlatform::EGL)
}
#[cfg(feature = "gst-gl-x11")]
(
glutin::display::RawDisplay::Glx(glx_display),
glutin::context::RawContext::Glx(glx_context),
) => {
let gl_display =
unsafe { gst_gl_x11::GLDisplayX11::with_display(glx_display as usize) }
.context("Failed to create GLDisplayX11 from raw X11 `Display`")?
.upcast::<gst_gl::GLDisplay>();
(glx_context as usize, gl_display, gst_gl::GLPlatform::GLX)
}
#[allow(unreachable_patterns)]
handler => anyhow::bail!("Unsupported platform: {handler:?}."),
};
let shared_context = unsafe {
gst_gl::GLContext::new_wrapped(&gst_gl_display, raw_gl_context, platform, api)
}
.context("Couldn't wrap GL context")?;
let gl_context = shared_context.clone();
let event_proxy = event_loop.create_proxy();
#[allow(clippy::single_match)]
bus.set_sync_handler(move |_, msg| {
match msg.view() {
gst::MessageView::NeedContext(ctxt) => {
let context_type = ctxt.context_type();
if context_type == *gst_gl::GL_DISPLAY_CONTEXT_TYPE {
if let Some(el) =
msg.src().map(|s| s.downcast_ref::<gst::Element>().unwrap())
{
let context = gst::Context::new(context_type, true);
context.set_gl_display(&gst_gl_display);
el.set_context(&context);
}
}
if context_type == "gst.gl.app_context" {
if let Some(el) =
msg.src().map(|s| s.downcast_ref::<gst::Element>().unwrap())
{
let mut context = gst::Context::new(context_type, true);
{
let context = context.get_mut().unwrap();
let s = context.structure_mut();
s.set("context", &gl_context);
}
el.set_context(&context);
}
}
_ => (),
}
_ => (),
}
if let Err(e) = event_proxy.lock().unwrap().send_event(Message::BusEvent) {
eprintln!("Failed to send BusEvent to event proxy: {e}")
}
if let Err(e) = event_proxy.send_event(Message::BusEvent) {
eprintln!("Failed to send BusEvent to event proxy: {e}")
}
gst::BusSyncReply::Pass
});
} else {
panic!("This example only has Linux support");
}
gst::BusSyncReply::Pass
});
Ok(App {
pipeline,
appsink,
bus,
event_loop,
windowed_context,
window,
not_current_gl_context: Some(not_current_gl_context),
shared_context,
})
}
fn setup(&self, event_loop: &glutin::event_loop::EventLoop<Message>) -> Result<(), Error> {
fn setup(&self, event_loop: &winit::event_loop::EventLoop<Message>) -> Result<()> {
let event_proxy = event_loop.create_proxy();
self.appsink.set_callbacks(
gst_app::AppSinkCallbacks::builder()
@ -521,22 +587,33 @@ impl App {
.build(),
);
self.pipeline.set_state(gst::State::Playing)?;
Ok(())
}
fn map_gl_api(api: glutin::Api) -> gst_gl::GLAPI {
match api {
glutin::Api::OpenGl => gst_gl::GLAPI::OPENGL3,
glutin::Api::OpenGlEs => gst_gl::GLAPI::GLES2,
_ => gst_gl::GLAPI::empty(),
}
/// Converts from <https://docs.rs/glutin/latest/glutin/config/struct.Api.html> to
/// <https://gstreamer.freedesktop.org/documentation/gl/gstglapi.html?gi-language=c#GstGLAPI>.
fn map_gl_api(api: glutin::config::Api) -> gst_gl::GLAPI {
use glutin::config::Api;
use gst_gl::GLAPI;
let mut gst_gl_api = GLAPI::empty();
// In gstreamer:
// GLAPI::OPENGL: Desktop OpenGL up to and including 3.1. The compatibility profile when the OpenGL version is >= 3.2
// GLAPI::OPENGL3: Desktop OpenGL >= 3.2 core profile
// In glutin, API::OPENGL is set for every context API, except EGL where it is set based on
// EGL_RENDERABLE_TYPE containing EGL_OPENGL_BIT:
// https://registry.khronos.org/EGL/sdk/docs/man/html/eglChooseConfig.xhtml
gst_gl_api.set(GLAPI::OPENGL | GLAPI::OPENGL3, api.contains(Api::OPENGL));
gst_gl_api.set(GLAPI::GLES1, api.contains(Api::GLES1));
// OpenGL ES 2.x and 3.x
gst_gl_api.set(GLAPI::GLES2, api.intersects(Api::GLES2 | Api::GLES3));
gst_gl_api
}
fn create_pipeline(
gl_element: Option<&gst::Element>,
) -> Result<(gst::Pipeline, gst_app::AppSink), Error> {
) -> Result<(gst::Pipeline, gst_app::AppSink)> {
let pipeline = gst::Pipeline::default();
let src = gst::ElementFactory::make("videotestsrc").build()?;
@ -576,7 +653,7 @@ impl App {
}
}
fn handle_messages(bus: &gst::Bus) -> Result<(), Error> {
fn handle_messages(bus: &gst::Bus) -> Result<()> {
use gst::MessageView;
for msg in bus.iter() {
@ -601,77 +678,143 @@ impl App {
}
}
pub(crate) fn main_loop(app: App) -> Result<(), Error> {
pub(crate) fn main_loop(app: App) -> Result<()> {
app.setup(&app.event_loop)?;
println!(
"Pixel format of the window's GL context {:?}",
app.windowed_context.get_pixel_format()
);
let gl = load(&app.windowed_context);
let mut curr_frame: Option<gst_video::VideoFrame<gst_video::video_frame::Readable>> = None;
let App {
pipeline,
bus,
event_loop,
pipeline,
mut window,
mut not_current_gl_context,
shared_context,
windowed_context,
..
} = app;
event_loop.run(move |event, _, cf| {
*cf = glutin::event_loop::ControlFlow::Wait;
let mut curr_frame: Option<gst_video::VideoFrame<gst_video::video_frame::Readable>> = None;
let mut running_state = None::<(
Gl,
glutin::context::PossiblyCurrentContext,
glutin::surface::Surface<glutin::surface::WindowSurface>,
)>;
Ok(event_loop.run(move |event, window_target| {
window_target.set_control_flow(winit::event_loop::ControlFlow::Wait);
let mut needs_redraw = false;
match event {
glutin::event::Event::LoopDestroyed => {
winit::event::Event::LoopExiting => {
pipeline.send_event(gst::event::Eos::new());
pipeline.set_state(gst::State::Null).unwrap();
}
glutin::event::Event::WindowEvent { event, .. } => match event {
glutin::event::WindowEvent::CloseRequested
| glutin::event::WindowEvent::KeyboardInput {
input:
glutin::event::KeyboardInput {
state: glutin::event::ElementState::Released,
virtual_keycode: Some(glutin::event::VirtualKeyCode::Escape),
winit::event::Event::WindowEvent { event, .. } => match event {
winit::event::WindowEvent::CloseRequested
| winit::event::WindowEvent::KeyboardInput {
event:
winit::event::KeyEvent {
state: winit::event::ElementState::Released,
logical_key:
winit::keyboard::Key::Named(winit::keyboard::NamedKey::Escape),
..
},
..
} => *cf = glutin::event_loop::ControlFlow::Exit,
glutin::event::WindowEvent::Resized(physical_size) => {
windowed_context.resize(physical_size);
gl.resize(physical_size);
} => window_target.exit(),
winit::event::WindowEvent::Resized(size) => {
// Some platforms like EGL require resizing GL surface to update the size
// Notable platforms here are Wayland and macOS, other don't require it
// and the function is no-op, but it's wise to resize it for portability
// reasons.
if let Some((gl, gl_context, gl_surface)) = &running_state {
gl_surface.resize(
gl_context,
// XXX Ignore minimizing
NonZeroU32::new(size.width).unwrap(),
NonZeroU32::new(size.height).unwrap(),
);
gl.resize(size);
}
}
winit::event::WindowEvent::RedrawRequested => needs_redraw = true,
_ => (),
},
glutin::event::Event::RedrawRequested(_) => needs_redraw = true,
// Receive a frame
glutin::event::Event::UserEvent(Message::Frame(info, buffer)) => {
winit::event::Event::UserEvent(Message::Frame(info, buffer)) => {
if let Ok(frame) = gst_video::VideoFrame::from_buffer_readable_gl(buffer, &info) {
curr_frame = Some(frame);
needs_redraw = true;
}
}
// Handle all pending messages when we are awaken by set_sync_handler
glutin::event::Event::UserEvent(Message::BusEvent) => {
winit::event::Event::UserEvent(Message::BusEvent) => {
App::handle_messages(&bus).unwrap();
}
winit::event::Event::Resumed => {
let not_current_gl_context = not_current_gl_context
.take()
.expect("There must be a NotCurrentContext prior to Event::Resumed");
let gl_config = not_current_gl_context.config();
let gl_display = gl_config.display();
let window = window.get_or_insert_with(|| {
let window_builder = winit::window::WindowBuilder::new().with_transparent(true);
glutin_winit::finalize_window(window_target, window_builder, &gl_config)
.unwrap()
});
let attrs = window.build_surface_attributes(<_>::default());
let gl_surface = unsafe {
gl_config
.display()
.create_window_surface(&gl_config, &attrs)
.unwrap()
};
// Make it current.
let gl_context = not_current_gl_context.make_current(&gl_surface).unwrap();
// Tell GStreamer that the context has been made current (for borrowed contexts,
// this does not try to make it current again)
shared_context.activate(true).unwrap();
shared_context
.fill_info()
.expect("Couldn't fill context info");
// The context needs to be current for the Renderer to set up shaders and buffers.
// It also performs function loading, which needs a current context on WGL.
let gl = load(&gl_display);
// Try setting vsync.
if let Err(res) = gl_surface.set_swap_interval(
&gl_context,
glutin::surface::SwapInterval::Wait(std::num::NonZeroU32::new(1).unwrap()),
) {
eprintln!("Error setting vsync: {res:?}");
}
pipeline.set_state(gst::State::Playing).unwrap();
assert!(running_state
.replace((gl, gl_context, gl_surface))
.is_none());
}
_ => (),
}
if needs_redraw {
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 Some(texture) = frame.texture_id(0) {
gl.draw_frame(texture as gl::types::GLuint);
if let Some((gl, gl_context, gl_surface)) = &running_state {
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 Some(texture) = frame.texture_id(0) {
gl.draw_frame(texture as gl::types::GLuint);
}
}
gl_surface.swap_buffers(gl_context).unwrap();
}
windowed_context.swap_buffers().unwrap();
}
})
})?)
}

2
gir

@ -1 +1 @@
Subproject commit 1d1ce102e130a70684f90f411ee75b4e73f90beb
Subproject commit 23d7c100187cb4767ef77e0e4b3a511cbfadf035

@ -1 +1 @@
Subproject commit 060b114d8edb20c4041abb1e95acccb2cb2302be
Subproject commit 6415239ef4354633334410cfae108e64ae7ff708

@ -1 +1 @@
Subproject commit 8ea27b3f0b3316bdc3df48581820805b18473413
Subproject commit 62054dc7234dfe1499245ce19ac9454dcb5dd594

View file

@ -1,6 +1,6 @@
[package]
name = "gstreamer-allocators"
version = "0.21.0"
version = "0.21.3"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
categories = ["api-bindings", "multimedia"]
description = "Rust bindings for GStreamer Allocators library"
@ -15,9 +15,9 @@ rust-version = "1.70"
[dependencies]
libc = "0.2"
ffi = { package = "gstreamer-allocators-sys", path = "sys" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../gstreamer" }
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"

View file

@ -94,3 +94,15 @@ status = "generate"
[[object.function]]
name = "alloc"
manual = true
[[object]]
name = "GstAllocators.ShmAllocator"
status = "generate"
cfg_condition = "unix"
[[object.function]]
name = "get"
manual = true
[[object.function]]
name = "init_once"
manual = true

View file

@ -11,6 +11,11 @@ pub static ALLOCATOR_DMABUF: &GStr =
#[doc(alias = "GST_ALLOCATOR_FD")]
pub static ALLOCATOR_FD: &GStr =
unsafe { GStr::from_utf8_with_nul_unchecked(ffi::GST_ALLOCATOR_FD) };
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[doc(alias = "GST_ALLOCATOR_SHM")]
pub static ALLOCATOR_SHM: &GStr =
unsafe { GStr::from_utf8_with_nul_unchecked(ffi::GST_ALLOCATOR_SHM) };
#[doc(alias = "GST_CAPS_FEATURE_MEMORY_DMABUF")]
pub static CAPS_FEATURE_MEMORY_DMABUF: &GStr =
unsafe { GStr::from_utf8_with_nul_unchecked(ffi::GST_CAPS_FEATURE_MEMORY_DMABUF) };

View file

@ -27,6 +27,17 @@ pub use self::fd_allocator::FdAllocator;
mod phys_memory_allocator;
pub use self::phys_memory_allocator::PhysMemoryAllocator;
#[cfg(unix)]
#[cfg_attr(docsrs, doc(cfg(unix)))]
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
mod shm_allocator;
#[cfg(unix)]
#[cfg_attr(docsrs, doc(cfg(unix)))]
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub use self::shm_allocator::ShmAllocator;
mod flags;
pub use self::flags::FdMemoryFlags;
@ -35,6 +46,9 @@ pub mod functions;
mod constants;
pub use self::constants::ALLOCATOR_DMABUF;
pub use self::constants::ALLOCATOR_FD;
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub use self::constants::ALLOCATOR_SHM;
pub use self::constants::CAPS_FEATURE_MEMORY_DMABUF;
#[doc(hidden)]

View file

@ -0,0 +1,20 @@
// This file was generated by gir (https://github.com/gtk-rs/gir)
// from gir-files (https://github.com/gtk-rs/gir-files)
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT
use crate::FdAllocator;
glib::wrapper! {
#[doc(alias = "GstShmAllocator")]
pub struct ShmAllocator(Object<ffi::GstShmAllocator, ffi::GstShmAllocatorClass>) @extends FdAllocator, gst::Allocator;
match fn {
type_ => || ffi::gst_shm_allocator_get_type(),
}
}
impl ShmAllocator {}
unsafe impl Send for ShmAllocator {}
unsafe impl Sync for ShmAllocator {}

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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

@ -44,6 +44,10 @@ mod drm_dumb_allocator;
#[cfg_attr(docsrs, doc(cfg(all(feature = "v1_24", target_os = "linux"))))]
pub use drm_dumb_allocator::*;
#[cfg(any(all(feature = "v1_24", unix), docsrs))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "v1_24", unix))))]
mod shm_allocator;
mod phys_memory;
pub use phys_memory::*;

View file

@ -0,0 +1,14 @@
use glib::translate::*;
use crate::ShmAllocator;
impl ShmAllocator {
#[doc(alias = "gst_shm_allocator_get")]
pub fn get() -> Option<gst::Allocator> {
assert_initialized_main_thread!();
unsafe {
ffi::gst_shm_allocator_init_once();
from_glib_full(ffi::gst_shm_allocator_get())
}
}
}

View file

@ -7,14 +7,19 @@ libc = "0.2"
[dependencies.glib]
git = "https://github.com/gtk-rs/gtk-rs-core"
package = "glib-sys"
branch = "0.18"
version = "0.18"
[dependencies.gobject]
git = "https://github.com/gtk-rs/gtk-rs-core"
package = "gobject-sys"
branch = "0.18"
version = "0.18"
[dependencies.gst]
package = "gstreamer-sys"
path = "../../gstreamer/sys"
version = "0.21"
[dev-dependencies]
shell-words = "1.0.0"
@ -43,7 +48,7 @@ name = "gstreamer-allocators-sys"
readme = "README.md"
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
rust-version = "1.70"
version = "0.21.0"
version = "0.21.3"
[package.metadata.docs.rs]
all-features = true

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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

@ -24,6 +24,7 @@ use glib::{gboolean, gconstpointer, gpointer, GType};
// Constants
pub const GST_ALLOCATOR_DMABUF: &[u8] = b"dmabuf\0";
pub const GST_ALLOCATOR_FD: &[u8] = b"fd\0";
pub const GST_ALLOCATOR_SHM: &[u8] = b"shm\0";
pub const GST_CAPS_FEATURE_MEMORY_DMABUF: &[u8] = b"memory:DMABuf\0";
// Flags
@ -93,6 +94,20 @@ impl ::std::fmt::Debug for GstPhysMemoryAllocatorInterface {
}
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct GstShmAllocatorClass {
pub parent_class: GstFdAllocatorClass,
}
impl ::std::fmt::Debug for GstShmAllocatorClass {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
f.debug_struct(&format!("GstShmAllocatorClass @ {self:p}"))
.field("parent_class", &self.parent_class)
.finish()
}
}
// Classes
#[repr(C)]
pub struct GstDRMDumbAllocator {
@ -136,6 +151,19 @@ impl ::std::fmt::Debug for GstFdAllocator {
}
}
#[repr(C)]
pub struct GstShmAllocator {
_data: [u8; 0],
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
impl ::std::fmt::Debug for GstShmAllocator {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
f.debug_struct(&format!("GstShmAllocator @ {self:p}"))
.finish()
}
}
// Interfaces
#[repr(C)]
pub struct GstPhysMemoryAllocator {
@ -211,6 +239,19 @@ extern "C" {
flags: GstFdMemoryFlags,
) -> *mut gst::GstMemory;
//=========================================================================
// GstShmAllocator
//=========================================================================
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn gst_shm_allocator_get_type() -> GType;
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn gst_shm_allocator_get() -> *mut gst::GstAllocator;
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn gst_shm_allocator_init_once();
//=========================================================================
// GstPhysMemoryAllocator
//=========================================================================

View file

@ -247,11 +247,19 @@ const RUST_LAYOUTS: &[(&str, Layout)] = &[
alignment: align_of::<GstPhysMemoryAllocatorInterface>(),
},
),
(
"GstShmAllocatorClass",
Layout {
size: size_of::<GstShmAllocatorClass>(),
alignment: align_of::<GstShmAllocatorClass>(),
},
),
];
const RUST_CONSTANTS: &[(&str, &str)] = &[
("GST_ALLOCATOR_DMABUF", "dmabuf"),
("GST_ALLOCATOR_FD", "fd"),
("GST_ALLOCATOR_SHM", "shm"),
("GST_CAPS_FEATURE_MEMORY_DMABUF", "memory:DMABuf"),
("(guint) GST_FD_MEMORY_FLAG_DONT_CLOSE", "4"),
("(guint) GST_FD_MEMORY_FLAG_KEEP_MAPPED", "1"),

View file

@ -31,6 +31,7 @@
int main() {
PRINT_CONSTANT(GST_ALLOCATOR_DMABUF);
PRINT_CONSTANT(GST_ALLOCATOR_FD);
PRINT_CONSTANT(GST_ALLOCATOR_SHM);
PRINT_CONSTANT(GST_CAPS_FEATURE_MEMORY_DMABUF);
PRINT_CONSTANT((guint) GST_FD_MEMORY_FLAG_DONT_CLOSE);
PRINT_CONSTANT((guint) GST_FD_MEMORY_FLAG_KEEP_MAPPED);

View file

@ -15,5 +15,6 @@ int main() {
printf("%s;%zu;%zu\n", "GstFdAllocatorClass", sizeof(GstFdAllocatorClass), alignof(GstFdAllocatorClass));
printf("%s;%zu;%zu\n", "GstFdMemoryFlags", sizeof(GstFdMemoryFlags), alignof(GstFdMemoryFlags));
printf("%s;%zu;%zu\n", "GstPhysMemoryAllocatorInterface", sizeof(GstPhysMemoryAllocatorInterface), alignof(GstPhysMemoryAllocatorInterface));
printf("%s;%zu;%zu\n", "GstShmAllocatorClass", sizeof(GstShmAllocatorClass), alignof(GstShmAllocatorClass));
return 0;
}

View file

@ -1,6 +1,6 @@
[package]
name = "gstreamer-app"
version = "0.21.0"
version = "0.21.3"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
categories = ["api-bindings", "multimedia"]
description = "Rust bindings for GStreamer App library"
@ -17,10 +17,10 @@ rust-version = "1.70"
futures-core = "0.3"
futures-sink = "0.3"
libc = "0.2"
ffi = { package = "gstreamer-app-sys", path = "sys" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../gstreamer" }
gst-base = { package = "gstreamer-base", path = "../gstreamer-base" }
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"] }

View file

@ -1163,6 +1163,24 @@ impl AppSinkBuilder {
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn max_time(self, max_time: Option<gst::ClockTime>) -> Self {
Self {
builder: self.builder.property("max-time", max_time),
..self
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn max_bytes(self, max_bytes: u64) -> Self {
Self {
builder: self.builder.property("max-bytes", max_bytes),
..self
}
}
pub fn name(self, name: impl Into<glib::GString>) -> Self {
Self {
builder: self.builder.property("name", name.into()),
@ -1236,9 +1254,8 @@ impl Stream for AppSinkStream {
fn poll_next(self: Pin<&mut Self>, context: &mut Context) -> Poll<Option<Self::Item>> {
let mut waker = self.waker_reference.lock().unwrap();
let app_sink = match self.app_sink.upgrade() {
Some(app_sink) => app_sink,
None => return Poll::Ready(None),
let Some(app_sink) = self.app_sink.upgrade() else {
return Poll::Ready(None);
};
app_sink

View file

@ -588,9 +588,8 @@ impl Sink<gst::Sample> for AppSrcSink {
fn poll_ready(self: Pin<&mut Self>, context: &mut Context) -> Poll<Result<(), Self::Error>> {
let mut waker = self.waker_reference.lock().unwrap();
let app_src = match self.app_src.upgrade() {
Some(app_src) => app_src,
None => return Poll::Ready(Err(gst::FlowError::Eos)),
let Some(app_src) = self.app_src.upgrade() else {
return Poll::Ready(Err(gst::FlowError::Eos));
};
let current_level_bytes = app_src.current_level_bytes();
@ -606,9 +605,8 @@ impl Sink<gst::Sample> for AppSrcSink {
}
fn start_send(self: Pin<&mut Self>, sample: gst::Sample) -> Result<(), Self::Error> {
let app_src = match self.app_src.upgrade() {
Some(app_src) => app_src,
None => return Err(gst::FlowError::Eos),
let Some(app_src) = self.app_src.upgrade() else {
return Err(gst::FlowError::Eos);
};
app_src.push_sample(&sample)?;
@ -621,9 +619,8 @@ impl Sink<gst::Sample> for AppSrcSink {
}
fn poll_close(self: Pin<&mut Self>, _: &mut Context) -> Poll<Result<(), Self::Error>> {
let app_src = match self.app_src.upgrade() {
Some(app_src) => app_src,
None => return Poll::Ready(Ok(())),
let Some(app_src) = self.app_src.upgrade() else {
return Poll::Ready(Ok(()));
};
app_src.end_of_stream()?;

View file

@ -48,6 +48,22 @@ impl AppSink {
unsafe { ffi::gst_app_sink_get_max_buffers(self.to_glib_none().0) }
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[doc(alias = "gst_app_sink_get_max_bytes")]
#[doc(alias = "get_max_bytes")]
pub fn max_bytes(&self) -> u64 {
unsafe { ffi::gst_app_sink_get_max_bytes(self.to_glib_none().0) }
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[doc(alias = "gst_app_sink_get_max_time")]
#[doc(alias = "get_max_time")]
pub fn max_time(&self) -> Option<gst::ClockTime> {
unsafe { from_glib(ffi::gst_app_sink_get_max_time(self.to_glib_none().0)) }
}
#[doc(alias = "gst_app_sink_get_wait_on_eos")]
#[doc(alias = "get_wait_on_eos")]
pub fn is_wait_on_eos(&self) -> bool {
@ -121,6 +137,24 @@ impl AppSink {
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[doc(alias = "gst_app_sink_set_max_bytes")]
pub fn set_max_bytes(&self, max: u64) {
unsafe {
ffi::gst_app_sink_set_max_bytes(self.to_glib_none().0, max);
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[doc(alias = "gst_app_sink_set_max_time")]
pub fn set_max_time(&self, max: impl Into<Option<gst::ClockTime>>) {
unsafe {
ffi::gst_app_sink_set_max_time(self.to_glib_none().0, max.into().into_glib());
}
}
#[doc(alias = "gst_app_sink_set_wait_on_eos")]
pub fn set_wait_on_eos(&self, wait: bool) {
unsafe {
@ -313,6 +347,64 @@ impl AppSink {
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[doc(alias = "max-bytes")]
pub fn connect_max_bytes_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self,
f: F,
) -> SignalHandlerId {
unsafe extern "C" fn notify_max_bytes_trampoline<
F: Fn(&AppSink) + Send + Sync + 'static,
>(
this: *mut ffi::GstAppSink,
_param_spec: glib::ffi::gpointer,
f: glib::ffi::gpointer,
) {
let f: &F = &*(f as *const F);
f(&from_glib_borrow(this))
}
unsafe {
let f: Box_<F> = Box_::new(f);
connect_raw(
self.as_ptr() as *mut _,
b"notify::max-bytes\0".as_ptr() as *const _,
Some(transmute::<_, unsafe extern "C" fn()>(
notify_max_bytes_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
)
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[doc(alias = "max-time")]
pub fn connect_max_time_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self,
f: F,
) -> SignalHandlerId {
unsafe extern "C" fn notify_max_time_trampoline<F: Fn(&AppSink) + Send + Sync + 'static>(
this: *mut ffi::GstAppSink,
_param_spec: glib::ffi::gpointer,
f: glib::ffi::gpointer,
) {
let f: &F = &*(f as *const F);
f(&from_glib_borrow(this))
}
unsafe {
let f: Box_<F> = Box_::new(f);
connect_raw(
self.as_ptr() as *mut _,
b"notify::max-time\0".as_ptr() as *const _,
Some(transmute::<_, unsafe extern "C" fn()>(
notify_max_time_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
)
}
}
#[doc(alias = "wait-on-eos")]
pub fn connect_wait_on_eos_notify<F: Fn(&Self) + Send + Sync + 'static>(
&self,

View file

@ -59,6 +59,7 @@ impl FromGlib<ffi::GstAppLeakyType> for AppLeakyType {
#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
impl StaticType for AppLeakyType {
#[inline]
#[doc(alias = "gst_app_leaky_type_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_app_leaky_type_get_type()) }
}
@ -72,7 +73,7 @@ impl glib::HasParamSpec for AppLeakyType {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -168,6 +169,7 @@ impl FromGlib<ffi::GstAppStreamType> for AppStreamType {
impl StaticType for AppStreamType {
#[inline]
#[doc(alias = "gst_app_stream_type_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_app_stream_type_get_type()) }
}
@ -179,7 +181,7 @@ impl glib::HasParamSpec for AppStreamType {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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

@ -7,14 +7,18 @@ libc = "0.2"
[dependencies.glib]
package = "glib-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gst_base]
package = "gstreamer-base-sys"
path = "../../gstreamer-base/sys"
version = "0.21"
[dependencies.gst]
package = "gstreamer-sys"
path = "../../gstreamer/sys"
version = "0.21"
[dev-dependencies]
shell-words = "1.0.0"
@ -41,7 +45,7 @@ license = "MIT"
name = "gstreamer-app-sys"
readme = "README.md"
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
version = "0.21.0"
version = "0.21.3"
edition = "2021"
rust-version = "1.70"

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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

@ -215,6 +215,12 @@ extern "C" {
pub fn gst_app_sink_get_drop(appsink: *mut GstAppSink) -> gboolean;
pub fn gst_app_sink_get_emit_signals(appsink: *mut GstAppSink) -> gboolean;
pub fn gst_app_sink_get_max_buffers(appsink: *mut GstAppSink) -> c_uint;
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn gst_app_sink_get_max_bytes(appsink: *mut GstAppSink) -> u64;
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn gst_app_sink_get_max_time(appsink: *mut GstAppSink) -> gst::GstClockTime;
pub fn gst_app_sink_get_wait_on_eos(appsink: *mut GstAppSink) -> gboolean;
pub fn gst_app_sink_is_eos(appsink: *mut GstAppSink) -> gboolean;
#[cfg(feature = "v1_20")]
@ -233,6 +239,12 @@ extern "C" {
pub fn gst_app_sink_set_drop(appsink: *mut GstAppSink, drop: gboolean);
pub fn gst_app_sink_set_emit_signals(appsink: *mut GstAppSink, emit: gboolean);
pub fn gst_app_sink_set_max_buffers(appsink: *mut GstAppSink, max: c_uint);
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn gst_app_sink_set_max_bytes(appsink: *mut GstAppSink, max: u64);
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn gst_app_sink_set_max_time(appsink: *mut GstAppSink, max: gst::GstClockTime);
pub fn gst_app_sink_set_wait_on_eos(appsink: *mut GstAppSink, wait: gboolean);
#[cfg(feature = "v1_20")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]

View file

@ -1,6 +1,6 @@
[package]
name = "gstreamer-audio"
version = "0.21.0"
version = "0.21.3"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
categories = ["api-bindings", "multimedia"]
description = "Rust bindings for GStreamer Audio library"
@ -16,14 +16,14 @@ rust-version = "1.70"
[dependencies]
libc = "0.2"
cfg-if = "1.0"
ffi = { package = "gstreamer-audio-sys", path = "sys" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../gstreamer" }
gst-base = { package = "gstreamer-base", path = "../gstreamer-base" }
ffi = { package = "gstreamer-audio-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" }
gst-base = { package = "gstreamer-base", path = "../gstreamer-base", version = "0.21" }
serde = { version = "1.0", optional = true }
[dev-dependencies]
itertools = "0.11"
itertools = "0.12"
serde_json = "1.0"
gir-format-check = "0.1"

View file

@ -160,7 +160,7 @@ impl AudioConverterConfig {
})
.collect::<Vec<_>>()
})
.unwrap_or_else(Vec::new)
.unwrap_or_default()
}
#[cfg(feature = "v1_22")]

View file

@ -148,13 +148,14 @@ impl str::FromStr for crate::AudioFormat {
}
impl PartialOrd for crate::AudioFormat {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
crate::AudioFormatInfo::from_format(*self)
.partial_cmp(&crate::AudioFormatInfo::from_format(*other))
Some(self.cmp(other))
}
}
impl Ord for crate::AudioFormat {
#[inline]
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
crate::AudioFormatInfo::from_format(*self).cmp(&crate::AudioFormatInfo::from_format(*other))
}

View file

@ -56,6 +56,7 @@ impl FromGlib<ffi::GstAudioDitherMethod> for AudioDitherMethod {
impl StaticType for AudioDitherMethod {
#[inline]
#[doc(alias = "gst_audio_dither_method_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_audio_dither_method_get_type()) }
}
@ -67,7 +68,7 @@ impl glib::HasParamSpec for AudioDitherMethod {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -284,6 +285,7 @@ impl FromGlib<ffi::GstAudioFormat> for AudioFormat {
impl StaticType for AudioFormat {
#[inline]
#[doc(alias = "gst_audio_format_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_audio_format_get_type()) }
}
@ -295,7 +297,7 @@ impl glib::HasParamSpec for AudioFormat {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -379,6 +381,7 @@ impl FromGlib<ffi::GstAudioLayout> for AudioLayout {
impl StaticType for AudioLayout {
#[inline]
#[doc(alias = "gst_audio_layout_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_audio_layout_get_type()) }
}
@ -390,7 +393,7 @@ impl glib::HasParamSpec for AudioLayout {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -486,6 +489,7 @@ impl FromGlib<ffi::GstAudioNoiseShapingMethod> for AudioNoiseShapingMethod {
impl StaticType for AudioNoiseShapingMethod {
#[inline]
#[doc(alias = "gst_audio_noise_shaping_method_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_audio_noise_shaping_method_get_type()) }
}
@ -497,7 +501,7 @@ impl glib::HasParamSpec for AudioNoiseShapingMethod {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -593,6 +597,7 @@ impl FromGlib<ffi::GstAudioResamplerMethod> for AudioResamplerMethod {
impl StaticType for AudioResamplerMethod {
#[inline]
#[doc(alias = "gst_audio_resampler_method_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_audio_resampler_method_get_type()) }
}
@ -604,7 +609,7 @@ impl glib::HasParamSpec for AudioResamplerMethod {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -746,6 +751,7 @@ impl FromGlib<ffi::GstAudioRingBufferFormatType> for AudioRingBufferFormatType {
impl StaticType for AudioRingBufferFormatType {
#[inline]
#[doc(alias = "gst_audio_ring_buffer_format_type_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_audio_ring_buffer_format_type_get_type()) }
}
@ -757,7 +763,7 @@ impl glib::HasParamSpec for AudioRingBufferFormatType {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}

View file

@ -35,6 +35,7 @@ impl FromGlib<ffi::GstAudioFlags> for AudioFlags {
impl StaticType for AudioFlags {
#[inline]
#[doc(alias = "gst_audio_flags_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_audio_flags_get_type()) }
}
@ -46,7 +47,7 @@ impl glib::HasParamSpec for AudioFlags {
type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name| Self::ParamSpec::builder(name)
Self::ParamSpec::builder
}
}
@ -126,6 +127,7 @@ impl FromGlib<ffi::GstAudioFormatFlags> for AudioFormatFlags {
impl StaticType for AudioFormatFlags {
#[inline]
#[doc(alias = "gst_audio_format_flags_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_audio_format_flags_get_type()) }
}
@ -137,7 +139,7 @@ impl glib::HasParamSpec for AudioFormatFlags {
type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name| Self::ParamSpec::builder(name)
Self::ParamSpec::builder
}
}
@ -209,6 +211,7 @@ impl FromGlib<ffi::GstAudioPackFlags> for AudioPackFlags {
impl StaticType for AudioPackFlags {
#[inline]
#[doc(alias = "gst_audio_pack_flags_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_audio_pack_flags_get_type()) }
}
@ -220,7 +223,7 @@ impl glib::HasParamSpec for AudioPackFlags {
type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name| Self::ParamSpec::builder(name)
Self::ParamSpec::builder
}
}

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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,12 +1,14 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::*;
use glib::{once_cell::sync::Lazy, translate::*};
use gst_base::{prelude::*, subclass::prelude::*};
use crate::{AudioFilter, AudioInfo};
pub trait AudioFilterImpl: AudioFilterImplExt + BaseTransformImpl {
fn allowed_caps() -> &'static gst::Caps;
fn allowed_caps() -> &'static gst::Caps {
Self::parent_allowed_caps()
}
fn setup(&self, info: &AudioInfo) -> Result<(), gst::LoggableError> {
self.parent_setup(info)
@ -38,6 +40,27 @@ pub trait AudioFilterImplExt: sealed::Sealed + ObjectSubclass {
.unwrap_or(Ok(()))
}
}
fn parent_allowed_caps() -> &'static gst::Caps {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut gst::ffi::GstElementClass;
let templ = gst::ffi::gst_element_class_get_pad_template(
parent_class,
glib::gstr!("sink").to_glib_none().0,
);
if templ.is_null() {
static ANY_AUDIO_CAPS: Lazy<gst::Caps> =
Lazy::new(|| crate::AudioCapsBuilder::new().build());
return &ANY_AUDIO_CAPS;
}
&*(&(*templ).caps as *const *mut gst::ffi::GstCaps as *const gst::Caps)
}
}
}
impl<T: AudioFilterImpl> AudioFilterImplExt for T {}

View file

@ -7,18 +7,24 @@ libc = "0.2"
[dependencies.glib]
package = "glib-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gobject]
package = "gobject-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gst_base]
package = "gstreamer-base-sys"
path = "../../gstreamer-base/sys"
version = "0.21"
[dependencies.gst]
package = "gstreamer-sys"
path = "../../gstreamer/sys"
version = "0.21"
[dev-dependencies]
shell-words = "1.0.0"
@ -45,7 +51,7 @@ license = "MIT"
name = "gstreamer-audio-sys"
readme = "README.md"
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
version = "0.21.0"
version = "0.21.3"
edition = "2021"
rust-version = "1.70"

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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

@ -2317,6 +2317,9 @@ extern "C" {
buf: *mut GstAudioRingBuffer,
position: *const GstAudioChannelPosition,
);
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn gst_audio_ring_buffer_set_errored(buf: *mut GstAudioRingBuffer);
pub fn gst_audio_ring_buffer_set_flushing(buf: *mut GstAudioRingBuffer, flushing: gboolean);
pub fn gst_audio_ring_buffer_set_sample(buf: *mut GstAudioRingBuffer, sample: u64);
pub fn gst_audio_ring_buffer_set_timestamp(

View file

@ -1,6 +1,6 @@
[package]
name = "gstreamer-base"
version = "0.21.0"
version = "0.21.3"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
categories = ["api-bindings", "multimedia"]
description = "Rust bindings for GStreamer Base library"
@ -16,9 +16,9 @@ rust-version = "1.70"
[dependencies]
cfg-if = "1.0"
libc = "0.2"
ffi = { package = "gstreamer-base-sys", path = "sys" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../gstreamer" }
ffi = { package = "gstreamer-base-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" }
atomic_refcell = "0.1"
[dev-dependencies]

View file

@ -61,6 +61,7 @@ impl FromGlib<ffi::GstAggregatorStartTimeSelection> for AggregatorStartTimeSelec
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
impl StaticType for AggregatorStartTimeSelection {
#[inline]
#[doc(alias = "gst_aggregator_start_time_selection_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_aggregator_start_time_selection_get_type()) }
}
@ -74,7 +75,7 @@ impl glib::HasParamSpec for AggregatorStartTimeSelection {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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

@ -7,14 +7,19 @@ libc = "0.2"
[dependencies.glib]
package = "glib-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gobject]
package = "gobject-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gst]
package = "gstreamer-sys"
path = "../../gstreamer/sys"
version = "0.21"
[dev-dependencies]
shell-words = "1.0.0"
@ -43,7 +48,7 @@ license = "MIT"
name = "gstreamer-base-sys"
readme = "README.md"
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
version = "0.21.0"
version = "0.21.3"
edition = "2021"
rust-version = "1.70"

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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

@ -1706,6 +1706,22 @@ extern "C" {
pub fn gst_queue_array_pop_head_struct(array: *mut GstQueueArray) -> gpointer;
pub fn gst_queue_array_pop_tail(array: *mut GstQueueArray) -> gpointer;
pub fn gst_queue_array_pop_tail_struct(array: *mut GstQueueArray) -> gpointer;
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn gst_queue_array_push_sorted(
array: *mut GstQueueArray,
data: gpointer,
func: glib::GCompareDataFunc,
user_data: gpointer,
);
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn gst_queue_array_push_sorted_struct(
array: *mut GstQueueArray,
p_struct: gpointer,
func: glib::GCompareDataFunc,
user_data: gpointer,
);
pub fn gst_queue_array_push_tail(array: *mut GstQueueArray, data: gpointer);
pub fn gst_queue_array_push_tail_struct(array: *mut GstQueueArray, p_struct: gpointer);
#[cfg(feature = "v1_16")]
@ -1714,6 +1730,13 @@ extern "C" {
array: *mut GstQueueArray,
clear_func: glib::GDestroyNotify,
);
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn gst_queue_array_sort(
array: *mut GstQueueArray,
compare_func: glib::GCompareDataFunc,
user_data: gpointer,
);
pub fn gst_queue_array_new(initial_size: c_uint) -> *mut GstQueueArray;
pub fn gst_queue_array_new_for_struct(
struct_size: size_t,

View file

@ -1,6 +1,6 @@
[package]
name = "gstreamer-check"
version = "0.21.0"
version = "0.21.3"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
categories = ["api-bindings", "multimedia"]
description = "Rust bindings for GStreamer Check library"
@ -14,9 +14,9 @@ edition = "2021"
rust-version = "1.70"
[dependencies]
ffi = { package = "gstreamer-check-sys", path = "sys" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../gstreamer" }
ffi = { package = "gstreamer-check-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"

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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

@ -7,14 +7,19 @@ libc = "0.2"
[dependencies.glib]
package = "glib-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gobject]
package = "gobject-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gst]
package = "gstreamer-sys"
path = "../../gstreamer/sys"
version = "0.21"
[dev-dependencies]
shell-words = "1.0.0"
@ -41,7 +46,7 @@ license = "MIT"
name = "gstreamer-check-sys"
readme = "README.md"
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
version = "0.21.0"
version = "0.21.3"
edition = "2021"
rust-version = "1.70"

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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,6 +1,6 @@
[package]
name = "gstreamer-controller"
version = "0.21.0"
version = "0.21.3"
authors = ["Alexey Galakhov <agalakhov@gmail.com>", "Sebastian Dröge <sebastian@centricular.com>"]
categories = ["api-bindings", "multimedia"]
description = "Rust bindings for GStreamer Controller library"
@ -14,9 +14,9 @@ edition = "2021"
rust-version = "1.70"
[dependencies]
ffi = { package = "gstreamer-controller-sys", path = "sys" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../gstreamer" }
ffi = { package = "gstreamer-controller-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"

View file

@ -55,6 +55,7 @@ impl FromGlib<ffi::GstInterpolationMode> for InterpolationMode {
impl StaticType for InterpolationMode {
#[inline]
#[doc(alias = "gst_interpolation_mode_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_interpolation_mode_get_type()) }
}
@ -66,7 +67,7 @@ impl glib::HasParamSpec for InterpolationMode {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -162,6 +163,7 @@ impl FromGlib<ffi::GstLFOWaveform> for LFOWaveform {
impl StaticType for LFOWaveform {
#[inline]
#[doc(alias = "gst_lfo_waveform_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::gst_lfo_waveform_get_type()) }
}
@ -173,7 +175,7 @@ impl glib::HasParamSpec for LFOWaveform {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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

@ -8,14 +8,19 @@ libc = "0.2"
[dependencies.glib]
package = "glib-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gobject]
package = "gobject-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gst]
package = "gstreamer-sys"
path = "../../gstreamer/sys"
version = "0.21"
[dev-dependencies]
shell-words = "1.0.0"
@ -42,7 +47,7 @@ license = "MIT"
name = "gstreamer-controller-sys"
readme = "README.md"
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
version = "0.21.0"
version = "0.21.3"
edition = "2021"
rust-version = "1.70"

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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,6 +1,6 @@
[package]
name = "gstreamer-editing-services"
version = "0.21.0"
version = "0.21.3"
authors = ["Thibault Saunier <tsaunier@igalia.com>", "Sebastian Dröge <sebastian@centricular.com>"]
categories = ["api-bindings", "multimedia"]
description = "Rust bindings for GStreamer Editing Services"
@ -15,12 +15,12 @@ rust-version = "1.70"
[dependencies]
libc = "0.2"
ffi = { package = "gstreamer-editing-services-sys", path = "sys"}
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gio = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../gstreamer" }
gst-base = { package = "gstreamer-base", path = "../gstreamer-base" }
gst-pbutils = { package = "gstreamer-pbutils", path = "../gstreamer-pbutils" }
ffi = { package = "gstreamer-editing-services-sys", path = "sys", version = "0.21"}
glib = { git = "https://github.com/gtk-rs/gtk-rs-core", branch = "0.18", version = "0.18" }
gio = { 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" }
gst-pbutils = { package = "gstreamer-pbutils", path = "../gstreamer-pbutils", version = "0.21" }
serde = { version = "1.0", optional = true }
[dev-dependencies]

View file

@ -18,6 +18,7 @@ external_libraries = [
]
manual = [
"GES.FrameCompositionMeta",
"Gio.AsyncReadyCallback",
"Gio.Cancellable",
"GLib.Date",

View file

@ -6,4 +6,5 @@
#[allow(unused_imports)]
use crate::auto::*;
#[doc(alias = "GESFrameNumber")]
pub type FrameNumber = i64;

View file

@ -150,6 +150,36 @@ impl DiscovererManager {
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[doc(alias = "source-setup")]
pub fn connect_source_setup<F: Fn(&Self, &gst::Element) + 'static>(
&self,
f: F,
) -> SignalHandlerId {
unsafe extern "C" fn source_setup_trampoline<
F: Fn(&DiscovererManager, &gst::Element) + 'static,
>(
this: *mut ffi::GESDiscovererManager,
source: *mut gst::ffi::GstElement,
f: glib::ffi::gpointer,
) {
let f: &F = &*(f as *const F);
f(&from_glib_borrow(this), &from_glib_borrow(source))
}
unsafe {
let f: Box_<F> = Box_::new(f);
connect_raw(
self.as_ptr() as *mut _,
b"source-setup\0".as_ptr() as *const _,
Some(transmute::<_, unsafe extern "C" fn()>(
source_setup_trampoline::<F> as *const (),
)),
Box_::into_raw(f),
)
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[doc(alias = "timeout")]

View file

@ -176,6 +176,7 @@ impl FromGlib<ffi::GESEdge> for Edge {
impl StaticType for Edge {
#[inline]
#[doc(alias = "ges_edge_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::ges_edge_get_type()) }
}
@ -187,7 +188,7 @@ impl glib::HasParamSpec for Edge {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -306,6 +307,7 @@ impl FromGlib<ffi::GESEditMode> for EditMode {
impl StaticType for EditMode {
#[inline]
#[doc(alias = "ges_edit_mode_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::ges_edit_mode_get_type()) }
}
@ -317,7 +319,7 @@ impl glib::HasParamSpec for EditMode {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -481,6 +483,7 @@ impl FromGlib<ffi::GESTextHAlign> for TextHAlign {
impl StaticType for TextHAlign {
#[inline]
#[doc(alias = "ges_text_halign_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::ges_text_halign_get_type()) }
}
@ -492,7 +495,7 @@ impl glib::HasParamSpec for TextHAlign {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -592,6 +595,7 @@ impl FromGlib<ffi::GESTextVAlign> for TextVAlign {
impl StaticType for TextVAlign {
#[inline]
#[doc(alias = "ges_text_valign_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::ges_text_valign_get_type()) }
}
@ -603,7 +607,7 @@ impl glib::HasParamSpec for TextVAlign {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -973,6 +977,7 @@ impl FromGlib<ffi::GESVideoStandardTransitionType> for VideoStandardTransitionTy
impl StaticType for VideoStandardTransitionType {
#[inline]
#[doc(alias = "ges_video_standard_transition_type_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::ges_video_standard_transition_type_get_type()) }
}
@ -984,7 +989,7 @@ impl glib::HasParamSpec for VideoStandardTransitionType {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}
@ -1130,6 +1135,7 @@ impl FromGlib<ffi::GESVideoTestPattern> for VideoTestPattern {
impl StaticType for VideoTestPattern {
#[inline]
#[doc(alias = "ges_video_test_pattern_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::ges_video_test_pattern_get_type()) }
}
@ -1141,7 +1147,7 @@ impl glib::HasParamSpec for VideoTestPattern {
type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name, default_value| Self::ParamSpec::builder_with_default(name, default_value)
Self::ParamSpec::builder_with_default
}
}

View file

@ -46,6 +46,7 @@ impl FromGlib<ffi::GESMarkerFlags> for MarkerFlags {
#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
impl StaticType for MarkerFlags {
#[inline]
#[doc(alias = "ges_marker_flags_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::ges_marker_flags_get_type()) }
}
@ -59,7 +60,7 @@ impl glib::HasParamSpec for MarkerFlags {
type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name| Self::ParamSpec::builder(name)
Self::ParamSpec::builder
}
}
@ -143,6 +144,7 @@ impl FromGlib<ffi::GESMetaFlag> for MetaFlag {
impl StaticType for MetaFlag {
#[inline]
#[doc(alias = "ges_meta_flag_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::ges_meta_flag_get_type()) }
}
@ -154,7 +156,7 @@ impl glib::HasParamSpec for MetaFlag {
type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name| Self::ParamSpec::builder(name)
Self::ParamSpec::builder
}
}
@ -234,6 +236,7 @@ impl FromGlib<ffi::GESPipelineFlags> for PipelineFlags {
impl StaticType for PipelineFlags {
#[inline]
#[doc(alias = "ges_pipeline_flags_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::ges_pipeline_flags_get_type()) }
}
@ -245,7 +248,7 @@ impl glib::HasParamSpec for PipelineFlags {
type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name| Self::ParamSpec::builder(name)
Self::ParamSpec::builder
}
}
@ -344,6 +347,7 @@ impl FromGlib<ffi::GESTrackType> for TrackType {
impl StaticType for TrackType {
#[inline]
#[doc(alias = "ges_track_type_get_type")]
fn static_type() -> glib::Type {
unsafe { from_glib(ffi::ges_track_type_get_type()) }
}
@ -355,7 +359,7 @@ impl glib::HasParamSpec for TrackType {
type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder<Self>;
fn param_spec_builder() -> Self::BuilderFn {
|name| Self::ParamSpec::builder(name)
Self::ParamSpec::builder
}
}

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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

@ -0,0 +1,141 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use std::fmt;
use glib::translate::from_glib;
use gst::prelude::*;
#[repr(transparent)]
#[doc(alias = "GESFrameCompositionMeta")]
pub struct FrameCompositionMeta(ffi::GESFrameCompositionMeta);
unsafe impl Send for FrameCompositionMeta {}
unsafe impl Sync for FrameCompositionMeta {}
impl FrameCompositionMeta {
#[inline]
pub fn alpha(&self) -> f64 {
self.0.alpha
}
#[inline]
pub fn position(&self) -> (i32, i32) {
(self.0.posx, self.0.posy)
}
#[inline]
pub fn pos_x(&self) -> i32 {
self.0.posx
}
#[inline]
pub fn pos_y(&self) -> i32 {
self.0.posy
}
#[inline]
pub fn size(&self) -> (i32, i32) {
(self.0.width, self.0.height)
}
#[inline]
pub fn width(&self) -> i32 {
self.0.width
}
#[inline]
pub fn height(&self) -> i32 {
self.0.height
}
#[inline]
pub fn zorder(&self) -> u32 {
self.0.zorder
}
#[inline]
pub fn operator(&self) -> i32 {
self.0.operator
}
}
unsafe impl MetaAPI for FrameCompositionMeta {
type GstType = ffi::GESFrameCompositionMeta;
#[doc(alias = "ges_frame_composition_meta_api_get_type")]
#[inline]
fn meta_api() -> glib::Type {
unsafe { from_glib(ffi::ges_frame_composition_meta_api_get_type()) }
}
}
impl fmt::Debug for FrameCompositionMeta {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("FrameCompositionMeta")
.field("pos-x", &self.pos_x())
.field("pos-y", &self.pos_y())
.field("width", &self.width())
.field("height", &self.height())
.field("zorder", &self.zorder())
.field("alpha", &self.alpha())
.field("operator", &self.operator())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn add_composition_meta(
buffer: &mut gst::BufferRef,
position: (i32, i32),
size: (i32, i32),
alpha: f64,
zorder: u32,
operator: i32,
) -> Result<gst::MetaRefMut<FrameCompositionMeta, gst::meta::Standalone>, glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
let meta = ffi::ges_buffer_add_frame_composition_meta(buffer.as_mut_ptr());
if meta.is_null() {
return Err(glib::bool_error!("Failed to add frame composition meta"));
}
let mut result = FrameCompositionMeta::from_mut_ptr(buffer, meta);
result.0.posx = position.0;
result.0.posy = position.1;
result.0.width = size.0;
result.0.height = size.1;
result.0.alpha = alpha;
result.0.zorder = zorder;
result.0.operator = operator;
Ok(result)
}
}
#[test]
fn test_add_get_meta() {
gst::init().unwrap();
crate::init().unwrap();
let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
{
let _meta =
add_composition_meta(buffer.get_mut().unwrap(), (42, 42), (20, 22), 0.42, 2, 42)
.unwrap();
}
{
let meta = buffer.meta::<FrameCompositionMeta>().unwrap();
assert_eq!(meta.position(), (42, 42));
assert_eq!(meta.size(), (20, 22));
assert_eq!(meta.alpha(), 0.42);
assert_eq!(meta.zorder(), 2);
assert_eq!(meta.operator(), 42);
}
}
}

View file

@ -56,6 +56,9 @@ macro_rules! skip_assert_initialized {
mod auto;
mod formatter;
pub use crate::auto::*;
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
mod composition_meta;
pub mod subclass;
#[cfg(feature = "serde")]
@ -74,5 +77,8 @@ pub mod prelude {
pub use gst_pbutils::prelude::*;
pub use crate::auto::traits::*;
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub use crate::composition_meta::FrameCompositionMeta;
pub use crate::formatter::FormatterExtManual;
}

View file

@ -7,22 +7,30 @@ libc = "0.2"
[dependencies.gio]
package = "gio-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.glib]
package = "glib-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gobject]
package = "gobject-sys"
git = "https://github.com/gtk-rs/gtk-rs-core"
branch = "0.18"
version = "0.18"
[dependencies.gst_pbutils]
package = "gstreamer-pbutils-sys"
path = "../../gstreamer-pbutils/sys"
version = "0.21"
[dependencies.gst]
package = "gstreamer-sys"
path = "../../gstreamer/sys"
version = "0.21"
[dev-dependencies]
shell-words = "1.0.0"
@ -49,7 +57,7 @@ license = "MIT"
name = "gstreamer-editing-services-sys"
readme = "README.md"
repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs"
version = "0.21.0"
version = "0.21.3"
edition = "2021"
rust-version = "1.70"

View file

@ -30,3 +30,10 @@ ignore = [
[external_libraries]
gstreamer="Gst"
gstreamer_pbutils="GstPbutils"
[[object]]
name = "GES.*"
status = "generate"
[[object.function]]
name = "frame_composition_meta_api_get_type"
version = "1.24"

View file

@ -1,3 +1,3 @@
Generated by gir (https://github.com/gtk-rs/gir @ 1d1ce102e130)
from gir-files (https://github.com/gtk-rs/gir-files @ 060b114d8edb)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 8ea27b3f0b33)
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

@ -868,6 +868,34 @@ pub struct _GESFormatterPrivate {
pub type GESFormatterPrivate = *mut _GESFormatterPrivate;
#[derive(Copy, Clone)]
#[repr(C)]
pub struct GESFrameCompositionMeta {
pub meta: gst::GstMeta,
pub alpha: c_double,
pub posx: c_int,
pub posy: c_int,
pub height: c_int,
pub width: c_int,
pub zorder: c_uint,
pub operator: c_int,
}
impl ::std::fmt::Debug for GESFrameCompositionMeta {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
f.debug_struct(&format!("GESFrameCompositionMeta @ {self:p}"))
.field("meta", &self.meta)
.field("alpha", &self.alpha)
.field("posx", &self.posx)
.field("posy", &self.posy)
.field("height", &self.height)
.field("width", &self.width)
.field("zorder", &self.zorder)
.field("operator", &self.operator)
.finish()
}
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct GESGroupClass {
@ -4395,10 +4423,18 @@ extern "C" {
// Other functions
//=========================================================================
pub fn ges_add_missing_uri_relocation_uri(uri: *const c_char, recurse: gboolean) -> gboolean;
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn ges_buffer_add_frame_composition_meta(
buffer: *mut gst::GstBuffer,
) -> *mut GESFrameCompositionMeta;
pub fn ges_deinit();
#[cfg(feature = "v1_18")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
pub fn ges_find_formatter_for_uri(uri: *const c_char) -> *mut GESAsset;
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub fn ges_frame_composition_meta_api_get_type() -> GType;
pub fn ges_init() -> gboolean;
pub fn ges_init_check(
argc: *mut c_int,

View file

@ -499,6 +499,13 @@ const RUST_LAYOUTS: &[(&str, Layout)] = &[
alignment: align_of::<GESFormatterClass>(),
},
),
(
"GESFrameCompositionMeta",
Layout {
size: size_of::<GESFrameCompositionMeta>(),
alignment: align_of::<GESFrameCompositionMeta>(),
},
),
(
"GESFrameNumber",
Layout {

View file

@ -51,6 +51,7 @@ int main() {
printf("%s;%zu;%zu\n", "GESExtractableInterface", sizeof(GESExtractableInterface), alignof(GESExtractableInterface));
printf("%s;%zu;%zu\n", "GESFormatter", sizeof(GESFormatter), alignof(GESFormatter));
printf("%s;%zu;%zu\n", "GESFormatterClass", sizeof(GESFormatterClass), alignof(GESFormatterClass));
printf("%s;%zu;%zu\n", "GESFrameCompositionMeta", sizeof(GESFrameCompositionMeta), alignof(GESFrameCompositionMeta));
printf("%s;%zu;%zu\n", "GESFrameNumber", sizeof(GESFrameNumber), alignof(GESFrameNumber));
printf("%s;%zu;%zu\n", "GESGroup", sizeof(GESGroup), alignof(GESGroup));
printf("%s;%zu;%zu\n", "GESGroupClass", sizeof(GESGroupClass), alignof(GESGroupClass));

View file

@ -1,6 +1,6 @@
[package]
name = "gstreamer-gl"
version = "0.21.0"
version = "0.21.3"
authors = [
"Sebastian Dröge <sebastian@centricular.com>",
"Víctor M. Jáquez L. <vjaquez@igalia.com>"
@ -18,11 +18,11 @@ rust-version = "1.70"
[dependencies]
libc = "0.2"
ffi = { package = "gstreamer-gl-sys", path = "sys" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../gstreamer" }
gst-base = { package = "gstreamer-base", path = "../gstreamer-base" }
gst-video = { package = "gstreamer-video", path = "../gstreamer-video" }
ffi = { package = "gstreamer-gl-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" }
gst-base = { package = "gstreamer-base", path = "../gstreamer-base", version = "0.21" }
gst-video = { package = "gstreamer-video", path = "../gstreamer-video", version = "0.21" }
serde = { version = "1.0", optional = true }
[dev-dependencies]

View file

@ -120,6 +120,12 @@ status = "generate"
[[object.function]]
name = "buffer_pool_config_set_gl_allocation_params"
ignore = true
[[object.function]]
name = "buffer_pool_config_get_gl_min_free_queue_size"
ignore = true
[[object.function]]
name = "buffer_pool_config_set_gl_min_free_queue_size"
ignore = true
# Needs manual binding to be an extension on gst_video::VideoAffineTransformationMeta
[[object.function]]
@ -340,7 +346,7 @@ status = "generate"
[[object.function]]
name = "get_handle"
# return handle
ignore = true
manual = true
[[object.function]]
name = "get_gl_context_for_thread"

1
gstreamer-gl/egl/COPYRIGHT Symbolic link
View file

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

View file

@ -1,6 +1,6 @@
[package]
name = "gstreamer-gl-egl"
version = "0.21.0"
version = "0.21.3"
authors = [
"Sebastian Dröge <sebastian@centricular.com>",
"Víctor M. Jáquez L. <vjaquez@igalia.com>"
@ -18,11 +18,11 @@ rust-version = "1.70"
[dependencies]
libc = "0.2"
ffi = { package = "gstreamer-gl-egl-sys", path = "sys" }
ffi = { package = "gstreamer-gl-egl-sys", path = "sys", version = "0.21" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../../gstreamer" }
gst-gl = { package = "gstreamer-gl", path = "../" }
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 = "../", version = "0.21" }
[dev-dependencies]
gir-format-check = "0.1"

View file

@ -59,3 +59,16 @@ status = "generate"
name = "new"
[object.function.return]
nullable_return_is_error = "Failed to create EGL display"
[[object.function]]
name = "new_with_egl_display"
manual = true
[[object.function]]
name = "get_from_native"
manual = true
[[object.function]]
name = "new_surfaceless"
[object.function.return]
nullable_return_is_error = "Failed to create surfaceless EGL display"

View file

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

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