Compare commits

...

291 commits
0.21.2 ... main

Author SHA1 Message Date
Sebastian Dröge 455996c60b rtsp-server: Fix compilation after from_glib_ptr_borrow() API improvements
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1440>
2024-05-10 10:35:19 +03:00
Sebastian Dröge 83fe420466 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1440>
2024-05-10 10:09:10 +03:00
Sebastian Dröge 5af4a262b8 Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1440>
2024-05-10 10:09:10 +03:00
Sebastian Dröge b8dbfc66ca pbutils: Remove unnecessary nullable override and add override for new API
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1440>
2024-05-10 10:09:10 +03:00
Sebastian Dröge b15e0e1633 Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1440>
2024-05-10 10:09:10 +03:00
Sebastian Dröge a430291725 Update gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1440>
2024-05-10 10:09:10 +03:00
Sebastian Dröge 0ee36ea4b5 ci: Update to rustup 1.27.1
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1440>
2024-05-10 10:09:07 +03:00
Sebastian Dröge a7a0bf226d ci: Update image version to rebuild it
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1440>
2024-05-10 10:09:07 +03:00
Naglis Jonaitis 19ea814a09 examples: Update playbin flag handling snippet
Closes #512

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1438>
2024-05-09 11:45:00 +03:00
Sebastian Dröge 2a9d0d035f Fix various new 1.78 clippy warnings
Quite a bit of API was accidentally not exported but apparently nobody
was using it.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1437>
2024-05-02 18:13:27 +03:00
Sebastian Dröge 1e293e5cb8 ci: Update to Rust 1.78.0
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1437>
2024-05-02 16:34:15 +03:00
Sebastian Dröge fe1fe5b114 gstreamer: Use a reference to a pointer of correct mutability for from_glib_ptr_borrow()
This hopefully makes it easier to use and harder to get the returned
lifetime wrong.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1436>
2024-04-30 15:39:15 +03:00
Sebastian Dröge 238768f525 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:36:37 +03:00
Sebastian Dröge 2f99c4c560 rtp: Only use glib::translate if 1.24 APIs are enabled
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:36:37 +03:00
Sebastian Dröge 9fca740851 ci: Run Linux clippy build with 1.26 APIs enabled
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:36:37 +03:00
Sebastian Dröge 9490735655 ci: Enable gstreamer-mpegts and gstreamer-tag on Windows
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:36:37 +03:00
Sebastian Dröge 81b20b9329 ci: Enable allocators, analytics, play, rtp and validate sys tests
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:36:37 +03:00
Sebastian Dröge ba4bd5c631 Add 1.26 version features and update 1.24 requirement from 1.23 to 1.24
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:36:37 +03:00
Sebastian Dröge 4b79dddc14 video: Remove some unnecessary #[cfg] attributes
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:36:37 +03:00
Sebastian Dröge 01b32ce143 video: Add double click mouse event
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:36:37 +03:00
Sebastian Dröge 873aeff133 Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:36:37 +03:00
Sebastian Dröge 87cc9fe6e4 Fix or update various overrides in Gir.toml
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:36:37 +03:00
Sebastian Dröge bac0828260 ci: Rebuild image to get latest GStreamer
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:29:04 +03:00
Sebastian Dröge 200d8b1c0c Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1435>
2024-04-30 12:29:04 +03:00
François Laignel dc04a53207 ci: test gstreamer-editing-services/sys
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1434>
2024-04-30 09:52:14 +02:00
François Laignel 0bb334e14c regen
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1434>
2024-04-30 09:52:12 +02:00
François Laignel 46226106b4 ges: ignore deprecated PitiviFormatter & PitiviFormatterClass
... they cause ABI tests failures and should be ignored.

See https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1425#note_2380648

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1434>
2024-04-30 09:51:35 +02:00
Nick Steel b7b5352353 log: Log trait adapter around the GStreamer debug system
Allows usage of normal `log` crate macros, and for other crates
using those macros to have their log messages go to the GStreamer
debug logs.

This implementation is based on the one found in Servo.

Fixes #187

DebugCategoryLogger is optional via 'log' feature
check category above threshold
skip_assert_initialized for constructor and helper

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1426>
2024-04-29 16:16:47 +01:00
Jordan Petridis 88a6977777 ci: Bump the image tag to rebuild
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1433>
2024-04-28 10:40:00 +03:00
Jordan Petridis cb560e59a3 ci: Move GST_UPSTREAM_BRANCH into the images_template.yml
Used for determining which version of gstreamer we will build
in the docker images. Move it along ther other variables so
it will be easier to update.

Also change ci/install-gst.sh to avoid hardoding the version
and instead use the variable like the windows build does.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1433>
2024-04-28 10:29:37 +03:00
Sebastian Dröge 241338f43c audio: video: Improve Display trait impl test for AudioFormat and Video a bit
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1432>
2024-04-27 16:10:49 +00:00
Sebastian Dröge 5c8a989029 video: Remove nonsensical test
Printing an unknown video format returns NULL, and with latest git main
this actually causes a critical warning in addition.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1432>
2024-04-27 16:10:49 +00:00
Sebastian Dröge 57050f66c6 Regenerate with latest gir / gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1429>
2024-04-27 11:31:11 +03:00
Sebastian Dröge 63654c67da Update gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1429>
2024-04-27 11:30:29 +03:00
Sebastian Dröge 70a15e8dbe Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1429>
2024-04-27 11:30:25 +03:00
François Laignel 953e3747f2 Pad: allow building a Pad with an automatically generated name
For convenience, the `Pad` builder checks a name is provided when a wildcard-
named template is used. For `GhostPad`s, the builder tries to assign the name of
the target `Pad` making sure the provided `name` conforms to the `PadTemplate`.

This commit adds a function to optionally keep the `gst::Object` automatically
generated unique `Pad` name (such as `ghostpad4`) and reorganises name handling
so it is processed when `build` is invoked.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1428>
2024-04-26 09:57:28 +00:00
Sebastian Dröge e117010bc0 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1427>
2024-04-25 12:05:49 +03:00
Sebastian Dröge 694d1fd39b examples: Update to windows 0.56
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1427>
2024-04-25 12:05:49 +03:00
François Laignel db03c8edd1 Add field_if_some setter for builder ClockTime fields
Optional `ClockTime` fields already implemented their setters in such a way
that they could accept either `Option<ClockTime>` or `ClockTime`. This commit
adds `field_if_some()` setter variants for builder `ClockTime` builder fields
for consistency with other builder fields.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1424>
2024-04-17 17:15:41 +02:00
François Laignel ea25c9262b Add field_if_some setter for builders
This commit adds `_if_some()` variants for builder field setters.
The variants aim at improving usability when setting optional fields.
E.g. currently, we need to write something like:

```rust
let opt_value = ...;
let mut sb = gst::Structure::builder("test")
    .field("mandatory_field", "mandatory");

if let Some(value) = opt_value
    sb = sb.field("optional_field", value);
}

let s = sb.build();
```

With `_if_some()`, this can be written like this:

```rust
let opt_value = ...;
let s = gst::Structure::builder("test")
    .field("mandatory_field", "mandatory")
    .field_if_some("optional_field", opt_value)
    .build();
```

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1424>
2024-04-17 17:15:39 +02:00
Sebastian Dröge 0d872ae6f8 ci: Update to Rust 1.77.2
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1422>
2024-04-10 09:00:24 +03:00
Sebastian Dröge 7433ea79c9 ci: Update image version to get a working libvpx on Windows 2024-04-09 12:19:14 +03:00
Sebastian Dröge 46be4a0b1e examples: Use safe RTSPMediaFactory role API
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1421>
2024-04-09 06:27:14 +00:00
Sebastian Dröge 43c82da25a rtsp-server: Add builder API for RTSPToken for consistency with Structure
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1421>
2024-04-09 06:27:14 +00:00
Sebastian Dröge da1f53f4c7 ci: tag linter and sanity check jobs as a "placeholder" jobs
They hardly use any resources and almost finish immediately.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1420>
2024-04-09 09:09:51 +03:00
Sebastian Dröge 0524435190 Update CHANGELOG.md for 0.22.4 2024-04-08 16:11:10 +03:00
Sebastian Dröge 917c458a86 ci: Rebuild image to get the flac plugin included on Windows too
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1418>
2024-04-08 08:58:28 +03:00
Sebastian Dröge 5eaa0ca46d Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1418>
2024-04-08 08:58:10 +03:00
Jordan Petridis 5400979e28 ci: Pin typos-cli to 1.19.0
New version includes false positives

https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1417#note_2358711

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1417>
2024-04-05 12:02:47 +03:00
Jordan Petridis c43c08804a typos.toml: Ignore anc and sys/tests
The tests are autogenerated

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1417>
2024-04-05 11:59:08 +03:00
Jordan Petridis a7ebe45ff3 ci: Add libflac in the debian image
So we can build flac elements.

Related: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1401
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1417>
2024-04-04 15:37:42 +03:00
Sebastian Dröge 2b53c55ee6 ci: Update to Rust 1.77.1
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1416>
2024-03-29 09:52:23 +02:00
Sebastian Dröge 04c840a1d9 mpegts: Always re-export the contents of the auto module
Pre-1.20 it currently has nothing to re-export and would cause clippy
warnings, but like this it won't be forgotten to update the conditions
if new API is added that is available from older versions.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1414>
2024-03-24 11:21:45 +02:00
Piotr Brzeziński 6111663e26 audio: Implement From/ToValue in Audio/VideoConverterConfig
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1408>
2024-03-22 17:16:48 +00:00
Piotr Brzeziński 7cea7ba6f1 examples: Add audiomixer example with mixing 4 stereo tracks into 8ch output
Will be useful to show how to create and set the mix-matrix via our bindings.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1408>
2024-03-22 17:16:48 +00:00
Philippe Normand e2e38d9494 Fix build warnings after update to Rust 1.77
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1413>
2024-03-21 15:44:46 +00:00
Philippe Normand 676e41064b Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1413>
2024-03-21 13:41:23 +00:00
Philippe Normand 4524af89ee ci: Update to Rust 1.77
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1413>
2024-03-21 13:40:49 +00:00
Philippe Normand e5830c2ea9 ci: Update to dav1d >= 1.3.0
This is going to be needed for:
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1507

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1413>
2024-03-21 13:40:29 +00:00
Sebastian Dröge d7fe0709a5 ci: Rebuild image to get fixes for the Windows gst-plugins-rs CI
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1412>
2024-03-20 10:49:09 +02:00
Sebastian Dröge 983e8b3308 Update CHANGELOG.md for 0.22.3 2024-03-19 18:13:28 +02:00
Olivier Crête 6aff1773bd video_meta: Rename transformation to scale
This transformation is really only for scaling for now, so let's
make it clearer in the bindings.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1397>
2024-03-19 14:44:57 +00:00
Sebastian Dröge ebc06257b5 ci: Rebuild image to pull in the GES fixes
And follow the 1.24 branch of GStreamer for now.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1410>
2024-03-19 09:57:38 +02:00
Sebastian Dröge 86d02890ca Regenerate with latest gir / gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1410>
2024-03-19 09:57:38 +02:00
Sebastian Dröge 29c82cd54d Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1410>
2024-03-19 09:57:38 +02:00
Michiel Westerbeek c05563d22e ges: framepositioner: Make positioning properties doubles
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1410>
2024-03-19 09:57:37 +02:00
Sebastian Dröge 9e80250b49 Use 0.19 branches of gir / gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1410>
2024-03-19 09:57:37 +02:00
Sebastian Dröge 0b027c853b Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1410>
2024-03-19 09:57:37 +02:00
Olivier Crête 3246f4fb5b analytics: Allow empty object type
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1407>
2024-03-13 13:52:37 +00:00
François Laignel 82f6accc31 webrtc: SessionDescription: access the inner SDPMessage as & or &mut
`WebRTCSessionDescription` owns its `SDPMessage`. The `sdp()` accessor used to
return a copy of the `SDPMessage` which prevented the user from getting a ref
and by extension from getting a mutable ref for in-place modification.

This commit makes the accessor return a reference to the inner `SDPMessage` and
adds a mutable accessor.

Previous behaviour (getting an owned copy of the `SDPMessage`) is available by
calling `to_owned()` on the reference returned by `sdp()`.

Users who wish to change the type of `WebRTCSessionDescription` can call
`set_type()`.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1406>
2024-03-11 13:03:26 +01:00
François Laignel ffad1188b9 net: fix faillible PtpClock::new()
`PtpClock::new()` can fail in which case it panicked due to an assertion
failure. This commit makes it return a `Result` instead.

Also sets the `name` argument optional, similar to what is done for `NtpClock`.

See also: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6251

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1405>
2024-03-01 17:39:39 +01:00
Dave Patrick Caberto 353e3d1611 fraction: refer to numer and denom more consistently
This also lessens the tendency to confuse num with number.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1404>
2024-03-01 18:30:19 +08:00
Dave Patrick Caberto b5cb4ae831 fraction: add const new_raw and from_integer methods
These are direct counterparts to their respective Rational32 constructors.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1404>
2024-03-01 18:28:39 +08:00
Sebastian Dröge 14576fdf26 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1403>
2024-02-29 11:32:12 +02:00
Sebastian Dröge 70045a36fb examples: Update to windows 0.54
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1403>
2024-02-29 11:31:26 +02:00
Sebastian Dröge 28451435a4 Update CHANGELOG.md for 0.22.2 2024-02-26 14:50:48 +02:00
Sebastian Dröge fcc7ab6b88 Update CHANGELOG.md for 0.22.1 2024-02-26 14:08:30 +02:00
Sebastian Dröge 18a02f6d34 gstreamer: Update serde flags tests for new ObjectFlags
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1401>
2024-02-26 11:29:19 +00:00
Sebastian Dröge c5111ddcc2 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1401>
2024-02-26 11:29:19 +00:00
Sebastian Dröge d5917be045 Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1401>
2024-02-26 11:29:19 +00:00
Sebastian Dröge 4e6ddf6663 rtp: Add bindings for new RTPBaseDepayload::extensions() property
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1401>
2024-02-26 11:29:19 +00:00
Sebastian Dröge ab0a29b765 Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1401>
2024-02-26 11:29:19 +00:00
Guillaume Desmottes 8062a8748f ci: rebuild images to update GStreamer
Pick GStreamer 1.23.90 as it requires to build the new uriplaylistbin
version, see https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/1471

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1400>
2024-02-26 09:09:00 +01:00
Sebastian Dröge 28fe70f479 rtpheaderextension: Don't pass a mutable output buffer reference to write()
The extension is only supposed to use it for potentially reading metas
from it, and `GstRTPBasePay` is currently passing the same buffer as the
one that owns the data so we currently end up with the possibility to
e.g. resize the buffer which would invalidate the data.

This change prevents at least the biggest problems, but would still
allow getting an immutable and mutable reference to the same data with a
bit of effort.

See also https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/375

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1399>
2024-02-22 12:17:13 +02:00
Sebastian Dröge c8b98dde8c gstreamer: bus: Handle all previously queued messages too in the BusStream
Before the stream was created, some messages might've been queued on the
bus. For more similar behaviour with the bus watch, first pop all the
queued messages before handling new messages.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1398>
2024-02-21 12:09:14 +02:00
Olivier Crête b47aba1837 video_meta: Add a safe wrapper for the VIDEO_TRANSFORM of metas
With a test

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1388>
2024-02-16 14:28:26 -05:00
Olivier Crête 28931e2f09 meta: Make a generic transform method with a specific trait for each transform
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1388>
2024-02-16 14:28:26 -05:00
Sebastian Dröge 1649e268c5 rtp: Add gst::Object as parent class to the various types
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1396>
2024-02-16 19:49:16 +02:00
Sebastian Dröge d575cd1f95 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1395>
2024-02-16 14:24:32 +02:00
Sebastian Dröge ac275fe10e Remove Cargo.lock from .gitignore
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1395>
2024-02-16 14:24:32 +02:00
Olivier Crête b10f395c2c meta: Add modules containing the tags
Export the tags as both quark or string

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1387>
2024-02-16 08:59:36 +00:00
Benjamin Gaignard 22796cee0c meta: Add is_registered function for CustomMeta
Test if a Meta type is already registered.
It is useful to know if a custom metadata type has already
been registed to avoid registererd twice and get asserts.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1391>
2024-02-13 08:21:38 +00:00
Sebastian Dröge 7f9dd58718 video: Add AncillaryMeta bindings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1393>
2024-02-12 16:54:19 +02:00
Sebastian Dröge 798ee29b98 structure: Call _full() serialize function for GST_SERIALIZE_FLAG_STRICT
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1393>
2024-02-12 16:10:24 +02:00
Sebastian Dröge 040a194700 tags: Add new ContainerSpecificTrackId tag
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1393>
2024-02-12 16:09:28 +02:00
Sebastian Dröge b69fee9abe Regenerate with new GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1393>
2024-02-12 16:06:44 +02:00
Sebastian Dröge a87a844604 ci: Rebuild image to get new GStreamer version
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1393>
2024-02-12 16:05:41 +02:00
Sebastian Dröge 5d19b26974 Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1393>
2024-02-12 16:05:14 +02:00
Benjamin Gaignard 2613c57739 analytics: Make AnalyticsODLocation members public
Get access to AnalyticsODLocation structure members outside
the module is useful if other elements need them.
For example it can be used to draw objects location.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1389>
2024-02-09 15:35:32 +00:00
Sebastian Dröge f82b9cc197 meta: Add support for 1.24 Meta clear function
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1390>
2024-02-09 10:25:32 +02:00
Sebastian Dröge 12c9ada9e0 meta: Fix MetaRefMut::upcast_mut() to return a mutable reference
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1390>
2024-02-09 10:24:40 +02:00
Sebastian Dröge a784ea2d0b ci: Update to Rust 1.76
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1386>
2024-02-08 17:46:08 +02:00
Sebastian Dröge 90e6108ed7 gstreamer-tag: Reduce number of keywords 2024-02-08 15:37:44 +02:00
Sebastian Dröge 77b2800caf Publish docs for 0.22 release 2024-02-08 15:24:21 +02:00
Sebastian Dröge c4636fc0cd Update Cargo.lock 2024-02-08 15:01:11 +02:00
Sebastian Dröge 6a1441203d Update versions to 0.23.0 2024-02-08 14:47:20 +02:00
Sebastian Dröge 811e564ff9 examples: Move some more gtk-rs-core dependencies to the workspace 2024-02-08 14:39:58 +02:00
Sebastian Dröge 0eacca7102 Use workspace features for crates metadata in remaining crates 2024-02-08 14:30:43 +02:00
Sebastian Dröge aab36d9745 Update CHANGELOG.md for 0.22.0 2024-02-08 14:27:28 +02:00
Sebastian Dröge d96dbef08c ci: Update image version
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1358>
2024-02-07 18:26:46 +02:00
Olivier Crête 7ec3c8713a analytics: Add bindings for apps/plugins
The whole API to use the Analytics meta is implemented.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1358>
2024-02-07 12:21:54 +02:00
Sebastian Dröge 36792404a9 ci: Don't install cargo-c with --locked on nightly for now
Otherwise a version of ahash is used that doesn't build on nightly anymore.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1385>
2024-02-06 10:39:23 +02:00
Sebastian Dröge ebc18ea0b8 deny: Add override for duplicated toml_edit dependency
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1385>
2024-02-06 10:29:12 +02:00
Sebastian Dröge 9cf270611f Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1385>
2024-02-06 10:28:23 +02:00
Sebastian Dröge 79846af1e6 ci: Rebuild image to update GStreamer
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1385>
2024-02-06 09:55:43 +02:00
Sebastian Dröge 90bb9182c2 Regenerate with latest gir / gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1385>
2024-02-06 09:55:42 +02:00
Sebastian Dröge a3b3017d75 gstreamer: Re-export / manually implement new standalone functions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1385>
2024-02-06 09:55:42 +02:00
Sebastian Dröge e16832a2a8 gstreamer: Update configuration for new standalone functions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1385>
2024-02-06 09:52:57 +02:00
Sebastian Dröge a165f1aa96 Update gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1385>
2024-02-06 09:45:02 +02:00
Sebastian Dröge e192eac554 Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1385>
2024-02-06 09:44:51 +02:00
Sebastian Dröge a31940a916 Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1385>
2024-02-06 09:44:16 +02:00
Martin Robinson 230c906626 Make use of feature(doc_cfg) conditional on docsrs consistently
`feature(doc_cfg)` is turned on conditionally if `docsrs` is true in
most of the source code, but in some cases this isn't the case. This
change makes that consistent everywhere, fixing the doc build on stable
Rust.

Fixes #506.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1381>
2024-02-05 10:57:59 +00:00
Sebastian Dröge fde0c061c2 Switch git dependencies to explicitly name branch
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1384>
2024-02-05 12:29:46 +02:00
Sebastian Dröge a51b5bdfd3 Fix a new clippy warning
warning: this bound is already specified as the supertrait of `FusedStream`
   --> gstreamer/src/bus.rs:314:15
    |
314 |     ) -> impl Stream<Item = Message> + Unpin + FusedStream + Send + 'a {
    |               ^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#implied_bounds_in_impls
    = note: `#[warn(clippy::implied_bounds_in_impls)]` on by default
help: try removing this bound
    |
314 -     ) -> impl Stream<Item = Message> + Unpin + FusedStream + Send + 'a {
314 +     ) -> impl Unpin + FusedStream<Item = Message> + Send + 'a {
    |

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1383>
2024-02-05 12:07:15 +02:00
Sebastian Dröge 8230a7ccba Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1383>
2024-02-05 12:04:39 +02:00
Bilal Elmoussaoui 2dff5b8ae2 Use workspace features for common deps
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1382>
2024-02-03 10:48:37 +01:00
Bilal Elmoussaoui 14ffbfbe83 Use workspace features for crates metadata
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1382>
2024-02-03 10:48:37 +01:00
Bilal Elmoussaoui 771dbb4ed5 webrtc: Add missing gst dependency
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1382>
2024-02-03 10:48:37 +01:00
Bilal Elmoussaoui aaea288abf Adapt to no longer re-exported traits
Some of the traits were moved to prelude or translate
and no longer in the main scope of the crate

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1382>
2024-02-03 10:48:37 +01:00
Bilal Elmoussaoui cfc1aed3c3 Adapt to renamed ffi crates
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1382>
2024-02-03 08:56:45 +01:00
Bilal Elmoussaoui ba91648bd5 Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1382>
2024-02-03 08:48:44 +01:00
Bilal Elmoussaoui 95c00c4a5c Update gir submodule
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1382>
2024-02-03 08:47:01 +01:00
Sebastian Dröge 193bcbf055 Switch from once_cell to std::sync::OnceLock where it makes sense
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1379>
2024-01-31 14:59:54 +02:00
Sebastian Dröge ce5dca918d examples: Update to termion 3
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1379>
2024-01-31 14:48:32 +02:00
Sebastian Dröge e6ce8e4f71 deny: Remove unnecessary overrides
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1379>
2024-01-31 14:48:32 +02:00
Sebastian Dröge a83680ffeb Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1379>
2024-01-31 14:48:32 +02:00
Olivier Crête e13e9a7a7f Regenerate with updated generator
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1380>
2024-01-29 18:30:49 -05:00
Piotr Brzeziński 446bb7ec3e examples/tutorials: fix macOS run() wrapper terminating too early
Using terminate() kills the whole process instead of just stopping the event loop, so we're back to the 'old' way.
However, if the provided function finishes too early, that can also fail (will call stop() on a not-yet-running NSApp).
Creating a delegate and waiting for the callback makes sure NSApp is running before the actual main() is called.

Also, for whatever reason only tutorials were changed to use terminate(). Now both tutorials and examples are
using identical code.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1378>
2024-01-29 14:15:19 +00:00
Piotr Brzeziński 047f4a3f75 gstreamer: add gst_macos_main()
Unlike the C version, this allows for any arbitrary type of return value.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1377>
2024-01-29 13:55:16 +01:00
Sebastian Dröge c376bfac4d rtp: Add RTPSourceMeta bindings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1376>
2024-01-15 19:04:09 +02:00
Jonas K Danielsson 6cea21617c gstreamer-video: Add VideoSeiUserDataUnregisteredMeta
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1375>
2024-01-08 13:11:55 +02:00
Sebastian Dröge c5357064cf ci: Update to Rust 1.75
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1371>
2024-01-07 11:17:47 +02:00
Sebastian Dröge b5c7c402b9 Add MiniObject::from_glib_ptr_borrow()
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1374>
2024-01-05 22:29:43 +02:00
Sebastian Dröge e35782a3a4 Add accessor for owned Buffer to read-mapped AudioBuffer / MappedBuffer
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1374>
2024-01-05 22:29:37 +02:00
Sebastian Dröge 92064a0c41 Remove &mut BufferRef getter from write-mapped AudioBuffer / VideoFrame
This allows invalidating the buffer map.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1374>
2024-01-05 22:27:07 +02:00
Sebastian Dröge c66fc90566 Add accessors for various base class fields
And fix some other existing accessors to use the correct mutex.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1373>
2024-01-05 15:56:19 +02:00
Sebastian Dröge 0b4c602c6f Provide a more convenient function for setting other fields on message/event builders
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1372>
2023-12-31 15:53:10 +02:00
Sebastian Dröge 3b3c3baee5 Fix / work around a few new clippy 1.75 warnings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1370>
2023-12-22 16:33:41 +02:00
Sebastian Dröge 5fe76aa785 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1369>
2023-12-22 15:10:36 +02:00
Sebastian Dröge 5f01bcf8f4 buffer: Fix range end calculations
And add various tests to cover for this.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1369>
2023-12-22 15:09:31 +02:00
olivierbabasse 60e8c44abb rtsp server: allow custom authentication
Enables subclassing gst_rtsp_server::RTSPAuth and overriding its
authenticate/check/generate_authenticate_header methods

Also add new methods in RTSPContext to retrieve RTSP request/response, and to
get/replace tokens.

Additionally, added RTSPMessage with methods to add an authentication
header to a request / retrieve authentication parameters from a
response.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1359>
2023-12-22 12:12:17 +02:00
Sebastian Dröge 08fa853c7e ci: Update image version again
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1368>
2023-12-21 14:10:41 +02:00
Nirbheek Chauhan 52c764b986 ci: Fix pwsh scripts not exiting on error
We all know that external utilities returning a non-zero exit code do
not terminate a powershell script. However, most do not know (and
neither did I) that it is impossible to promote error exit codes to
script-terminating errors with ErrorActionPreference.

Explicitly check the return codes and Exit.

https://github.com/MicrosoftDocs/PowerShell-Docs/issues/1583

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1368>
2023-12-21 14:10:41 +02:00
Sebastian Dröge b5f4246445 ci: Use cargo install --locked to make sure to not use too new dependency versions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1368>
2023-12-21 14:10:41 +02:00
Sebastian Dröge ea002e2e11 ci: Update to Rust 1.74.1
And rebuild image for newer GStreamer version.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1368>
2023-12-21 14:10:41 +02:00
Sebastian Dröge dae3d30fae play: Add bindings for new pipeline-dump-in-error-details config
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1368>
2023-12-21 14:10:41 +02:00
Sebastian Dröge 52bd716a80 meta: Add support for (de)serializing metas
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1368>
2023-12-21 13:47:11 +02:00
Sebastian Dröge 26611a66bd Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1368>
2023-12-21 13:47:11 +02:00
Sebastian Dröge 003ebbdf1c structure: Manually bind GST_SERIALIZE_FLAG_STRICT
As the flag changes the nullability of `gst_structure_serialize()` and
adding a new C function is apparently too much of a hassle for C
developers, add a new `serialize_strict()` function here that always
sets this flag and can fail.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1368>
2023-12-21 13:47:11 +02:00
Sebastian Dröge 0533160d94 rtp: Add support for new RTPBasePayload::extensions property
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1368>
2023-12-21 13:47:11 +02:00
Sebastian Dröge dff595193d Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1368>
2023-12-21 13:47:11 +02:00
Sebastian Dröge 86cf7a7d81 audio: Add array-based accessor for all audio buffer planes' data at once
This is mostly useful for getting mutable access to all planes at once.

Using `plane_data_mut()` for this is not possible as it would require
borrowing the frame mutably multiple times.

As each plane's data is not overlapping with any other plane we can
still provide such functionality safely.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1367>
2023-12-19 10:29:01 +02:00
Sebastian Dröge 38a9b7a242 video: Add array-based accessor for all video frame planes' data at once
This is mostly useful for getting mutable access to all planes at once.

Using `plane_data_mut()` for this is not possible as it would require
borrowing the frame mutably multiple times.

As each plane's data is not overlapping with any other plane we can
still provide such functionality safely.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1367>
2023-12-19 10:14:23 +02:00
Sebastian Dröge 2fb93e1c12 Update CHANGELOG.md for 0.21.3 2023-12-18 11:07:55 +02:00
Sebastian Dröge 8b9862052b gstreamer: memory: Simplify and correct offset/size calculations in mem_share()
This is all supposed to do unsigned wrapping arithmetic to calculate the
new offsets and sizes, despite input parameters being signed integers.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1363>
2023-12-17 13:15:55 +02:00
Sebastian Dröge 5c88bd0b5f gstreamer: memory: Use ranges instead of offset/size parameter pairs
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/497

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1363>
2023-12-17 13:15:38 +02:00
Sebastian Dröge 96de51a7b7 gstreamer: buffer: Use ranges instead of offset/length parameter pairs
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/497

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1363>
2023-12-17 11:41:01 +02:00
Sebastian Dröge cd30854c2b gstreamer: memory: Fix assertions for copy_range/resize/share functions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1363>
2023-12-17 11:37:58 +02:00
Sebastian Dröge 33e3e25b49 gstreamer: buffer: Add bindings for Buffer::map_range_readable() and _writable()
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/496

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1363>
2023-12-17 11:37:56 +02:00
Olivier Crête 248b6d2f31 gstreamer: meta: Implement Clone trait on MetaRef
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1365>
2023-12-13 18:05:27 -05:00
Sebastian Dröge 2139f368e9 gstreamer: buffer: Add Buffer::dump() and Buffer::dump_range()
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/495

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1362>
2023-12-11 18:34:13 +02:00
Sebastian Dröge e72a3bfc8d gstreamer: Improve support for dumping memories and add same functionality to byte slices
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1362>
2023-12-11 16:05:34 +00:00
Sebastian Dröge 34fee6b691 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/1364>
2023-12-10 20:49:17 +02:00
Sebastian Dröge fddeacc358 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1361>
2023-12-09 12:14:28 +02:00
Sebastian Dröge 5d8652e872 Update to pretty-hex 0.4
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1361>
2023-12-09 12:13:42 +02:00
Sebastian Dröge 3daab0112d examples: Add a few more docs/comments to the subclass/virtual methods example
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1360>
2023-12-09 11:58:14 +02:00
Sebastian Dröge 0ec7b2608c examples: Add an example that shows how to write subclasses with virtual methods
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1356>
2023-12-05 11:20:24 +02:00
Sebastian Dröge 84ca72a833 gstreamer: audiofilter: Add parent_allowed_caps()
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1356>
2023-12-05 11:20:24 +02:00
Sebastian Dröge ceed45cfd7 gstreamer: Optimize Buffer / Memory from_slice() to have fewer allocations
Instead of using `gst_memory_new_wrapped_full()` and boxing the data,
create an GstAllocator subclass that allows allocating memories that
store the data inline.

By avoiding the box, one additional heap allocation per memory is
avoided.

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

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1357>
2023-12-05 10:51:28 +02:00
Guillaume Desmottes a29d7c0e19 gstreamer: rename util_get_timestamp() to get_timestamp()
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1355>
2023-12-04 17:07:21 +01:00
Guillaume Desmottes f055c113ac streamer: do not publicly import functions
All the functions are re-exported in the root crate.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1355>
2023-12-04 16:15:51 +01:00
Guillaume Desmottes 9bcf48050b gstreamer: move update_registry() as Registry method
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1355>
2023-12-04 16:15:51 +01:00
Guillaume Desmottes a649e7dead gstreamer: move parse_* functions to their own module
Better namespacing so the API is more Rust-y.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1355>
2023-12-04 16:15:51 +01:00
Guillaume Desmottes f255b82b55 gstreamer: move debug_* functions to their own module
Better namespacing so the API is more Rust-y.

Fix #500

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1355>
2023-12-04 12:46:59 +01:00
Dave Patrick Caberto 7f234c88ac pbutils: make element_properties mod public
This makes the builders accessible/nameable.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1354>
2023-11-29 19:32:44 +08:00
Sebastian Dröge 59420b1590 Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1353>
2023-11-29 11:59:03 +02:00
Sebastian Dröge a05e3fed14 Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1353>
2023-11-29 11:58:35 +02:00
Sebastian Dröge ca8309a5dd Simplify various raw pointer casts everywhere
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1353>
2023-11-29 11:24:47 +02:00
Sebastian Dröge 897c7dfd39 gstreamer: Remove deprecated APIs
They were deprecated in the previous release or even older releases.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1352>
2023-11-23 13:38:16 +02:00
Sebastian Dröge c82ba6ffe0 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1351>
2023-11-17 10:58:50 +02:00
Sebastian Dröge e56061c25e examples: Update to windows 0.52
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1351>
2023-11-17 10:58:40 +02:00
Sebastian Dröge 4c3de8b80e Update versions of all autogenerated files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1348>
2023-11-16 20:53:08 +02:00
Sebastian Dröge db2028c4c5 net: Add new PtpClock::init_full() function
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1348>
2023-11-16 20:53:08 +02:00
Philippe Normand 9ab8dee59c gstreamer-editing-services: Add bindings for FrameCompositionMeta
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1348>
2023-11-16 20:53:08 +02:00
Philippe Normand 6371b82c48 gst-gir-files: Update submodule for GES FrameCompositionMeta
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1348>
2023-11-16 19:47:58 +02:00
Bilal Elmoussaoui 9617731206 ci/docs: Add missing cfg docsrs
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1350>
2023-11-16 17:29:36 +00:00
Sebastian Dröge 53f1ab938e ci: Update to Rust 1.74
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1349>
2023-11-16 16:42:08 +02:00
Sebastian Dröge 6cb371d3e5 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1347>
2023-11-15 17:17:52 +02:00
Sebastian Dröge 1946973c25 Update to itertool 0.12
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1347>
2023-11-15 16:53:20 +02:00
Sebastian Dröge c4413f1db7 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/1346>
2023-11-14 09:36:58 +02:00
Sebastian Dröge 3ac254d34c gstreamer: pad: Remove "caps" property getter
Only only leave the notify signal connection function. The property
getter is the same as `current_caps()`, which is more lightweight.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1345>
2023-11-11 19:21:20 +02:00
Sebastian Dröge 30d8a7893b Update CHANGELOG.md for 0.21.2 2023-11-11 15:57:11 +02:00
Sebastian Dröge 4c6bb9eefa allocators: Ignore init_once() function correctly 2023-11-11 11:43:17 +02:00
Sebastian Dröge 39b472ce8b gl: Update serde serialization tests for new flags/enum variants
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1343>
2023-11-10 17:19:20 +02:00
Sebastian Dröge 9bc2a3dbf5 ci: Update image version for rebuild
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1343>
2023-11-10 16:51:05 +02:00
Sebastian Dröge 9419730ea4 video: Add VIDEO_FORMATS_ANY and iterator over the formats
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1343>
2023-11-10 16:51:05 +02:00
Sebastian Dröge ec3a3610d3 allocator: Generate new ShmAllocator
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1343>
2023-11-10 16:51:05 +02:00
Sebastian Dröge 6403d3c0ee Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1343>
2023-11-10 16:51:04 +02:00
Sebastian Dröge b8fff2d6fc Update some Gir.toml configuration
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1343>
2023-11-10 16:50:55 +02:00
Sebastian Dröge 7cabb4f22c Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1343>
2023-11-10 16:50:43 +02:00
Marijn Suijten bf568714b6 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/1336>
2023-11-10 15:47:20 +02:00
Marijn Suijten 73180e530b 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/1336>
2023-11-10 12:57:16 +01:00
Marijn Suijten 5fdd56747f 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/1336>
2023-11-10 12:57:16 +01:00
Marijn Suijten 0f3d2d6d09 examples/glupload: Sanity-check that the EGL display via Wayland equals glutin
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1336>
2023-11-10 12:53:08 +01:00
Marijn Suijten ce98a4755e 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/1336>
2023-11-10 12:53:08 +01:00
Marijn Suijten 1ec4560b62 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/1336>
2023-11-10 12:53:08 +01:00
Marijn Suijten 5741b6a52e 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/1336>
2023-11-10 12:53:08 +01:00
Sebastian Dröge 5ee8ee8545 utils: streamproducer: Don't use gst_element_send_event() in another place
It can cause deadlocks thanks to taking the state lock.
2023-11-10 09:45:09 +02:00
Sebastian Dröge 754b6487d4 ci: Run cargo update as part of the cargo deny / cargo outdated jobs 2023-11-10 08:56:32 +02:00
Sebastian Dröge 41519511aa Add Cargo.lock to the repository
This makes sure that any broken dependency updates are not breaking our
build, at the cost of requiring us to update the lock file regularly.

See also https://blog.rust-lang.org/2023/08/29/committing-lockfiles.html

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1340>
2023-11-09 10:07:47 +02:00
Sebastian Dröge 3051401aa4 deny: Add override for duplicated toml_edit dependency
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1340>
2023-11-09 10:03:23 +02:00
Sebastian Dröge 4b3d9f586e 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/1339>
2023-11-07 10:43:20 +02:00
Sebastian Dröge f471501df5 gstreamer: meta: Add MetaRef::copy() for copying a meta between buffers
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1338>
2023-11-03 11:55:20 +02:00
Sebastian Dröge eb6d3a6c6c 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/1338>
2023-11-03 11:49:41 +02:00
Sebastian Dröge 86d470e82c 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/1338>
2023-11-03 11:48:23 +02:00
Sebastian Dröge e84af103a1 Regenerate with latest gir / gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1335>
2023-11-02 15:09:20 +02:00
Sebastian Dröge 339bec6aef Update gir / gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1335>
2023-11-02 15:08:17 +02:00
Fabian Orccon b901322c46 gstreamer: rank: Do not implement gst::Rank as enum
Rank is not limited to known types like GST_RANK_NONE,
GST_RANK_MARGINAL, GST_RANK_SECONDARY and GST_RANK_PRIMARY, but it
can be whatever arbitrary number.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1327>
2023-11-02 13:32:00 +02:00
Sebastian Dröge 4a015d94af Use let-else instead of match for weak reference upgrades
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1333>
2023-10-30 11:00:58 +02:00
Sebastian Dröge fc4a0d29c6 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/1333>
2023-10-30 11:00:58 +02:00
Marc Wiblishauser 130dc49b22 gstreamer-tag: Introduce gstreamer-tag
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1330>
2023-10-27 13:27:26 +03:00
Sebastian Dröge bd4122e334 gstreamer: error: Allow using variable expansion in loggable_error! macro
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/490

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1332>
2023-10-26 11:49:58 +00:00
Sebastian Dröge bd9b1d6e38 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/1331>
2023-10-26 13:41:50 +03:00
Sebastian Dröge a26fcaf0ad 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/1331>
2023-10-26 13:41:50 +03:00
Sebastian Dröge 16acea71d4 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/1331>
2023-10-26 13:41:47 +03:00
Sebastian Dröge d5ba6c1336 gstreamer: meta: Add some more AsRef and AsMut impls
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1331>
2023-10-26 13:38:07 +03:00
Sebastian Dröge 4d19d7b0b6 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/1329>
2023-10-25 12:09:45 +03:00
Sebastian Dröge 414019af21 gstreamer: Implement Default trait for AllocationParams
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1328>
2023-10-24 15:04:14 +00:00
François Laignel a41dc25eba video: fix big endian video format order
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1326>
2023-10-22 18:24:39 +02:00
Sebastian Dröge a04ed127af gstreamer: Fix API typo in owned ReferenceTimestampMeta reference getter
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1325>
2023-10-16 15:45:12 +03:00
Sebastian Dröge 5312131069 gstreamer: Simplify MetaAPIExt trait implementation
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1325>
2023-10-16 15:19:52 +03:00
Sebastian Dröge 62f58620b7 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/1324>
2023-10-16 11:28:18 +03:00
François Laignel 4c8d16d09e video: fix visibility for VideoVBIEncoder::try_new
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1323>
2023-10-11 17:53:43 +02:00
Sebastian Dröge 547cfb44e2 gstreamer: Simplify Element::element_class() implementation a bit
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1322>
2023-10-11 16:06:20 +03:00
Sebastian Dröge 3f16233a01 gstreamer: Add DeviceProviderClassExt extension trait for class methods
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1322>
2023-10-11 16:06:16 +03:00
Bilal Elmoussaoui 27a0bc5af0 docs/gstreamer: Embed docs for ElementClass functions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1322>
2023-10-11 12:49:51 +00:00
François Laignel abdd4df415 gst-video: bindings for VideoVBIEncoder & VideoVBIParser
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1319>
2023-10-09 18:21:16 +00:00
François Laignel b158ca83f9 gst-video: generate vertical blanking interval related bindings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1319>
2023-10-09 18:21:16 +00:00
Sebastian Dröge a2387d1f84 examples: Updates to memmap2 0.9
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1321>
2023-10-06 09:08:29 +03:00
Sebastian Dröge 8df470b85c ci: Update to Rust 1.73
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1320>
2023-10-06 00:15:45 +03:00
Sebastian Dröge b42b01ba86 Update CHANGELOG.md for 0.21.1 2023-10-04 13:30:40 +03:00
Sebastian Dröge 3a5f69b64c gl: Don't autogenerate GL buffer pool configuration functions
These need manual bindings.
2023-10-04 10:22:03 +03:00
Sebastian Dröge a6470f13c9 Fix various new 1.73 clippy warnings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1317>
2023-10-03 17:44:12 +03:00
Guillaume Desmottes 7bde0285ff 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/1316>
2023-10-03 11:45:51 +02:00
Sebastian Dröge d7494bf1db 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/1310>
2023-10-02 19:50:41 +03:00
Sebastian Dröge fa3ce573d7 app: Add max-bytes and max-time setters to the AppSink builder
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1310>
2023-10-02 19:49:10 +03:00
Sebastian Dröge 44602238d9 Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1310>
2023-10-02 19:44:35 +03:00
Sebastian Dröge c0696d872d Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1310>
2023-10-02 19:43:18 +03:00
Sebastian Dröge 635b31614c video: Fix ordering of video formats according to latest libgstvideo
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1310>
2023-10-02 19:39:46 +03:00
Sebastian Dröge 72a5b1bdb9 ci: Update to Rust 1.72.1
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1310>
2023-10-02 19:39:46 +03:00
Anders Hellerup Madsen 3e5316c869 gl: implement Debug for GL video frames
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1312>
2023-10-02 11:33:57 +02:00
Anders Hellerup Madsen f8effdda61 gl: export GLMemory getter methods on GLVideoFrame
also change `as_non_null_ptr()` to `as_raw()`

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1312>
2023-10-02 11:33:57 +02:00
Anders Hellerup Madsen 6eb01dc916 video_frame: refactor traits
this adds an IsVideoFrame trait that makes it easier to provide all the
shared methods between VideoFrame, VideoFrameRef, GLVideoFrame and
GLVideoFrameRef. Now only a single method, `as_non_null_ptr()` has to be
implemented and the rest of the shared methods will be provided by the
`VideoFrameExt` trait.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1312>
2023-10-02 11:33:57 +02:00
Anders Hellerup Madsen 61d559521b gl: add memory access functions to GLVideoFrame
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1312>
2023-10-02 11:33:57 +02:00
Anders Hellerup Madsen e8387bf4cf gl: support for writable GLVideoFrame
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1312>
2023-10-02 11:33:57 +02:00
Anders Hellerup Madsen 4957921cfa gl: reimplement gl video frame support
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1312>
2023-10-02 11:33:57 +02:00
Anders Hellerup Madsen 2a00236a1f video: extract common videoframe methods to trait
In preparation to make a more specialized VideoFrameGL this extracts
common helper functions valid for all VideoFrames into a trait that can
be implemented without too much code duplication.

Note that this is a breaking change, now VideoFrame and VideoFrameRef
cannot really be used without include the gst_video prelude.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1312>
2023-10-02 11:33:54 +02:00
Anders Hellerup Madsen 8e3994f641 gl: wrapper for gst_gl_framebuffer_draw_to_texture
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1314>
2023-09-29 07:07:43 +00:00
Anders Hellerup Madsen c071d8cba7 gl: wrapper for the gst_gl_context_thread_add function
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1313>
2023-09-29 06:55:47 +00:00
Kalev Lember a60cb26c27 Add COPYRIGHT and LICENSE files as links into all gstreamer-gl crates
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1315>
2023-09-28 23:22:12 +02:00
Sebastian Dröge 51075c71f6 examples: Update to memmap2 0.8
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1311>
2023-09-25 13:31:46 +03:00
Arun Raghavan b80a723de8 Minor copy-pasto fix for gstreamer-validate description
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1309>
2023-09-13 08:50:09 -04:00
Sebastian Dröge b93113c4c6 ci: Run cargo-deny on the whole workspace with all features enabled
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1308>
2023-09-07 15:20:43 +03:00
Sebastian Dröge 3988df8463 deny: Update and skip examples / tutorials
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1308>
2023-09-07 15:19:56 +03:00
Sebastian Dröge 7167fb78ce 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/1308>
2023-09-07 15:19:23 +03:00
Bilal Elmoussaoui 3228c36ef7 Adapt to no longer re-exported auto functions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1307>
2023-08-29 06:36:38 +00:00
Bilal Elmoussaoui 54979d859d Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1307>
2023-08-29 06:36:38 +00:00
Bilal Elmoussaoui ba202a5f87 Update gir submodule
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1307>
2023-08-29 06:36:38 +00:00
Sebastian Dröge 0306dd6b53 Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1306>
2023-08-28 21:45:31 +03:00
Sebastian Dröge 5e32d2efbf Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1306>
2023-08-28 21:45:31 +03:00
Sebastian Dröge c7662ce15a Update indentation for rustfmt 1.72
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1306>
2023-08-28 21:45:31 +03:00
Sebastian Dröge 4b87796c92 ci: Update to Rust 1.72
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1306>
2023-08-28 21:45:31 +03:00
Sebastian Dröge 83a562e227 Fix/silence various 1.72 clippy warnings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1306>
2023-08-28 16:50:41 +00:00
Sebastian Dröge f4486f5d61 Drop 0.20 docs to reduce disk usage requirements
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/482
2023-08-22 11:14:11 +03:00
Sebastian Dröge 4976e4ac4b examples: Update to windows 0.51
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1305>
2023-08-16 20:02:24 +09:00
Sebastian Dröge 13835a9f03 examples: Update to uds 0.4
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1305>
2023-08-16 12:35:19 +03:00
Tim-Philipp Müller db16dca822 tutorials: update old gstreamer-sdk media links
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1304>
2023-08-14 11:07:00 +03:00
Sebastian Dröge 277cb517cd Switch to resolver = "2" for the workspace
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1303>
2023-08-09 09:50:00 +03:00
Sebastian Dröge 76b8281709 ci: Build 0.21 docs and drop 0.19 docs 2023-08-08 19:48:54 +03:00
Sebastian Dröge a7be931474 Update versions to 0.22.0 2023-08-08 19:47:55 +03:00
Sebastian Dröge faf03c73ca Update CHANGELOG.md for 0.21.0 2023-08-08 19:47:27 +03:00
666 changed files with 21747 additions and 5052 deletions

1
.gitignore vendored
View file

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

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.22=0.22
stages:
- "trigger"
@ -74,6 +73,7 @@ trigger:
stage: 'trigger'
variables:
GIT_STRATEGY: none
tags: [ 'placeholder-job' ]
script:
- echo "Trigger job done, now running the pipeline."
rules:
@ -96,13 +96,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
@ -149,6 +142,7 @@ trigger:
libpango1.0-dev libcairo2-dev libjson-glib-dev libgdk-pixbuf-2.0-dev
libtiff-dev libpng-dev libjpeg-dev libepoxy-dev libsass-dev sassc
libcsound64-dev llvm clang nasm libsodium-dev libwebp-dev
libflac-dev
FDO_DISTRIBUTION_EXEC: >-
bash ci/install-gst.sh &&
bash ci/install-dav1d.sh &&
@ -319,6 +313,7 @@ test nightly sys:
rustfmt:
extends: .img-stable
stage: "lint"
tags: [ 'placeholder-job' ]
script:
- cargo fmt --version
- cargo fmt -- --color=always --check
@ -329,6 +324,7 @@ rustfmt:
check commits:
extends: .img-stable
stage: "lint"
tags: [ 'placeholder-job' ]
script:
- ci-fairy check-commits --textwidth 0 --no-signed-off-by
needs:
@ -338,6 +334,7 @@ check commits:
typos:
extends: .img-stable
stage: "lint"
tags: [ 'placeholder-job' ]
script:
- typos
needs:
@ -366,13 +363,15 @@ deny:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
script:
- cargo deny --color=always check
- cargo update --color=always
- cargo deny --color=always --workspace --all-features check all
gir-checks:
variables:
GIT_SUBMODULE_STRATEGY: recursive
extends: .img-stable
stage: 'extras'
tags: [ 'placeholder-job' ]
needs:
- job: 'build-stable'
artifacts: false
@ -389,6 +388,7 @@ outdated:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
script:
- cargo update --color=always
- cargo outdated --color=always --root-deps-only --exit-code 1 -v
coverage:
@ -514,7 +514,6 @@ pages:
# We also don't need a CONTEXT_DIR var as its also
# hardcoded to be windows-docker/
DOCKERFILE: 'ci/windows-docker/Dockerfile'
GST_UPSTREAM_BRANCH: 'main'
tags:
- 'windows'
- 'shell'

3068
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,13 +23,11 @@ multiple-versions = "deny"
wildcards = "allow"
highlight = "all"
# Various cocoa crates are in the middle of updating to newer versions
# proc-macro-crate depends on an older version of toml_edit
# https://github.com/bkchr/proc-macro-crate/pull/50
[[bans.skip]]
name = "foreign-types"
version = "0.3"
[[bans.skip]]
name = "foreign-types-shared"
version = "0.1"
name = "toml_edit"
version = "0.21"
[sources]
unknown-registry = "deny"
@ -41,13 +35,3 @@ unknown-git = "deny"
allow-git = [
"https://github.com/gtk-rs/gtk-rs-core",
]
# Various crates depend on an older version of syn
[[bans.skip]]
name = "syn"
version = "1.0"
# Various crates depend on an older version of bitflags
[[bans.skip]]
name = "bitflags"
version = "1.0"

View file

@ -1,46 +1,51 @@
[package]
name = "examples"
version = "0.21.0"
version.workspace = true
license = "MIT"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
edition = "2021"
rust-version = "1.70"
edition.workspace = true
rust-version.workspace = true
[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.workspace = true
gst.workspace = true
gst-gl = { workspace = true, optional = true }
gst-gl-egl = { workspace = true, optional = true }
gst-gl-x11 = { workspace = true, optional = true }
gst-app.workspace = true
gst-audio.workspace = true
gst-base.workspace = true
gst-video.workspace = true
gst-pbutils.workspace = true
gst-play = { workspace = true, optional = true }
gst-player = { workspace = true, optional = true }
ges = { workspace = true, optional = true }
gst-sdp = { workspace = true, optional = true }
gst-rtsp = { workspace = true, optional = true }
gst-rtsp-server = { workspace = true, optional = true }
gst-allocators = { workspace = true, optional = true }
gio = { workspace = true, optional = true }
anyhow = "1.0"
byte-slice-cast = "1"
cairo-rs = { workspace = true, 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 = { workspace = true, optional = true }
pangocairo = { workspace = true, optional = true }
raw-window-handle = { version = "0.5", optional = true }
uds = { version = "0.4", optional = true }
winit = { version = "0.29", optional = true, default-features = false, features = ["rwh_05"] }
atomic_refcell = "0.1"
data-encoding = "2.0"
once_cell = "1"
[target.'cfg(windows)'.dependencies]
windows = { version = "0.48", features=["Win32_Graphics_Direct3D11",
windows = { version = "0.56", 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",
@ -48,6 +53,7 @@ windows = { version = "0.48", features=["Win32_Graphics_Direct3D11",
[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.25"
objc = "0.2.7"
[build-dependencies]
gl_generator = { version = "0.14", optional = true }
@ -58,10 +64,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]]
@ -131,6 +136,10 @@ required-features = ["rtsp-server"]
name = "rtsp-server-subclass"
required-features = ["rtsp-server"]
[[bin]]
name = "rtsp-server-custom-auth"
required-features = ["rtsp-server", "gst-rtsp-server/v1_22"]
[[bin]]
name = "tagsetter"
@ -195,3 +204,6 @@ required-features = ["cairo-rs", "gst-video/v1_18"]
[[bin]]
name = "d3d11videosink"
required-features = ["windows"]
[[bin]]
name = "audio_multichannel_interleave"

View file

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

View file

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

View file

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

View file

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

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

View file

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

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

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

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

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

View file

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

View file

@ -1,5 +1,7 @@
#![allow(clippy::non_send_fields_in_send_ty)]
use anyhow::Result;
#[path = "../glupload.rs"]
mod glupload;
use glupload::*;
@ -30,13 +32,13 @@ void main () {
mod mirror {
use std::sync::Mutex;
use glib::once_cell::sync::Lazy;
use gst_base::subclass::BaseTransformMode;
use gst_gl::{
prelude::*,
subclass::{prelude::*, GLFilterMode},
*,
};
use once_cell::sync::Lazy;
use super::{gl, FRAGMENT_SHADER};
@ -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

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

View file

@ -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

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

View file

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

View file

@ -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

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

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

View file

@ -28,7 +28,7 @@ fn example_main() {
let main_loop = glib::MainLoop::new(None, false);
// Let GStreamer create a pipeline from the parsed launch syntax on the cli.
let pipeline = gst::parse_launch(&pipeline_str).unwrap();
let pipeline = gst::parse::launch(&pipeline_str).unwrap();
let bus = pipeline.bus().unwrap();
pipeline
@ -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) {
@ -253,11 +252,7 @@ fn example_main() -> Result<(), Error> {
if let Some(element) = msg.src() {
if element == &pipeline && s.current() == gst::State::Playing {
eprintln!("PLAYING");
gst::debug_bin_to_dot_file(
&pipeline,
gst::DebugGraphDetails::all(),
"client-playing",
);
pipeline.debug_to_dot_file(gst::DebugGraphDetails::all(), "client-playing");
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,188 @@
// In the imp submodule we include the actual implementation
use std::{collections::VecDeque, sync::Mutex};
use glib::prelude::*;
use gst_audio::subclass::prelude::*;
use once_cell::sync::Lazy;
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: std::sync::OnceLock<gst::Caps> = std::sync::OnceLock::new();
CAPS.get_or_init(|| {
// 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()
})
}
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 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::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: std::sync::OnceLock<Vec<glib::ParamSpec>> = std::sync::OnceLock::new();
PROPERTIES.get_or_init(|| {
vec![glib::ParamSpecFloat::builder("cutoff")
.nick("Cutoff")
.blurb("Cutoff frequency in Hz")
.default_value(Settings::default().cutoff)
.minimum(0.0)
.mutable_playing()
.build()]
})
}
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: std::sync::OnceLock<gst::subclass::ElementMetadata> =
std::sync::OnceLock::new();
Some(ELEMENT_METADATA.get_or_init(|| {
gst::subclass::ElementMetadata::new(
"Lowpass Filter",
"Filter/Effect/Audio",
"A Lowpass audio filter",
"Sebastian Dröge <sebastian@centricular.com>",
)
}))
}
}
// 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

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

View file

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

View file

@ -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

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

View file

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

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

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_gl::GLVideoFrame<gst_gl::gl_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)) => {
if let Ok(frame) = gst_video::VideoFrame::from_buffer_readable_gl(buffer, &info) {
winit::event::Event::UserEvent(Message::Frame(info, buffer)) => {
if let Ok(frame) = gst_gl::GLVideoFrame::from_buffer_readable(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 Ok(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 5223ce91b97a833b09d6cbd04bbeab1bf18112b7

@ -1 +1 @@
Subproject commit 060b114d8edb20c4041abb1e95acccb2cb2302be
Subproject commit 6cd7b656acd61172ab7f125a7059e4d0ecfc9637

@ -1 +1 @@
Subproject commit 8ea27b3f0b3316bdc3df48581820805b18473413
Subproject commit c988e03b5e99349efb8ffb6f502879ad4ddbc248

View file

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

View file

@ -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,17 +27,30 @@ 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;
pub mod functions;
pub(crate) 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)]
pub mod traits {
pub(crate) mod traits {
pub use super::phys_memory_allocator::PhysMemoryAllocatorExt;
}

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 @ 5223ce91b97a)
from gir-files (https://github.com/gtk-rs/gir-files @ 6cd7b656acd6)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ c988e03b5e99)

View file

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

View file

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

View file

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

View file

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

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::*;
@ -52,6 +56,8 @@ pub use phys_memory::*;
pub mod prelude {
#[doc(hidden)]
pub use gst::prelude::*;
pub use crate::auto::traits::*;
}
pub mod subclass;

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

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

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 @ 5223ce91b97a)
from gir-files (https://github.com/gtk-rs/gir-files @ 6cd7b656acd6)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ c988e03b5e99)

View file

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

@ -11,7 +11,7 @@ use std::error::Error;
use std::ffi::OsString;
use std::mem::{align_of, size_of};
use std::path::Path;
use std::process::Command;
use std::process::{Command, Stdio};
use std::str;
use tempfile::Builder;
@ -71,9 +71,11 @@ fn pkg_config_cflags(packages: &[&str]) -> Result<Vec<String>, Box<dyn Error>> {
let mut cmd = Command::new(pkg_config);
cmd.arg("--cflags");
cmd.args(packages);
cmd.stderr(Stdio::inherit());
let out = cmd.output()?;
if !out.status.success() {
return Err(format!("command {cmd:?} returned {}", out.status).into());
let (status, stdout) = (out.status, String::from_utf8_lossy(&out.stdout));
return Err(format!("command {cmd:?} failed, {status:?}\nstdout: {stdout}").into());
}
let stdout = str::from_utf8(&out.stdout)?;
Ok(shell_words::split(stdout.trim())?)
@ -188,13 +190,15 @@ fn get_c_output(name: &str) -> Result<String, Box<dyn Error>> {
let cc = Compiler::new().expect("configured compiler");
cc.compile(&c_file, &exe)?;
let mut abi_cmd = Command::new(exe);
let output = abi_cmd.output()?;
if !output.status.success() {
return Err(format!("command {abi_cmd:?} failed, {output:?}").into());
let mut cmd = Command::new(exe);
cmd.stderr(Stdio::inherit());
let out = cmd.output()?;
if !out.status.success() {
let (status, stdout) = (out.status, String::from_utf8_lossy(&out.stdout));
return Err(format!("command {cmd:?} failed, {status:?}\nstdout: {stdout}").into());
}
Ok(String::from_utf8(output.stdout)?)
Ok(String::from_utf8(out.stdout)?)
}
const RUST_LAYOUTS: &[(&str, Layout)] = &[
@ -247,11 +251,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

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

View file

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

View file

@ -0,0 +1,32 @@
[package]
name = "gstreamer-analytics"
authors = ["Olivier Crête <olivier.crete@collabora.com>"]
description = "Rust bindings for GStreamer Analytics library"
license = "MIT OR Apache-2.0"
readme = "README.md"
documentation = "https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer_analytics/"
keywords = ["gstreamer", "multimedia", "audio", "video", "gnome"]
version.workspace = true
categories.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
rust-version.workspace = true
[dependencies]
libc = "0.2"
ffi = { package = "gstreamer-analytics-sys", path = "sys" }
glib.workspace = true
gst.workspace = true
[dev-dependencies]
gir-format-check = "0.1"
[features]
default = []
v1_26 = ["gst/v1_26", "ffi/v1_26"]
[package.metadata.docs.rs]
all-features = true
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"]

View file

@ -0,0 +1,34 @@
[options]
girs_directories = ["../gir-files", "../gst-gir-files"]
library = "GstAnalytics"
version = "1.0"
min_cfg_version = "1.24"
work_mode = "normal"
concurrency = "send+sync"
generate_safety_asserts = true
single_version_file = true
generate_display_trait = false
trust_return_value_nullability = true
external_libraries = [
"GLib",
"GObject",
"Gst",
]
generate = [
"GstAnalytics.RelTypes"
]
manual = [
"GObject.Object",
"Gst.Element",
"Gst.MiniObject",
"Gst.Object"
]
[[object]]
name = "Gst.Buffer"
status = "manual"
ref_mode = "ref"

View file

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

View file

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

View file

@ -0,0 +1,214 @@
# gstreamer-rs [![crates.io](https://img.shields.io/crates/v/gstreamer-app.svg)](https://crates.io/crates/gstreamer-app) [![pipeline status](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/badges/main/pipeline.svg)](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/commits/main)
[GStreamer](https://gstreamer.freedesktop.org/) (App library) bindings for Rust.
Documentation can be found [here](https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer_app/).
These bindings are providing a safe API that can be used to interface with
GStreamer, e.g. for writing GStreamer-based applications and GStreamer plugins.
The bindings are mostly autogenerated with [gir](https://github.com/gtk-rs/gir/)
based on the [GObject-Introspection](https://wiki.gnome.org/Projects/GObjectIntrospection/)
API metadata provided by the GStreamer project.
## Table of Contents
1. [Installation](#installation)
1. [Linux/BSDs](#installation-linux)
1. [macOS](#installation-macos)
1. [Windows](#installation-windows)
1. [Getting Started](#getting-started)
1. [License](#license)
1. [Contribution](#contribution)
<a name="installation"/>
## Installation
To build the GStreamer bindings or anything depending on them, you need to
have at least GStreamer 1.14 and gst-plugins-base 1.14 installed. In addition,
some of the examples/tutorials require various GStreamer plugins to be
available, which can be found in gst-plugins-base, gst-plugins-good,
gst-plugins-bad, gst-plugins-ugly and/or gst-libav.
<a name="installation-linux"/>
### Linux/BSDs
You need to install the above mentioned packages with your distributions
package manager, or build them from source.
On Debian/Ubuntu they can be installed with
```console
$ apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
gstreamer1.0-libav libgstrtspserver-1.0-dev libges-1.0-dev
```
The minimum required version of the above libraries is >= 1.14. If you
build the gstreamer-player sub-crate, or any of the examples that
depend on gstreamer-player, you must ensure that in addition to the above
packages, `libgstreamer-plugins-bad1.0-dev` is installed. See the `Cargo.toml`
files for the full details,
```console
$ apt-get install libgstreamer-plugins-bad1.0-dev
```
Package names on other distributions should be similar.
Please submit a pull request with instructions for yours.
<a name="installation-macos"/>
### macOS
You can install GStreamer and the plugins via [Homebrew](https://brew.sh/) or
by installing the [binaries](https://gstreamer.freedesktop.org/data/pkg/osx/)
provided by the GStreamer project.
We recommend using the official GStreamer binaries over Homebrew, especially
as GStreamer in Homebrew is [currently broken](https://github.com/orgs/Homebrew/discussions/3740#discussioncomment-3804964).
#### GStreamer Binaries
You need to download the *two* `.pkg` files from the GStreamer website and
install them, e.g. `gstreamer-1.0-1.20.4-universal.pkg` and
`gstreamer-1.0-devel-1.20.4-universal.pkg`.
After installation, you also need to set the `PATH` environment variable as
follows
```console
$ export PATH="/Library/Frameworks/GStreamer.framework/Versions/1.0/bin${PATH:+:$PATH}"
```
Also note that the `pkg-config` from GStreamer should be the first one in
the `PATH` as other versions have all kinds of quirks that will cause
problems.
#### Homebrew
Homebrew only installs various plugins if explicitly enabled, so some extra
`--with-*` flags may be required.
```console
$ brew install gstreamer gst-plugins-base gst-plugins-good \
gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server \
gst-editing-services --with-orc --with-libogg --with-opus \
--with-pango --with-theora --with-libvorbis --with-libvpx \
--enable-gtk3
```
Make sure the version of these libraries is >= 1.14.
<a name="installation-windows"/>
### Windows
You can install GStreamer and the plugins via [MSYS2](http://www.msys2.org/)
with `pacman` or by installing the
[binaries](https://gstreamer.freedesktop.org/data/pkg/windows/) provided by
the GStreamer project.
We recommend using the official GStreamer binaries over MSYS2.
#### GStreamer Binaries
You need to download the *two* `.msi` files for your platform from the
GStreamer website and install them, e.g. `gstreamer-1.0-x86_64-1.20.4.msi` and
`gstreamer-1.0-devel-x86_64-1.20.4.msi`. Make sure to select the version that
matches your Rust toolchain, i.e. MinGW or MSVC.
After installation set the ``PATH` environment variable as follows:
```console
# For a UNIX-style shell:
$ export PATH="c:/gstreamer/1.0/msvc_x86_64/bin${PATH:+:$PATH}"
# For cmd.exe:
$ set PATH=C:\gstreamer\1.0\msvc_x86_64\bin;%PATH%
```
Make sure to update the path to where you have actually installed GStreamer
and for the corresponding toolchain.
Also note that the `pkg-config.exe` from GStreamer should be the first one in
the `PATH` as other versions have all kinds of quirks that will cause
problems.
#### MSYS2 / pacman
```console
$ pacman -S glib2-devel pkg-config \
mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base \
mingw-w64-x86_64-gst-plugins-good mingw-w64-x86_64-gst-plugins-bad \
mingw-w64-x86_64-gst-plugins-ugly mingw-w64-x86_64-gst-libav \
mingw-w64-x86_64-gst-rtsp-server
```
Make sure the version of these libraries is >= 1.14.
Note that the version of `pkg-config` included in `MSYS2` is
[known to have problems](https://github.com/rust-lang/pkg-config-rs/issues/51#issuecomment-346300858)
compiling GStreamer, so you may need to install another version. One option
would be [`pkg-config-lite`](https://sourceforge.net/projects/pkgconfiglite/).
<a name="getting-started"/>
## Getting Started
The API reference can be found
[here](https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer/), however it is
only the Rust API reference and does not explain any of the concepts.
For getting started with GStreamer development, the best would be to follow
the [documentation](https://gstreamer.freedesktop.org/documentation/) on the
GStreamer website, especially the [Application Development
Manual](https://gstreamer.freedesktop.org/documentation/application-development/).
While being C-centric, it explains all the fundamental concepts of GStreamer
and the code examples should be relatively easily translatable to Rust. The
API is basically the same, function/struct names are the same and everything
is only more convenient (hopefully) and safer.
In addition there are
[tutorials](https://gstreamer.freedesktop.org/documentation/tutorials/) on the
GStreamer website. Many of them were ported to Rust already and the code can
be found in the
[tutorials](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/tree/main/tutorials)
directory.
Some further examples for various aspects of GStreamer and how to use it from
Rust can be found in the
[examples](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/tree/main/examples)
directory.
Various GStreamer plugins written in Rust can be found in the
[gst-plugins-rs](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs)
repository.
<a name="license"/>
## LICENSE
gstreamer-rs and all crates contained in here are licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
http://opensource.org/licenses/MIT)
at your option.
GStreamer itself is licensed under the Lesser General Public License version
2.1 or (at your option) any later version:
https://www.gnu.org/licenses/lgpl-2.1.html
<a name="contribution"/>
## Contribution
Any kinds of contributions are welcome as a pull request.
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in gstreamer-rs by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

View file

@ -0,0 +1,44 @@
// This file was generated by gir (https://github.com/gtk-rs/gir)
// from gir-files (https://github.com/gtk-rs/gir-files)
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT
use glib::{bitflags::bitflags, translate::*};
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[doc(alias = "GstAnalyticsRelTypes")]
pub struct RelTypes: u32 {
#[doc(alias = "GST_ANALYTICS_REL_TYPE_NONE")]
const NONE = ffi::GST_ANALYTICS_REL_TYPE_NONE as _;
#[doc(alias = "GST_ANALYTICS_REL_TYPE_IS_PART_OF")]
const IS_PART_OF = ffi::GST_ANALYTICS_REL_TYPE_IS_PART_OF as _;
#[doc(alias = "GST_ANALYTICS_REL_TYPE_CONTAIN")]
const CONTAIN = ffi::GST_ANALYTICS_REL_TYPE_CONTAIN as _;
#[doc(alias = "GST_ANALYTICS_REL_TYPE_RELATE_TO")]
const RELATE_TO = ffi::GST_ANALYTICS_REL_TYPE_RELATE_TO as _;
#[doc(alias = "GST_ANALYTICS_REL_TYPE_LAST")]
const LAST = ffi::GST_ANALYTICS_REL_TYPE_LAST as _;
#[doc(alias = "GST_ANALYTICS_REL_TYPE_ANY")]
const ANY = ffi::GST_ANALYTICS_REL_TYPE_ANY as _;
}
}
#[doc(hidden)]
impl IntoGlib for RelTypes {
type GlibType = ffi::GstAnalyticsRelTypes;
#[inline]
fn into_glib(self) -> ffi::GstAnalyticsRelTypes {
self.bits()
}
}
#[doc(hidden)]
impl FromGlib<ffi::GstAnalyticsRelTypes> for RelTypes {
#[inline]
unsafe fn from_glib(value: ffi::GstAnalyticsRelTypes) -> Self {
skip_assert_initialized!();
Self::from_bits_truncate(value)
}
}

View file

@ -0,0 +1,7 @@
// This file was generated by gir (https://github.com/gtk-rs/gir)
// from gir-files (https://github.com/gtk-rs/gir-files)
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT
mod flags;
pub use self::flags::RelTypes;

View file

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

View file

@ -0,0 +1,212 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::*;
use crate::relation_meta::*;
#[derive(Debug)]
pub enum AnalyticsClassificationMtd {}
mod sealed {
pub trait Sealed {}
impl<T: super::AnalyticsRelationMetaClassificationExt> Sealed for T {}
}
pub trait AnalyticsRelationMetaClassificationExt: sealed::Sealed {
fn add_one_cls_mtd(
&mut self,
confidence_level: f32,
class_quark: glib::Quark,
) -> Result<AnalyticsMtdRef<AnalyticsClassificationMtd>, glib::BoolError>;
fn add_cls_mtd(
&mut self,
confidence_levels: &[f32],
class_quarks: &[glib::Quark],
) -> Result<AnalyticsMtdRef<AnalyticsClassificationMtd>, glib::BoolError>;
}
impl<'a> AnalyticsRelationMetaClassificationExt
for gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>
{
#[doc(alias = "gst_analytics_relation_meta_add_one_cls_mtd")]
fn add_one_cls_mtd(
&mut self,
confidence_level: f32,
class_quark: glib::Quark,
) -> Result<AnalyticsMtdRef<'a, AnalyticsClassificationMtd>, glib::BoolError> {
unsafe {
let mut mtd = std::mem::MaybeUninit::uninit();
let ret = from_glib(ffi::gst_analytics_relation_meta_add_one_cls_mtd(
self.as_mut_ptr(),
confidence_level,
class_quark.into_glib(),
mtd.as_mut_ptr(),
));
let id = mtd.assume_init().id;
if ret {
Ok(AnalyticsMtdRef::from_meta(self.as_ref(), id))
} else {
Err(glib::bool_error!("Couldn't add more data"))
}
}
}
#[doc(alias = "gst_analytics_relation_meta_add_cls_mtd")]
fn add_cls_mtd(
&mut self,
confidence_levels: &[f32],
class_quarks: &[glib::Quark],
) -> Result<AnalyticsMtdRef<'a, AnalyticsClassificationMtd>, glib::BoolError> {
let length = std::cmp::min(confidence_levels.len(), class_quarks.len());
unsafe {
let mut mtd = std::mem::MaybeUninit::uninit();
let ret = from_glib(ffi::gst_analytics_relation_meta_add_cls_mtd(
self.as_mut_ptr(),
length,
mut_override(confidence_levels.as_ptr()),
class_quarks.as_ptr() as *mut _,
mtd.as_mut_ptr(),
));
let id = mtd.assume_init().id;
if ret {
Ok(AnalyticsMtdRef::from_meta(self.as_ref(), id))
} else {
Err(glib::bool_error!("Couldn't add more data"))
}
}
}
}
unsafe impl AnalyticsMtd for AnalyticsClassificationMtd {
#[doc(alias = "gst_analytics_cls_mtd_get_mtd_type")]
fn mtd_type() -> ffi::GstAnalyticsMtdType {
unsafe { ffi::gst_analytics_cls_mtd_get_mtd_type() }
}
}
unsafe fn from(t: ffi::GstAnalyticsMtd) -> ffi::GstAnalyticsClsMtd {
std::mem::transmute(t)
}
impl<'a> AnalyticsMtdRef<'a, AnalyticsClassificationMtd> {
#[doc(alias = "gst_analytics_cls_mtd_get_length")]
pub fn len(&self) -> usize {
unsafe {
let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self));
ffi::gst_analytics_cls_mtd_get_length(&mut mtd)
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[doc(alias = "gst_analytics_cls_mtd_get_level")]
pub fn level(&self, index: usize) -> f32 {
assert!(index < self.len());
unsafe {
let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self));
ffi::gst_analytics_cls_mtd_get_level(&mut mtd, index)
}
}
#[doc(alias = "gst_analytics_cls_mtd_get_quark")]
pub fn quark(&self, index: usize) -> glib::Quark {
assert!(index < self.len());
unsafe {
let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self));
from_glib(ffi::gst_analytics_cls_mtd_get_quark(&mut mtd, index))
}
}
pub fn iterate(&self) -> AnalyticsClassificationIterator {
AnalyticsClassificationIterator {
mtd: self,
index: 0,
length: self.len(),
}
}
}
pub struct AnalyticsClassificationIterator<'a> {
mtd: &'a AnalyticsMtdRef<'a, AnalyticsClassificationMtd>,
index: usize,
length: usize,
}
impl<'a> Iterator for AnalyticsClassificationIterator<'a> {
type Item = (glib::Quark, f32);
fn next(&mut self) -> Option<Self::Item> {
if self.index == self.length {
None
} else {
let ret = Some((self.mtd.quark(self.index), self.mtd.level(self.index)));
self.index += 1;
ret
}
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn one_class() {
gst::init().unwrap();
assert_eq!(AnalyticsClassificationMtd::type_name(), "classification");
let mut buf = gst::Buffer::new();
let mut meta = AnalyticsRelationMeta::add(buf.make_mut());
assert!(meta.is_empty());
let cls = meta
.add_one_cls_mtd(0.7, glib::Quark::from_str("class1"))
.unwrap();
assert_eq!(cls.len(), 1);
assert_eq!(cls.level(0), 0.7);
assert_eq!(cls.quark(0), glib::Quark::from_str("class1"));
}
#[test]
fn many_classes() {
gst::init().unwrap();
assert_eq!(AnalyticsClassificationMtd::type_name(), "classification");
let mut buf = gst::Buffer::new();
let mut meta = AnalyticsRelationMeta::add(buf.make_mut());
assert!(meta.is_empty());
let classes = [
glib::Quark::from_str("a"),
glib::Quark::from_str("b"),
glib::Quark::from_str("c"),
glib::Quark::from_str("d"),
];
let levels = [0.1, 0.2, 0.3, 0.4];
let cls = meta.add_cls_mtd(&levels, &classes).unwrap();
assert_eq!(cls.len(), 4);
for i in 0..4usize {
assert_eq!(cls.level(i), levels[i]);
assert_eq!(cls.quark(i), classes[i]);
}
for (i, (q, l)) in cls.iterate().enumerate() {
assert_eq!(l, levels[i]);
assert_eq!(q, classes[i]);
}
}
}

View file

@ -0,0 +1,36 @@
// Take a look at the license at the top of the repository in the LICENSE file.
#![cfg_attr(docsrs, feature(doc_cfg))]
#![allow(clippy::missing_safety_doc)]
#![doc = include_str!("../README.md")]
pub use ffi;
pub use glib;
pub use gst;
macro_rules! skip_assert_initialized {
() => {};
}
mod auto;
pub use crate::auto::*;
mod relation_meta;
pub use crate::relation_meta::*;
mod object_detection;
pub use crate::object_detection::*;
mod tracking;
pub use crate::tracking::*;
mod classification;
pub use crate::classification::*;
// Re-export all the traits in a prelude module, so that applications
// can always "use gst_app::prelude::*" without getting conflicts
pub mod prelude {
pub use crate::classification::AnalyticsRelationMetaClassificationExt;
pub use crate::object_detection::AnalyticsRelationMetaODExt;
pub use crate::tracking::AnalyticsRelationMetaTrackingExt;
}

View file

@ -0,0 +1,175 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::*;
use crate::relation_meta::*;
#[derive(Debug)]
pub enum AnalyticsODMtd {}
mod sealed {
pub trait Sealed {}
impl<T: super::AnalyticsRelationMetaODExt> Sealed for T {}
}
pub trait AnalyticsRelationMetaODExt: sealed::Sealed {
fn add_od_mtd(
&mut self,
type_: glib::Quark,
x: i32,
y: i32,
w: i32,
h: i32,
loc_conf_lvl: f32,
) -> Result<AnalyticsMtdRef<AnalyticsODMtd>, glib::BoolError>;
}
impl<'a> AnalyticsRelationMetaODExt
for gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>
{
#[doc(alias = "gst_analytics_relation_meta_add_od_mtd")]
fn add_od_mtd(
&mut self,
type_: glib::Quark,
x: i32,
y: i32,
w: i32,
h: i32,
loc_conf_lvl: f32,
) -> Result<AnalyticsMtdRef<AnalyticsODMtd>, glib::BoolError> {
unsafe {
let mut mtd = std::mem::MaybeUninit::uninit();
let ret = from_glib(ffi::gst_analytics_relation_meta_add_od_mtd(
self.as_mut_ptr(),
type_.into_glib(),
x,
y,
w,
h,
loc_conf_lvl,
mtd.as_mut_ptr(),
));
let id = mtd.assume_init().id;
if ret {
Ok(AnalyticsMtdRef::from_meta(self.as_ref(), id))
} else {
Err(glib::bool_error!("Couldn't add more data"))
}
}
}
}
#[derive(Clone, Copy, Default, Debug)]
pub struct AnalyticsODLocation {
pub x: i32,
pub y: i32,
pub w: i32,
pub h: i32,
pub loc_conf_lvl: f32,
}
unsafe impl AnalyticsMtd for AnalyticsODMtd {
#[doc(alias = "gst_analytics_od_mtd_get_mtd_type")]
fn mtd_type() -> ffi::GstAnalyticsMtdType {
unsafe { ffi::gst_analytics_od_mtd_get_mtd_type() }
}
}
unsafe fn from(t: ffi::GstAnalyticsMtd) -> ffi::GstAnalyticsODMtd {
std::mem::transmute(t)
}
impl<'a> AnalyticsMtdRef<'a, AnalyticsODMtd> {
#[doc(alias = "gst_analytics_od_mtd_get_obj_type")]
pub fn obj_type(&self) -> Option<glib::Quark> {
unsafe {
let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self));
let type_ = ffi::gst_analytics_od_mtd_get_obj_type(&mut mtd);
if type_ == 0 {
None
} else {
Some(glib::Quark::from_glib(type_))
}
}
}
#[doc(alias = "gst_analytics_od_mtd_get_location")]
pub fn location(&self) -> Result<AnalyticsODLocation, glib::BoolError> {
let mut loc = AnalyticsODLocation::default();
let success = unsafe {
let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self));
ffi::gst_analytics_od_mtd_get_location(
&mut mtd,
&mut loc.x,
&mut loc.y,
&mut loc.w,
&mut loc.h,
&mut loc.loc_conf_lvl,
)
};
if success != 0 {
Ok(loc)
} else {
Err(glib::bool_error!("Could retrieve location"))
}
}
#[doc(alias = "gst_analytics_od_mtd_get_confidence_lvl")]
pub fn confidence_level(&self) -> f32 {
unsafe {
let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self));
let mut lvl: f32 = 0.0;
ffi::gst_analytics_od_mtd_get_confidence_lvl(&mut mtd, &mut lvl);
lvl
}
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn object_detection() {
gst::init().unwrap();
assert_eq!(AnalyticsODMtd::type_name(), "object-detection");
let mut buf = gst::Buffer::new();
let mut meta = AnalyticsRelationMeta::add(buf.make_mut());
assert!(meta.is_empty());
let od = meta
.add_od_mtd(glib::Quark::from_str("blb"), 0, 1, 10, 20, 0.8)
.unwrap();
assert_eq!(od.obj_type().unwrap(), glib::Quark::from_str("blb"));
let loc = od.location().unwrap();
assert_eq!(loc.x, 0);
assert_eq!(loc.y, 1);
assert_eq!(loc.w, 10);
assert_eq!(loc.h, 20);
assert_eq!(loc.loc_conf_lvl, 0.8);
let meta = buf.meta::<AnalyticsRelationMeta>().unwrap();
assert!(meta.mtd::<AnalyticsODMtd>(1).is_none());
let meta2 = buf.meta::<AnalyticsRelationMeta>().unwrap();
let od2 = meta2.mtd::<AnalyticsODMtd>(0).unwrap();
assert_eq!(od2.obj_type().unwrap(), glib::Quark::from_str("blb"));
let loc = od2.location().unwrap();
assert_eq!(loc.x, 0);
assert_eq!(loc.y, 1);
assert_eq!(loc.w, 10);
assert_eq!(loc.h, 20);
assert_eq!(loc.loc_conf_lvl, 0.8);
}
}

View file

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

View file

@ -0,0 +1,158 @@
// Take a look at the license at the top of the repository in the LICENSE file.
use glib::translate::*;
use crate::relation_meta::*;
#[derive(Debug)]
pub enum AnalyticsTrackingMtd {}
mod sealed {
pub trait Sealed {}
impl<T: super::AnalyticsRelationMetaTrackingExt> Sealed for T {}
}
pub trait AnalyticsRelationMetaTrackingExt: sealed::Sealed {
fn add_tracking_mtd(
&mut self,
tracking_id: u64,
tracking_first_seen: gst::ClockTime,
) -> Result<AnalyticsMtdRef<AnalyticsTrackingMtd>, glib::BoolError>;
}
impl<'a> AnalyticsRelationMetaTrackingExt
for gst::MetaRefMut<'a, AnalyticsRelationMeta, gst::meta::Standalone>
{
#[doc(alias = "gst_analytics_relation_meta_add_tracking_mtd")]
fn add_tracking_mtd(
&mut self,
tracking_id: u64,
tracking_first_seen: gst::ClockTime,
) -> Result<AnalyticsMtdRef<AnalyticsTrackingMtd>, glib::BoolError> {
unsafe {
let mut mtd = std::mem::MaybeUninit::uninit();
let ret = from_glib(ffi::gst_analytics_relation_meta_add_tracking_mtd(
self.as_mut_ptr(),
tracking_id,
tracking_first_seen.into_glib(),
mtd.as_mut_ptr(),
));
let id = mtd.assume_init().id;
if ret {
Ok(AnalyticsMtdRef::from_meta(self.as_ref(), id))
} else {
Err(glib::bool_error!("Couldn't add more data"))
}
}
}
}
unsafe impl AnalyticsMtd for AnalyticsTrackingMtd {
#[doc(alias = "gst_analytics_tracking_mtd_get_mtd_type")]
fn mtd_type() -> ffi::GstAnalyticsMtdType {
unsafe { ffi::gst_analytics_tracking_mtd_get_mtd_type() }
}
}
unsafe fn from(t: ffi::GstAnalyticsMtd) -> ffi::GstAnalyticsTrackingMtd {
std::mem::transmute(t)
}
impl<'a> AnalyticsMtdRef<'a, AnalyticsTrackingMtd> {
#[doc(alias = "gst_analytics_tracking_mtd_get_info")]
pub fn info(&self) -> (u64, gst::ClockTime, gst::ClockTime, bool) {
let mut tracking_id: u64 = 0;
let mut tracking_first_seen: u64 = 0;
let mut tracking_last_seen: u64 = 0;
let mut tracking_lost: i32 = 0;
unsafe {
let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self));
ffi::gst_analytics_tracking_mtd_get_info(
&mut mtd,
&mut tracking_id,
&mut tracking_first_seen,
&mut tracking_last_seen,
&mut tracking_lost,
);
};
(
tracking_id,
gst::ClockTime::from_nseconds(tracking_first_seen),
gst::ClockTime::from_nseconds(tracking_last_seen),
tracking_lost != 0,
)
}
}
impl<'a> AnalyticsMtdRefMut<'a, AnalyticsTrackingMtd> {
#[doc(alias = "gst_analytics_tracking_mtd_update_last_seen")]
pub fn update_last_seen(&mut self, last_seen: gst::ClockTime) -> Result<(), glib::BoolError> {
let ret: bool = unsafe {
let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self));
from_glib(ffi::gst_analytics_tracking_mtd_update_last_seen(
&mut mtd,
last_seen.into_glib(),
))
};
assert!(ret);
Ok(())
}
#[doc(alias = "gst_analytics_tracking_mtd_set_lost")]
pub fn set_lost(&mut self) -> Result<(), glib::BoolError> {
let ret: bool = unsafe {
let mut mtd = from(ffi::GstAnalyticsMtd::unsafe_from(self));
from_glib(ffi::gst_analytics_tracking_mtd_set_lost(&mut mtd))
};
assert!(ret);
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn tracking() {
gst::init().unwrap();
assert_eq!(AnalyticsTrackingMtd::type_name(), "object-tracking");
let mut buf = gst::Buffer::new();
let mut meta = AnalyticsRelationMeta::add(buf.make_mut());
assert!(meta.is_empty());
let track = meta
.add_tracking_mtd(10, gst::ClockTime::from_seconds(10))
.unwrap();
let (tracking_id, tracking_first_seen, tracking_last_seen, tracking_lost) = track.info();
assert_eq!(tracking_id, 10);
assert_eq!(tracking_first_seen, gst::ClockTime::from_seconds(10));
assert_eq!(tracking_last_seen, gst::ClockTime::from_seconds(10));
assert!(!tracking_lost);
let track_id = track.id();
let mut tracking_mut = meta.mtd_mut::<AnalyticsTrackingMtd>(track_id).unwrap();
tracking_mut
.update_last_seen(gst::ClockTime::from_seconds(20))
.unwrap();
tracking_mut.set_lost().unwrap();
let tracking: AnalyticsMtdRef<_> = tracking_mut.into();
let (tracking_id, tracking_first_seen, tracking_last_seen, tracking_lost) = tracking.info();
assert_eq!(tracking_id, 10);
assert_eq!(tracking_first_seen, gst::ClockTime::from_seconds(10));
assert_eq!(tracking_last_seen, gst::ClockTime::from_seconds(20));
assert!(tracking_lost);
}
}

View file

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

View file

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

View file

@ -0,0 +1,61 @@
[build-dependencies]
system-deps = "6"
[dependencies]
libc = "0.2"
[dependencies.glib-sys]
workspace = true
[dependencies.gstreamer-sys]
workspace = true
[dev-dependencies]
shell-words = "1.0.0"
tempfile = "3"
[lib]
name = "gstreamer_analytics_sys"
[package]
authors = ["Olivier Crête <olivier.crete@collabora.com"]
build = "build.rs"
description = "FFI bindings to libgstanalytics-1.0"
documentation = "https://gstreamer.pages.freedesktop.org/gstreamer-rs/stable/latest/docs/gstreamer_analytics_sys/"
keywords = ["ffi", "gstreamer", "gnome", "multimedia"]
license = "MIT"
name = "gstreamer-analytics-sys"
readme = "README.md"
[package.version]
workspace = true
[package.categories]
workspace = true
[package.repository]
workspace = true
[package.homepage]
workspace = true
[package.edition]
workspace = true
[package.rust-version]
workspace = true
[package.metadata.docs.rs]
all-features = true
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"]
[package.metadata.system-deps.gstreamer_analytics_1_0]
name = "gstreamer-analytics-1.0"
version = "1.24"
[package.metadata.system-deps.gstreamer_analytics_1_0.v1_26]
version = "1.25"
[features]
v1_26 = []

View file

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

View file

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

View file

@ -0,0 +1,31 @@
# gstreamer-sys [![crates.io](https://img.shields.io/crates/v/gstreamer-app-sys.svg)](https://crates.io/crates/gstreamer-app-sys) [![pipeline status](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/badges/main/pipeline.svg)](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/commits/main)
[GStreamer](https://gstreamer.freedesktop.org/) (App library) FFI bindings for Rust.
These bindings are providing unsafe FFI API that can be used to interface with
GStreamer. Generally they are meant to be used as the building block for
higher-level abstractions like:
* Bindings for GStreamer applications and plugins: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs
* Various GStreamer plugins written in Rust: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs
The bindings are autogenerated with [gir](https://github.com/gtk-rs/gir/)
based on the [GObject-Introspection](https://wiki.gnome.org/Projects/GObjectIntrospection/)
API metadata provided by the GStreamer project.
## LICENSE
gstreamer-sys and all crates contained here are licensed under the MIT
license ([LICENSE](LICENSE) or http://opensource.org/licenses/MIT).
GStreamer itself is licensed under the Lesser General Public License version
2.1 or (at your option) any later version:
https://www.gnu.org/licenses/lgpl-2.1.html
## Contribution
Any kinds of contributions are welcome as a pull request.
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in gstreamer-rs by you shall be licensed under the MIT license as above,
without any additional terms or conditions.

View file

@ -0,0 +1,18 @@
// This file was generated by gir (https://github.com/gtk-rs/gir)
// from gir-files (https://github.com/gtk-rs/gir-files)
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT
#[cfg(not(docsrs))]
use std::process;
#[cfg(docsrs)]
fn main() {} // prevent linking libraries to avoid documentation failure
#[cfg(not(docsrs))]
fn main() {
if let Err(s) = system_deps::Config::new().probe() {
println!("cargo:warning={s}");
process::exit(1);
}
}

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