Compare commits

...

673 commits
0.19.8 ... main

Author SHA1 Message Date
Sebastian Dröge 413a6baa8c Update CHANGELOG.md for 0.22.5 2024-05-23 16:06:42 +03:00
Sebastian Dröge 9e2c6268cb gstreamer: Use usize instead of u32 for various indices
This affects buffers, caps, caps features, structures and tag lists and
makes it easier to use them with other Rust APIs that use usize-based
indicing.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1445>
2024-05-22 08:15:08 +00:00
Tim-Philipp Müller 4cda565a39 gstreamer: bufferlist: add another test for foreach_mut
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1446>
2024-05-22 06:59:40 +00:00
Sebastian Dröge 805cd6c591 gstreamer: bufferlist: Change remove function to take a range instead of index + length
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1444>
2024-05-21 08:21:17 +03:00
Sebastian Dröge a0e58ec359 gstreamer: bufferlist: Check index/length when removing a buffer
Out of range values give assertions in the C function.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1444>
2024-05-21 08:19:30 +03:00
Sebastian Dröge 9f151466b7 gstreamer: bufferlist: Check for out of range indices before trying to get buffer
Passing an index bigger than the length will cause an assertion in the C
function.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1444>
2024-05-21 08:11:41 +03:00
Sebastian Dröge 1b537c17c8 Update Cargo.lock
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1443>
2024-05-20 14:06:30 +03:00
Sebastian Dröge c3619b45aa Update to itertools 0.13
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1443>
2024-05-20 14:03:58 +03:00
Seungha Yang f59029b57c event: Fix leak in SelectStreamsBuilder
gst_event_new_select_streams() does not take ownership of GList

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1442>
2024-05-16 14:30:52 +00:00
Sebastian Dröge b468280353 Improve code generation with panic=abort around panic handling code
None of that can ever be called in that case but the compiler can't know
that in more complicated cases like these. Handling it explicitly allows
no handling code to be generated at all here, like would already happen
everywhere else.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1441>
2024-05-16 16:38:15 +03:00
Mathieu Duponchelle 0ef80c4fe7 streamproducer: expose set_forward_preroll() API
This is useful to decide whether the preroll sample should be forwarded
to consumers when prerolling or only once it is time to render it.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1439>
2024-05-10 22:46:16 +00:00
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
Sebastian Dröge 9c6e48119c Use all-features = true instead of all-features = "true" 2023-08-08 17:46:20 +03:00
Sebastian Dröge 7a7b2c7b21 Regenerate with latest gir 2023-08-08 17:45:57 +03:00
Sebastian Dröge af100377ed gir: Update 2023-08-08 17:45:29 +03:00
Sebastian Dröge e95e62d871 Fix build on docs.rs and document all features
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/478

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1302>
2023-08-08 10:50:12 +03:00
Sebastian Dröge 03417068dc base: Remove last occurence of nowadays unused dox feature
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/477

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1302>
2023-08-08 10:40:11 +03:00
Guillaume Desmottes 63852b3b19 streamproducer: forward selected sticky events when adding consumers
The consumer pipeline may rely on some sticky events (Tag in my case)
which may have already been sent.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1299>
2023-08-07 20:26:28 +00:00
Sebastian Dröge 783b95884d Regenerate with latest gir / gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1301>
2023-08-07 11:09:48 +03:00
Sebastian Dröge 03b614372d Update gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1301>
2023-08-07 11:09:48 +03:00
Sebastian Dröge ab153de47f Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1301>
2023-08-07 11:09:48 +03:00
Sebastian Dröge bac88e88b8 Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1301>
2023-08-07 11:09:48 +03:00
Sebastian Dröge 00e42854fa gl: Manually implement swizzle array functions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1301>
2023-08-07 11:09:48 +03:00
Sebastian Dröge e4d7748241 video: Add some more constants to the ignore list
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1301>
2023-08-07 11:05:39 +03:00
Sebastian Dröge 7a79fc89d6 ci: Update to Rust 1.71.1
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1301>
2023-08-07 09:29:18 +03:00
Sebastian Dröge cdd548acba ci: Update to cargo-c 0.9.22
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1301>
2023-08-07 09:28:56 +03:00
Kourosh Firoozbakht 1e2e57836f examples: fix typo
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1300>
2023-07-26 01:42:02 +00:00
Sebastian Dröge c0f9551fc4 ci: Install GTK from the GStreamer monorepo
Force-build the gtk subproject when building gstreamer

This subproject is only pulled in when -Drs=enabled by gst-plugins-rs,
so we need to force-enable it here.

Co-authored-by: Nirbheek Chauhan <nirbheek@centricular.com>
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1298>
2023-07-19 17:58:37 +05:30
Nirbheek Chauhan 16e1f92489 ci: Use meson --vsenv instead of invoking VsDevCmd.bat
This is simpler, easier to use, and less likely to break.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1298>
2023-07-19 17:58:37 +05:30
Nirbheek Chauhan 0d7555bed0 ci: Switch install_gst powershell script to error by default
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1298>
2023-07-19 17:58:37 +05:30
Sebastian Dröge d96d164c8d ci: Update Windows base docker image
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1298>
2023-07-19 10:53:22 +03:00
Sebastian Dröge f8bb992aaf ci: Don't install pango separately on Windows
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1298>
2023-07-19 10:03:37 +03:00
Sebastian Dröge a53069208b ci: Move extra packages from gst-plugins-rs CI images here
No need to have two layers of CI images for these few additional
packages. It only complicates the whole setup.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1298>
2023-07-19 09:39:25 +03:00
Sebastian Dröge 2abf75122d Update minimum supported Rust version to 1.70
gtk-rs will update soonish too.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1298>
2023-07-19 09:24:10 +03:00
Guillaume Gomez 8fba09e1ed Use --generate-link-to-definition option when generating documentation
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1297>
2023-07-17 18:06:40 +02:00
Guillaume Gomez 75f4c66f14 Add --generate-link-to-definition option when building on docs.rs
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1297>
2023-07-17 18:06:26 +02:00
Sebastian Dröge 92327be3b1 ci: Add various missing dependencies to the Linux image
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1295>
2023-07-17 10:29:20 +03:00
Jordan Petridis 63c79d377f ci: Update ci-templates ref
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1295>
2023-07-14 02:54:43 +03:00
Sebastian Dröge 29ffd10b35 ci: Update to Rust 1.71
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1295>
2023-07-13 17:16:27 +03:00
Sebastian Dröge 8b6c99a84e pbutils: Remove unnecessary mut 2023-07-11 10:05:32 +03:00
Mathieu Duponchelle 88c21505d2 streamproducer: forward preroll sample from new_preroll callback
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1280>
2023-07-07 17:06:54 +02:00
Mathieu Duponchelle a4247d5199 streamproducer: extract process_sample function
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1280>
2023-07-07 14:09:35 +02:00
Sebastian Dröge 214f61abc5 deny: Allow bitflags 1 for the time being 2023-07-07 09:09:58 +03:00
Bilal Elmoussaoui 19cf78d85f Adapt to glib::Continue changing it's module
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1294>
2023-07-06 22:22:43 +02:00
Bilal Elmoussaoui 2fe62d3107 Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1294>
2023-07-06 22:22:24 +02:00
Bilal Elmoussaoui 387c51f860 Update gir submodule
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1294>
2023-07-06 21:59:16 +02:00
Sebastian Dröge 89ab9d09c8 Remove GTK3 examples/tutorials
GTK3 is deprecated and the GTK videooverlay example does not even work
on modern systems with Wayland anymore.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1293>
2023-07-06 17:25:28 +03:00
Bilal Elmoussaoui f9fa7f55fc Use re-exported once_cell
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1293>
2023-07-06 16:50:35 +03:00
Bilal Elmoussaoui b156ba2c59 Adapt to glib::Continue rename
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1293>
2023-07-06 16:50:35 +03:00
Bilal Elmoussaoui 7cf66dbc61 Adapt to bitflags update
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1293>
2023-07-06 15:17:32 +02:00
Bilal Elmoussaoui 9eacba1569 Use bitflags from re-exported glib crates
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1293>
2023-07-06 15:06:47 +02:00
Bilal Elmoussaoui c2cda2c067 Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1293>
2023-07-06 15:05:38 +02:00
Bilal Elmoussaoui 4ec5f99142 Update gir submodule
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1293>
2023-07-06 15:04:50 +02:00
Sebastian Dröge 7ac1a2b753 Regenerate with latest gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1292>
2023-07-06 14:21:45 +03:00
Bilal Elmoussaoui 8cf099f0ab Seal manual traits
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1292>
2023-07-06 14:21:45 +03:00
Bilal Elmoussaoui 6a703508bc Update gir-files submodule
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1292>
2023-07-06 14:08:32 +03:00
Bilal Elmoussaoui 2740c38cdd Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1292>
2023-07-06 14:08:32 +03:00
Bilal Elmoussaoui 617652dce0 Update gir submodule
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1292>
2023-07-06 14:08:32 +03:00
Sebastian Dröge 80abcf6ca3 Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1286>
2023-07-06 08:46:06 +03:00
Sebastian Dröge 67b8c29274 video: Add conversions between VideoInfo and VideoInfoDmaDrm
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1286>
2023-07-06 08:46:06 +03:00
Sebastian Dröge bc979b7ce9 audio: Add version to AudioRingBufferFormatType::Dsd
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1286>
2023-07-06 08:40:36 +03:00
Sebastian Dröge 354f072ff3 gstreamer: Add new Fraction::simplify() bindings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1286>
2023-07-06 08:40:36 +03:00
Sebastian Dröge f806967a2e Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1286>
2023-07-06 08:40:36 +03:00
Sebastian Dröge c6015043f5 Regenerate with updated gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1286>
2023-07-06 08:40:36 +03:00
Sebastian Dröge a913a895c0 Temporarily switch to a gir branch with updated dependencies
Updating to latest gir requires various manual code changes and needs to
be done separately, but this unbreaks the CI for now.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1286>
2023-07-06 08:40:36 +03:00
Sebastian Dröge 90aad36c34 ci: typoes: Fix some typos and add subtiles to the word list
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1286>

fixup
2023-07-06 08:40:30 +03:00
Tim-Philipp Müller 42fe22301b ci: update gstreamer build
Need https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4951
to fix some gst-plugins-rs unit tests.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1286>
2023-07-06 08:08:39 +03:00
Sebastian Dröge 296a12d1ea Update CHANGELOG.md for 0.20.7 2023-07-05 12:29:02 +03:00
Sebastian Dröge 96c7eb9563 basetransform: Don't leak any output buffer if prepare_output_buffer fails
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1285>
2023-06-30 10:33:30 +03:00
Sebastian Dröge eff6b4c952 basetransform: Fix memory leak when dropping buffers from the transform function
Also add a basic test for a basetransform subclass.

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

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1285>
2023-06-30 10:24:55 +03:00
Sebastian Dröge 12bed29738 gstreamer: Move various MetaAPI methods to an extension trait
These don't make sense to implement any different than the default.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1284>
2023-06-30 08:50:03 +03:00
Thibault Saunier af57f6f17b gstreamer: meta Add API to list/check tags
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1284>
2023-06-30 08:43:45 +03:00
Li Yuanheng 1bc197db79 appsink: property should use hyphen not underscore
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1283>
2023-06-28 13:53:38 +08:00
Thibault Saunier a66fc95d2a ges: Mark asset APIs as Send+sync
Those objects are MT. safe

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1278>
2023-06-26 12:37:34 +00:00
Thibault Saunier 7f7c7a4165 ges: Allow subclassing GESFormatter
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1278>
2023-06-26 12:37:34 +00:00
Sebastian Dröge 7c67375d99 examples: Reduce dependencies of the thumbnail example
Instead of depending on libraries for every possible image format,
depend only on the JPEG and PNG libraries.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1281>
2023-06-26 14:14:45 +03:00
Sebastian Dröge b59680f437 Update to cocoa 0.25
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1281>
2023-06-26 14:00:54 +03:00
Sebastian Dröge e2c1dad0d5 Update to itertools 0.11
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1281>
2023-06-26 13:59:47 +03:00
Thibault Saunier 49bf604276 ges: Bind the new object
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1258>
2023-06-16 13:41:33 -04:00
Stéphane Cerveau 750206067c gitlab: add issue template
Use the same bug template as in gstreamer repository

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1277>
2023-06-15 11:37:18 +00:00
Guillaume Desmottes 1df5b0d028 pbutils: implement debug() method on DiscovererInfo related structs
The default Debug implementation is not very useful but unfortunately
cannot be overridden.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1276>
2023-06-14 14:33:59 +02:00
Sebastian Dröge 827cb31bac deny: Remove obsolete duplicated Windows dependencies
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1275>
2023-06-12 13:22:37 +03:00
Sebastian Dröge d72884685a examples: Update to memmap2 0.7
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1275>
2023-06-12 13:22:28 +03:00
Sebastian Dröge df67a2d860 Update CHANGELOG.md for 0.20.6 2023-06-06 17:16:18 +03:00
Sebastian Dröge b89b135c93 pbutils: Move DiscovererStreamInfo iterators to an extension trait
This way it can also be called directly on subclasses.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1273>
2023-06-06 14:09:48 +03:00
Daniel Pendse 2becc79dfb rtsp-server: Add RTSPContext uri getter
Add uri getter from RTSPContext

Fix #469

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1271>
2023-06-05 10:41:59 +02:00
Sebastian Dröge 5f8aaed96b ci: Update to GTK 4.10.3
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1272>
2023-06-01 20:12:51 +03:00
Sebastian Dröge 093bc9b9cc ci: Update to rustup 1.26.0
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1272>
2023-06-01 20:11:05 +03:00
Sebastian Dröge a5fa1dab79 ci: Update to meson 1.1.1
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1272>
2023-06-01 20:10:38 +03:00
Sebastian Dröge f75aa5f1f8 ci: Update to Rust 1.70
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1272>
2023-06-01 20:10:19 +03:00
Sebastian Dröge 130805fc50 Ignore various endianness-dependent constants/enum values in the sys bindings
They can't be used verbatim and need special handling depending on the
target platform's endianness.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1270>
2023-05-29 16:45:29 +03:00
Sebastian Dröge 5f16254059 deny: Update for cocoa crates being in the middle of updates 2023-05-29 12:50:01 +03:00
Sebastian Dröge 2290262c2e gstreamer: Add fmt::Debug impls for owned Event/Query/Message too
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1269>
2023-05-24 10:36:08 +03:00
Guillaume Desmottes fadca54d51 gstreamer: event: manually implement Debug
Allow us to display more useful information.

Fix #467

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1268>
2023-05-23 15:28:29 +02:00
Guillaume Desmottes 53173eb46c gstreamer: query: manually implement Debug
Allow us to display more useful information.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1268>
2023-05-23 15:28:29 +02:00
Guillaume Desmottes 71b77c513d gstreamer: message: add structure to Debug views
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1268>
2023-05-23 15:24:19 +02:00
Guillaume Desmottes 3ffba2453d gstreamer: message: manually implement Debug
Allow us to display more useful information.

Fix #466

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1267>
2023-05-23 10:32:42 +02:00
Guillaume Desmottes 041a1f2a8e gstreamer: message: implement Display on Error, Warning and Info
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1267>
2023-05-23 08:36:13 +02:00
Sebastian Dröge b6919d7c99 examples: Update for DiscovererStreamInfo::stream_id() being nullable
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1266>
2023-05-22 12:17:13 +03:00
Sebastian Dröge a13dcad033 ci: Update image version for building newer GStreamer
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1266>
2023-05-22 12:15:46 +03:00
Sebastian Dröge 6ab34e1656 Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1266>
2023-05-22 12:15:07 +03:00
Sebastian Dröge 4d7809424f Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1266>
2023-05-22 12:13:31 +03:00
Jordan Petridis 2f75087830 ci: add openssl into the windows-image
Useful to build a couple of plugins, including dtls.

Related to gstreamer/gst-plugins-rs#346

Originally gstreamer/gstreamer!4607 but can't be merged yet
due to x86 issue.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1264>
2023-05-16 10:50:12 +00:00
Sebastian Dröge adea2428af gstreamer: Only retrieve the debug category once per log call
Each retrieval would go through the one-time-initialization check, i.e.
yet another branch, so let's avoid that.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1263>
2023-05-13 20:44:42 +03:00
Sebastian Dröge 4f8862e15b gstreamer: Remove unnecessary clone() in debug logging macros
The macro called from them is already doing the `clone()` itself.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1263>
2023-05-13 20:44:42 +03:00
Sebastian Dröge 074a2b1578 gstreamer: Use temporary GStr for the debug category constructors
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1263>
2023-05-13 20:44:42 +03:00
Sebastian Dröge 4384934b32 gstreamer: Mark DebugCategory as repr(transparent)
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1263>
2023-05-13 14:06:58 +03:00
François Laignel 9453d63631 gst/pad: [Ghost]PadBuilder: inherit name from template or target when possible
This commit adds convenience auto naming in the following cases:

* When building from a non wildcard-named template, the name of the template is
  automatically assigned to the Pad. User can override with a specific name by
  calling `name()` on the `PadBuilder`.
* When building with a target and no name was provided via the above, the
  GhostPad is named after the target.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1255>
2023-05-12 10:55:46 +00:00
François Laignel 7cb5473ba6 gst: Pad move name definition to builders
Also apply consistent naming for builder/non-builder constructors.

See discussion in:
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/448#note_1799092

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1255>
2023-05-12 10:55:46 +00:00
François Laignel 13f0483a44 gst: Manually impl Bin & Pipeline constructors
Set `Bin` & `Pipeline` constructors to manual implementation to remove
optional `name` argument (use builder to specify name).

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1255>
2023-05-12 10:55:46 +00:00
Sebastian Dröge ccf3b57a8b examples: Update to memmap2
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1262>
2023-05-12 09:44:03 +03:00
Sebastian Dröge 33d4969493 gstreamer: Get function name for logging outside the internal closure
Otherwise the function name will include the name of the closure.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1260>
2023-05-10 11:14:21 +03:00
Jordan Petridis 13f4085456 ci: Build again with --all-features when possible
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1259>
2023-05-08 23:39:31 +03:00
Sebastian Dröge 9d61e39ed2 ci: Pass --all-features to the documentation build
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1257>
2023-05-04 10:02:57 +03:00
Sebastian Dröge 3d82f9cb65 gstreamer-app: appsink: Remove duplicated and misnamed callbacks builder function
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1257>
2023-05-04 10:00:58 +03:00
Sebastian Dröge 3699da7314 Remove dox feature and replace by docsrs configuration
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1256>
2023-05-04 09:19:29 +03:00
Sebastian Dröge 5c331e7e77 ci: Update docs generation for new configuration mechanism
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1256>
2023-05-04 09:19:29 +03:00
Sebastian Dröge 40578ae7e9 Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1256>
2023-05-04 09:19:29 +03:00
Sebastian Dröge 5a24f2d9db Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1256>
2023-05-04 09:19:29 +03:00
Sebastian Dröge 0585476687 gstreamer: serde: Update for glib::FlagsClass API changes
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1253>
2023-04-24 09:57:26 +03:00
Sebastian Dröge b1577af7cf Update CHANGELOG.md for 0.20.5 2023-04-22 11:53:29 +03:00
Sebastian Dröge 5dd1decd6a ci: Update to Rust 1.69
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1251>
2023-04-20 18:06:03 +03:00
Sebastian Dröge 86eb6c2bd8 Fix a couple of new Rust 1.69 clippy warnings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1250>
2023-04-20 16:42:39 +03:00
Thibault Saunier 145664ec0d miniobject: Implement the HasParamSpec trait in the macro
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1249>
2023-04-17 11:00:49 -04:00
Johan Sternerup e026d922e4 gstreamr: bus: Add BusWatchGuard to automatically remove watch
Previously, with add_watch()/add_watch_local() you had to remember
calling remove_watch() in order not to leak the bus, the watch source
and two associated file descriptors. Now these methods instead return an
object of type BusWatchGuard that will automatically remove the bus
watch when the object is dropped.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1248>
2023-04-14 11:53:41 +03:00
Bilal Elmoussaoui 5c156737a4 gst-player: Implement Default for Player
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1231>
2023-04-11 09:42:40 +00:00
Guillaume Desmottes e108a908dc gstreamer: CHANGELOG: fix typo
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1247>
2023-04-10 11:19:00 +02:00
Guillaume Desmottes 98a8b75646 gstreamer: fix unused import in test
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1246>
2023-04-10 08:04:12 +02:00
Guillaume Desmottes 68e0ae9a9c ci: check for typos
https://github.com/crate-ci/typos is quite nice, and is even written in Rust.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1246>
2023-04-07 17:09:48 +02:00
Guillaume Desmottes 6fc969932b CHANGELOG: fix typos
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1246>
2023-04-07 17:09:48 +02:00
Guillaume Desmottes e75391139c fix typos in comments
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1246>
2023-04-07 17:09:48 +02:00
Guillaume Desmottes 3cb2454fd3 gstreamer: fix typo in GeoLocationLongitude tag
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1246>
2023-04-07 17:09:48 +02:00
Sebastian Dröge 341ac517d1 Update CHANGELOG.md for 0.20.4 2023-04-07 13:07:06 +03:00
Sebastian Dröge 2dbd99bd18 webrtc: Add missing prelude re-export of WebRTCICEExtManual 2023-04-07 11:57:01 +03:00
Sebastian Dröge 03d046daba Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1244>
2023-04-06 21:31:39 +03:00
Sebastian Dröge a11e5cfd75 Add manual changes for the new/changed 1.24 APIs
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1244>
2023-04-06 21:31:39 +03:00
Sebastian Dröge 4d787df819 ci: Run tests with v1_24 feature
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1244>
2023-04-06 21:08:51 +03:00
Sebastian Dröge ca2fd54230 Add v1_24 feature flag everywhere
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1244>
2023-04-06 21:08:51 +03:00
Sebastian Dröge fdbef66c24 Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1244>
2023-04-06 21:08:51 +03:00
Sebastian Dröge ce0ddc7be0 Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1244>
2023-04-06 21:08:51 +03:00
Sebastian Dröge 8b0398aa32 Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1244>
2023-04-06 21:08:51 +03:00
Sebastian Dröge a88b06f73e Update gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1244>
2023-04-06 21:08:51 +03:00
Sebastian Dröge a252de69b1 audio: Don't store a copy of the AudioInfo in AudioFrame
Instead just reference the one inside the FFI struct directly by making
sure that the memory representation of the FFI and Rust type are the
same.

This reduces the size of `AudioFrame` by about half.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1244>
2023-04-06 21:08:51 +03:00
Sebastian Dröge e584fdb17b video: Don't store a copy of the VideoInfo in VideoFrame
Instead just reference the one inside the FFI struct directly by making
sure that the memory representation of the FFI and Rust type are the
same.

This reduces the size of `VideoFrame` by about half.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1244>
2023-04-06 21:08:51 +03:00
Sebastian Dröge ca9d822042 deny: Update for older versions of the windows bindings 2023-04-05 12:03:13 +03:00
Thibault Saunier 98db1b546e validate: Expose gst_validate::print_action_types
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1227>
2023-04-04 11:50:49 -04:00
Thibault Saunier 9647ce8895 validate: reporter: Add a report_action() method
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1227>
2023-04-04 11:50:49 -04:00
Thibault Saunier b34718697c validate: init_debug and setup_test_file is meant to be called before init
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1227>
2023-04-04 11:50:49 -04:00
Thibault Saunier 8eae37c525 validate: Implement action types registration support
This is implemented mostly manually because the API is a bit weird
and we need to do some extra work to make it work properly.
Also basing it on a Builder makes it much nicer to user.

This commit also includes required new types either generated with `gir`
or manually implemented when required.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1227>
2023-04-04 11:50:49 -04:00
Thibault Saunier 68db910bc8 Update gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1227>
2023-04-04 11:50:49 -04:00
Seungha Yang 6cb19c1f18 examples: Add Direct2D/DirectWrite text rendering example
Similar to overlay-composition example but for Direct2D/DirectWrite

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1206>
2023-04-04 09:09:18 +00:00
Jimmi Holst Christensen 85e427345e Forward tag events to consumers in StreamProducer
Fix #386

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1045>
2023-04-04 07:31:58 +00:00
Sebastian Dröge 0ab72911ee ci: Update to GTK4 4.10.1
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1242>
2023-04-01 18:53:28 +03:00
Sebastian Dröge 954d88154c ci: Update to Rust 1.68.2
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1242>
2023-04-01 13:53:46 +03:00
Sebastian Dröge 81a5f25f81 examples: Update to windows 0.48
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1241>
2023-04-01 12:00:53 +03:00
Sebastian Dröge a7131fc051 examples: Update to windows 0.47
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1240>
2023-03-31 11:50:51 +03:00
Sebastian Dröge bc81e5a6a2 deny: Update to allow multiple versions of syn for now 2023-03-19 17:47:09 +02:00
Sebastian Dröge 6d3c9d931b examples: Update to windows 0.46
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1239>
2023-03-14 11:24:08 +00:00
Sebastian Dröge d2ef4023f7 Update CHANGELOG.md for 0.20.3 2023-03-14 13:23:51 +02:00
Sebastian Dröge 7344e4bab2 tutorials: Update for glib::Priority API changes
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1237>
2023-03-12 10:26:06 +02:00
Arun Raghavan 273f084c06 aggregator: Mark src_pad() return type as an AggregatorPad
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1236>
2023-03-09 23:18:04 -05:00
Jordan Petridis 368e1cacb6 ci: Update base image to debian 12 bookworm
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1234>
2023-03-09 21:03:28 +02:00
Sebastian Dröge fe038b7a14 rtsp-server: Work around GstRTSPClientClass ABI breakage in 1.18
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/455

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1233>
2023-03-09 16:23:29 +00:00
Sebastian Dröge 43b5cffc85 ci: Update to gtk 4.10.0
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1232>
2023-03-09 17:10:37 +02:00
Sebastian Dröge ce0fab9cf9 ci: Update to meson 1.0.1
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1232>
2023-03-09 17:09:31 +02:00
Sebastian Dröge b243ba1577 ci: Update to Rust 1.68
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1232>
2023-03-09 17:09:26 +02:00
Guillaume Desmottes 01d3cef73e gstreamer: element: more generic (un)link_many() API
No longer enforces to pass an array of references.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1230>
2023-03-09 14:27:25 +00:00
Guillaume Desmottes c4a968a403 gstreamer: bin: more generic {add,remove}_many() API
No longer enforces to pass an array of references.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1230>
2023-03-09 14:27:25 +00:00
Marc Wiblishauser 0bd6e07346 ParamSpecArray: fix type_ from fraction to array
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1229>
2023-03-09 10:29:37 +01:00
Sebastian Dröge 4b112a9bb8 video: Fix two new clippy warnings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1228>
2023-03-07 10:41:19 +02:00
Sebastian Dröge 37785b222a deny: Allow older windows-sys 0.42 for now 2023-03-01 14:02:48 +02:00
Guillaume Desmottes 32a02b51e1 utils: streamproducer: document forward_eos default value
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1226>
2023-02-28 09:48:36 +01:00
Ruben Gonzalez 0b922b0e89 examples: zoom effect with compositor and navigations events
Use can change the video player zoom using the next keys:

  * +: Zoom in
  * -: Zoom out
  * Up/Down/Right/Left: Move the frame
  * r: reset the zoom

Also mouse navigation events can be used for a better UX.

Furthermore, it works with an pipeline using other video compositor
filters like glvideomixer. For instance:

  glvideomixer \
    name=mix background=1 \
    sink_0::xpos=0 sink_0::ypos=0 sink_0::zorder=0 \
    sink_0::width={WIDTH} sink_0::height={HEIGHT} \
  ! glimagesinkelement \
  gltestsrc pattern=mandelbrot name=src \
  ! video/x-raw(memory:GLMemory),framerate=30/1,width={WIDTH},height={HEIGHT},pixel-aspect-ratio=1/1 \
  ! queue \
  ! mix.sink_0

Probe was added in the sink pad to get direct navigation events w/o
transformation done by the mixer. More info about it in the PR [1].

[1] https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1495

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1217>
2023-02-22 20:41:06 +01:00
Sebastian Dröge 0056c62cec Update CHANGELOG.md for 0.20.2 2023-02-21 17:03:54 +02:00
François Laignel 58475f4a25 {Audio,Video}CapsBuilder: add for_encoding constructor
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1222>
2023-02-20 09:05:51 +00:00
Sebastian Dröge 8b6bf18bb0 ci: Update to rustup 1.25.2
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1223>
2023-02-20 10:42:07 +02:00
Sebastian Dröge b6e253acbf Update minimum supported Rust version to 1.66
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1223>
2023-02-20 10:42:07 +02:00
Sebastian Dröge de01403658 ci: windows: Update to dav1d 1.1.0
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1223>
2023-02-20 10:42:07 +02:00
Sebastian Dröge b3980b389d ci: Build GStreamer from the main branch again
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1223>
2023-02-20 10:42:07 +02:00
SeaDve 862f4d014c gstreamer: Add seconds_f32 & seconds_f64 methods and from_seconds_f32 & from_seconds_f64 constructor for ClockTime and Signed<ClockTime>
Closes #443

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1223>
2023-02-20 10:42:07 +02:00
SeaDve cd8e8cea5a gstreamer-play: impl default for Play
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1224>
2023-02-19 10:28:48 +08:00
SeaDve 12b4a9a03d gstreamer: implement HasParamSpec for ClockTime
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1221>
2023-02-14 23:40:28 +08:00
Sebastian Dröge 70b42a4846 Update CHANGELOG.md for 0.20.1 2023-02-13 15:02:49 +02:00
Sebastian Dröge f0bb4e5bef video: Don't leak the gst::Buffer when converting a VideoFrame into an ffi::GstVideoFrame
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1219>
2023-02-13 14:29:10 +02:00
Sebastian Dröge 6ffb1db482 video: Don't forget to unmap the VideoFrame when converting into a gst::Buffer
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1219>
2023-02-13 14:28:47 +02:00
Sebastian Dröge 2ac85cd8de audio: Don't forget to unmap the AudioBuffer and drop the Box when converting into a gst::Buffer
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1219>
2023-02-13 14:27:10 +02:00
Sebastian Dröge 60ad9b5038 gstreamer: Add a test for various combinations of element_error! string formatting 2023-02-13 11:40:41 +02:00
Sebastian Dröge 6f06a26327 Add support for inline variable names in error/warning/info message creation macros
Simply by removing the special-casing of string literals, which doesn't
really bring any improvements here.

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

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1216>
2023-02-12 13:27:59 +02:00
Sebastian Dröge 7d9c12f8d1 ci: Build 0.20 docs and drop 0.18 docs 2023-02-10 00:16:13 +02:00
Sebastian Dröge 13140d8b8a Update versions to 0.21.0 2023-02-09 23:42:32 +02:00
Sebastian Dröge d284fcdca0 Update CHANGELOG.md for 0.20.0 2023-02-09 23:41:58 +02:00
Sebastian Dröge b9f36c1b42 Update CHANGELOG.md for 0.19.8 2023-02-09 21:38:00 +02:00
Sebastian Dröge f6f0465655 Remove various unnecessary clippy allow attributes
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1214>
2023-02-07 21:13:19 +02:00
Sebastian Dröge 9155d6eb7b Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1214>
2023-02-07 21:00:46 +02:00
Sebastian Dröge c2dd69dfac Update gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1214>
2023-02-07 20:59:41 +02:00
Sebastian Dröge 8692caa0a6 Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1214>
2023-02-07 20:59:31 +02:00
Sebastian Dröge 172e22c4b3 gstreamer: Implement glib::HasParamSpec for our custom pspecs
This allows using `gst::Fraction` / `gst::Array` properties via the new
properties macro.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1213>
2023-02-06 15:21:02 +02:00
Sebastian Dröge 91eec7a33f Migrate everything to object lock API instead of custom GMutex handling
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1212>
2023-02-06 10:50:33 +02:00
Anders Hellerup Madsen 3ddbdbd383 gstreamer-gl: Require object lock in GLDisplay
The methods `gst_gl_display_get_gl_context_for_thread()`,
`gst_gl_display_create_context()`, `gst_gl_display_add_context()` and
`gst_gl_display_remove_context()` now require the display's object lock
to be held when called.

This is required by the C API.

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

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1212>
2023-02-06 10:10:18 +02:00
Anders Hellerup Madsen a021aaa3ce gstreamer: Add object_lock method to gst::Object
See https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/439

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1212>
2023-02-06 10:10:18 +02:00
Christian Meissl 77866a52df gstreamer-allocators: allow to subclass fd memory allocators
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1186>
2023-02-04 19:49:44 +01:00
Sebastian Dröge 00281e98f0 gstreamer: Rename TagSetter::add() to TagSetter::add_tag() to not conflict with Bin::add()
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/440

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1211>
2023-02-04 16:44:40 +02:00
Jordan Petridis c4dc549a5e ci: Make the plugin update jobs depend on the image builds
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1210>
2023-02-02 14:04:10 +02:00
Sebastian Dröge 478606e44c Use glib::Object::new() instead of new_default()
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1209>
2023-01-31 12:05:53 +02:00
Sebastian Dröge c62530e181 Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1209>
2023-01-31 10:49:39 +02:00
Sebastian Dröge f1db72dab2 Update gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1209>
2023-01-31 10:47:04 +02:00
Sebastian Dröge 51611ba779 Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1209>
2023-01-31 10:46:51 +02:00
Sebastian Dröge a7f670df7a Return exit code from gio::Application::run() from main()
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1208>
2023-01-27 19:02:03 +02:00
Sebastian Dröge 5f05f7ec05 gl: Mark other_context in GLDisplay::create_context() as nullable
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/438

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1207>
2023-01-27 16:29:49 +02:00
Sebastian Dröge 01bbb07744 ci: Update to Rust 1.67
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1205>
2023-01-26 18:56:35 +02:00
Sebastian Dröge 5cea810820 gstreamer: Add bindings for Message::structure_mut()
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1204>
2023-01-26 15:28:42 +02:00
Sebastian Dröge f24b38470b Fix various new clippy warnings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1203>
2023-01-25 10:18:33 +02:00
Sebastian Dröge 7efc22ebc9 Require GStreamer 1.22.0 instead of 1.21.0 when selecting v1_22
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1201>
2023-01-24 13:01:05 +02:00
Sebastian Dröge ecfb10649a Add 1.22 to extra_versions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1201>
2023-01-24 13:00:53 +02:00
Sebastian Dröge 4b99aae824 gstreamer: Create plugins for version 1.22 if selected
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1201>
2023-01-24 12:58:32 +02:00
Sebastian Dröge e82a1d0eb8 gstreamer: Mark MessageType enum as non-exhaustive
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1201>
2023-01-24 12:57:05 +02:00
Sebastian Dröge 8585158880 ci: Update gtk4 to 4.8.3
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1201>
2023-01-24 12:53:50 +02:00
Sebastian Dröge 848ed9c1e5 ci: Update to meson 1.0.0
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1201>
2023-01-24 12:53:06 +02:00
Sebastian Dröge f56febfd35 ci: Rebuild image for 1.22.0
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1201>
2023-01-24 12:52:44 +02:00
Sebastian Dröge 0f1c937465 Regenerate with latest gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1201>
2023-01-24 12:50:26 +02:00
Sebastian Dröge 73a9a5b3a3 Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1201>
2023-01-24 12:49:36 +02:00
Sebastian Dröge 72d1f72edc Update gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1201>
2023-01-24 12:49:36 +02:00
Sebastian Dröge c33fb38ca1 gstreamer: Mark various enums as exhaustive
This reduces their size to 4 bytes instead of 5 bytes, and as such makes
it possible to store them in a register on 32 bit platforms too.
Additionally it makes it possible for enums like
`Result<FlowSuccess, FlowReturn>` to be stored in a single register on
64 bit platforms.

Also the conversions between the C and Rust type is a simple copy of the
value now instead of a mapping.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1200>
2023-01-24 11:07:33 +02:00
Sebastian Dröge 2c2a6c3871 Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1200>
2023-01-24 10:40:31 +02:00
Sebastian Dröge d6bf3e1c3b Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1200>
2023-01-24 10:39:01 +02:00
Sebastian Dröge 36f89e19fc gstreamer: Deprecate ElementFactory::create_with_properties() and make_with_properties()
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1199>
2023-01-23 13:06:54 +00:00
Sebastian Dröge dc5e408c2d gstreamer: Add various convenience From impls for Caps, BufferList, CapsFeatures, Buffer and VideoOverlayComposition
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1199>
2023-01-23 13:06:54 +00:00
Sebastian Dröge eadb3c6db2 audio: Reduce size of AudioInfo from 832 to 320 bytes and make audio channel position handling more efficient
Assume that there are never more than 64 named channel positions and by
that provide an 1:1 mapping between the C and Rust types.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1198>
2023-01-23 12:58:16 +02:00
Sebastian Dröge 0f859b9029 Get README.md in sync again
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/437
2023-01-23 12:01:07 +02:00
Seungha Yang 8ef4420257 examples: d3d11videosink: Update for windows crate v0.44
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1197>
2023-01-23 03:01:17 +09:00
Sebastian Dröge d5e24b9fbd Update various object construction functions to more efficient approaches
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1196>
2023-01-22 09:48:51 +02:00
Sebastian Dröge 38dd1f462b gstreamer: Use obj() instead of instance() in the remaining places
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1196>
2023-01-22 09:14:50 +02:00
Sebastian Dröge 257a049673 gstreamer: Mark ParamSpec constructors as deprecated in favour of the builders
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1196>
2023-01-22 09:14:50 +02:00
Sebastian Dröge 24a16a43b6 Update CHANGELOG.md for 0.19.7 2023-01-19 19:05:17 +02:00
Sebastian Dröge d6e9cd33c0 gstreamer: Make allocation query caps optional
See also https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3752

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1194>
2023-01-19 16:08:16 +02:00
Sebastian Dröge 56498aa856 Fix version links in CHANGELOG.md 2023-01-18 16:53:08 +02:00
Sebastian Dröge a6abe15678 Update CHANGELOG.md for 0.19.6 release 2023-01-18 16:53:05 +02:00
Sebastian Dröge 82cf6e7842 Update for glib::Boxed ToGlibPtr<*mut _> trait impl addition
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1192>
2023-01-17 09:59:02 +02:00
Sebastian Dröge c2e7abd128 utils: streamproducer: Persist ConsumptionLink state when changing producers
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1189>
2023-01-16 16:16:15 +02:00
Sebastian Dröge 094d74e391 utils: streamproducer: Add ConsumptionLink::appsrc() getter
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1189>
2023-01-16 14:41:06 +02:00
Sebastian Dröge 0a6ed3c717 utils: streamproducer: Add new ConsumptionLink::disconnected() constructor
This allows constructing a new consumption link from an `appsrc` without
having it connected from the very beginning.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1189>
2023-01-16 14:41:06 +02:00
Sebastian Dröge dd284a80ea utils: streamproducer: Add ConsumptionLink::set_discard() to stop forwarding buffers for a while
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1189>
2023-01-16 14:41:06 +02:00
Sebastian Dröge a68c37e4eb utils: streamproducer: Remove StreamProducer::forward()
Most applications forget to call `forward()` in the beginning and then
nothing works.

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

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1189>
2023-01-16 14:41:06 +02:00
Sebastian Dröge f8d17555c5 utils: streamproducer: Add #[must_use] attribute to add_consumer()
Simply discarding the result will immediately disconnect it again, which
was likely not intended and can easily lead to bugs.

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

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1189>
2023-01-16 14:41:06 +02:00
Sebastian Dröge 8aa3e4417c gstreamer: Fix another typo in macro 2023-01-16 11:30:56 +02:00
Sebastian Dröge 2a11b9d2cf gstreamer: Fix typo in macro 2023-01-16 11:30:08 +02:00
Sebastian Dröge 64abf69987 Use glib::function_name! instead of module_path! macro in more places
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1191>
2023-01-16 11:10:21 +02:00
Sebastian Dröge 3e2eb6e652 gstreamer: Reduce code bloat in panic handling
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1191>
2023-01-16 11:08:02 +02:00
Sebastian Dröge 3a340d0a89 gstreamer: Implement Structure::from_iter() more generically 2023-01-15 23:06:45 +02:00
Sebastian Dröge 003554876c Update various APIs to use glib::GStr
Currently only covers what is needed to keep code compiling, plus
everything caps/structure/tags related.

This avoids unnecessary heap allocations for adding the NUL-terminator
of C strings, and especially makes caps/structure handling as efficient
as in C.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1190>
2023-01-15 21:05:57 +02:00
Sebastian Dröge ea136515cf Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1190>
2023-01-15 20:17:11 +02:00
Sebastian Dröge 6152dd7e3b Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1190>
2023-01-15 20:17:10 +02:00
Sebastian Dröge aa23ddbbdb gstreamer: Simplify element subclass panic catching functions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1188>
2023-01-14 17:13:53 +02:00
Sebastian Dröge 37bfb78fdc Change some assertions to debug assertions
These assertions can only trigger because of bugs in the bindings
implementation or in the C code and not because of bugs in calling code,
so using debug assertions is perfectly fine for them and reduces the
number of assertions inlined everywhere in release builds.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1188>
2023-01-14 17:13:46 +02:00
Sebastian Dröge f235dc987d Inline various trivial functions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1177>
2023-01-11 11:33:54 +02:00
Sebastian Dröge 0fccb73eb6 gstreamer: Remove unnecessary cast in gst::element_imp_error! and others
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1187>
2023-01-11 09:06:38 +00:00
Sebastian Dröge 608cae3703 gstreamer: Register only a single type instead of per return value for the gst::Iterator::filter() GValue
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1187>
2023-01-11 09:06:38 +00:00
Sebastian Dröge f07727ee6d Use uninitialized stack memory for out parameters instead of zeroed memory if applicable
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1187>
2023-01-11 09:06:38 +00:00
Sebastian Dröge 1b022a6b7c Get rid of unnecessary option wrapping
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1187>
2023-01-11 09:06:38 +00:00
Christian Meissl da2eb50dd3 gstreamer-video: implement VideoBufferPoolConfig for BufferPoolConfigRef
implementing VideoBufferPoolConfig for BufferPoolConfigRef
instead of BufferPoolConfig allows to retrieve the VideoAlignment
from within buffer pool set_config

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1185>
2023-01-08 19:15:46 +01:00
Sebastian Dröge 84720eee66 gstreamer: Use Value::from_type_unchecked() where applicable
Gets rid of some unnecessary assertions.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1184>
2023-01-06 10:41:55 +02:00
Sebastian Dröge 89326c7e7c Compile out GStreamer version checks if a high enough version is configured at build time
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1184>
2023-01-06 10:41:55 +02:00
Sebastian Dröge 277d63601c gstreamer: Return glib::GString for the error/warning/info message debug string
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1184>
2023-01-06 10:41:55 +02:00
Sebastian Dröge ba1d8c5ce6 gstreamer: Move initialization panic into a separate function
This keeps the number of duplicated panics all over the codebase lower
and reduces generated code size.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1184>
2023-01-05 21:33:14 +02:00
Sebastian Dröge 7b279b9d6c gstreamer-app: Assert that GStreamer is initialized before creating instances
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1184>
2023-01-05 21:33:14 +02:00
Sebastian Dröge 8d30bcbf4b Use IntoGlibPtr trait instead of to_glib_full() where appropriate to reduce unnecessary refcounting/copying
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1183>
2023-01-05 12:09:57 +02:00
Sebastian Dröge 5e852fa0ff gstreamer-video: Autogenerate part of the VideoDecoder subframe API
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1183>
2023-01-05 12:09:57 +02:00
Sebastian Dröge 315704fe67 gstreamer-check: Simplify borrowing of sink/src harnesses
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1183>
2023-01-05 12:09:57 +02:00
Sebastian Dröge 1e793f3b65 gstreamer: Return some values by reference instead
Less refcounting.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1183>
2023-01-05 12:09:57 +02:00
Sebastian Dröge 32a608b76b examples: Fix for API changes
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1182>
2023-01-04 13:26:07 +02:00
Sebastian Dröge b94bfe1613 gstreamer: Remove useless GstPluginExtManual trait
`Plugin` is a final type.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1182>
2023-01-04 13:25:17 +02:00
Sebastian Dröge a028e807df gstreamer: Autogenerate some more API
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1182>
2023-01-04 13:25:17 +02:00
Sebastian Dröge 7490846309 Fix compilation due to changes in autogenerated code
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1182>
2023-01-04 13:25:17 +02:00
Sebastian Dröge 567ce0a3bf Group and merge imports in all manual code
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1182>
2023-01-04 13:25:17 +02:00
Sebastian Dröge 45c145ad50 Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1182>
2023-01-04 13:25:17 +02:00
Sebastian Dröge dce54ee237 Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1182>
2023-01-04 13:22:39 +02:00
Sebastian Dröge 0e51e70c5a Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1182>
2023-01-04 13:22:39 +02:00
Sebastian Dröge 6ff5f89832 gstreamer: Fix memory leak in buffer pool subclassing test
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1180>
2023-01-03 10:41:35 +00:00
Sebastian Dröge 0ed3d95c60 gstreamer: Use glib::StrV internally instead of a custom version of it
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1180>
2023-01-03 10:41:35 +00:00
Sebastian Dröge 81bcf5c8dd gstreamer-video: Implement VideoTimeCode via glib::wrapper!
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1180>
2023-01-03 10:41:35 +00:00
Sebastian Dröge 30838b6549 gstreamer-video: Implement VideoTimeCodeInterval via glib::wrapper!
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1180>
2023-01-03 10:41:35 +00:00
Sebastian Dröge cbd3035a5b gstreamer: Implement gst::Segment via glib::wrapper!
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1180>
2023-01-03 10:41:35 +00:00
Sebastian Dröge 8ed150c853 gstreamer: Add missing doc alias
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1180>
2023-01-03 10:41:35 +00:00
Sebastian Dröge ae688406f8 gstreamer: Allocate debug messages up to 256 bytes on the stack and only then spill over into the heap
With this, debug logging from Rust is completely allocation-less for
short messages and string literals.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1179>
2023-01-03 10:28:43 +00:00
Sebastian Dröge 06a0dbacba gstreamer: Don't inline debug logging function
It's relatively big and increases code size and stack usage quite a bit,
and having a function call for logging is not going to make much of a
difference as it happens *after* filtering for the debug level
threshold.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1179>
2023-01-03 10:28:43 +00:00
Sebastian Dröge 036a020b62 gstreamer: Optimize various from/to Vec FFI translation functions
Use memcpys if possible instead of manual loops, and directly write into
the `Vec` memory and set the length afterwards to avoid having the
reallocate logic at every step.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1181>
2023-01-03 12:06:29 +02:00
Sebastian Dröge 882513d33a Make use of the new TransparentType / TransparentPtrType traits
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1178>
2023-01-02 19:07:24 +02:00
Jordan Petridis aeca82c095 ci: Update examples features on windows
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1089>
2022-12-28 14:37:24 +02:00
Seungha Yang b4d3bf297e examples: Add d3d11videosink example with Direct2D/DirectWrite interop
Demonstartes the use of d3d11videosink's present signal
introduced in
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2923
with Direct2D/DirectWrite API interop using the windows crate.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1089>
2022-12-28 11:20:51 +00:00
Sebastian Dröge e6e5d25e48 Update CHANGELOG.md for 0.19.5 2022-12-27 12:53:30 +02:00
Jordan Petridis e9ecdcdd72 ci/windows: Update base image
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1175>
2022-12-26 16:17:19 +02:00
Sebastian Dröge 3d0f563111 Update minimum supported Rust version to 1.64
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1175>
2022-12-25 14:54:38 +02:00
Jordan Petridis 141a71d69e ci: Avoid building examples with --all-features
--all-features ends up enabling the windows and trying to compile
the d3d example, which can't be built on linux.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1175>
2022-12-25 13:25:30 +02:00
Jordan Petridis dfc6344f59 ci: move tests scripts to individual files
Instead of inling bash scripts in yaml

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1175>
2022-12-25 13:25:30 +02:00
Sebastian Dröge 146b4fc08e gstreamer: Fix glib::GStr API changes 2022-12-25 00:25:42 +02:00
Sebastian Dröge cdc7aa4846 gstreamer: Allow returning Handled from BufferList pad probes
This is handled exactly the same way as buffers.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1174>
2022-12-23 12:21:18 +00:00
Sebastian Dröge dcfea9c35a gl: Reset video frame size/stride/offset to 0 for GL mapped frames
The memory pointers are actually the GL texture IDs, and accessing them
like raw video memory will read random memory areas.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1173>
2022-12-22 19:25:54 +00:00
Sebastian Dröge d6cc452cf3 Use PhantomData as Stash::Storage if nothing has to be stored except for a lifetime
This reduces the size of all stashes from two pointers to one.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1171>
2022-12-20 17:07:39 +00:00
Sebastian Dröge f166e80a79 gstreamer: Only use a single temporary Vec for [T]::to_glib_none() for miniobjects
The value itself is already kept alive via the stash and we only need a
temporary `Vec` to be able to append the terminating `NULL` pointer.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1171>
2022-12-20 17:07:39 +00:00
Sebastian Dröge e70536f6b2 ci: Rebuild CI images another time to get latest GStreamer version
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1169>
2022-12-18 11:50:23 +00:00
Jordan Petridis f7b848b3cd ci/install-{gst,gtk}.sh: run ldconfig after meson install
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1169>
2022-12-18 11:50:23 +00:00
Jordan Petridis cd49019941 ci/install-{gst, gtk}: update meson command usage
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1169>
2022-12-18 11:50:23 +00:00
Jordan Petridis 7ecc11564d ci/install-{gst, rust}.sh: add shebangs to the scripts
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1169>
2022-12-18 11:50:23 +00:00
Jordan Petridis 7b3b4f56ee ci/install-{gst, gtk}.sh: reformat to make it more readable
Split commands and strings to multiple lines

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1169>
2022-12-18 11:50:23 +00:00
Jordan Petridis bed4b8644b ci: Include x264 in the gst build
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1169>
2022-12-18 11:50:23 +00:00
Jordan Petridis 6c7196732e ci: Include gpl plugins when building gst
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1169>
2022-12-18 11:50:23 +00:00
Jordan Petridis 8344cbc829 ci: use a multiline string for FDO_DISTRIBUTION_PACKAGES
Makes it easier to read and change

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1169>
2022-12-18 11:50:23 +00:00
Sebastian Dröge 3764bf75f8 Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1170>
2022-12-16 22:09:29 +02:00
Sebastian Dröge d7a292ec00 video: Update for NavigationModifierType flags value rename
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1170>
2022-12-16 22:09:29 +02:00
Sebastian Dröge 7113458128 ci: Rebuild the image for getting newer GStreamer
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1170>
2022-12-16 18:47:06 +02:00
Sebastian Dröge 2e2b572215 Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1170>
2022-12-16 18:46:51 +02:00
Sebastian Dröge 8c22ba25f8 Update CHANGELOG.md for 0.19.4 2022-12-16 11:56:04 +02:00
Sebastian Dröge 857f3740e2 Fix some more new clippy warnings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1167>
2022-12-15 18:35:49 +02:00
Sebastian Dröge c32607a010 ci: Update to Rust 1.66 and meson 0.64.1
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1167>
2022-12-15 18:16:57 +02:00
Jordan Petridis 9deb507286 ci: Only check default and latest feature version build
Testing all the version makes the job slower for not that much
gain. Disable some of them for now.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1166>
2022-12-13 21:18:12 +02:00
Jordan Petridis d867077c3a ci: Combine windows features builds
Part of gstreamer/gstreamer-rs#417

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1166>
2022-12-13 20:43:24 +02:00
Arun Raghavan c3a950f207 audio: Add bindings for GstAudioFilter
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1165>
2022-12-13 12:27:05 -05:00
Sebastian Dröge e3ad1918dc Fix various new clippy warnings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1164>
2022-12-13 11:29:45 +02:00
Piotr Brzeziński e579eb5d84 examples/tutorials: Use NSApp terminate() instead of sending an event
Has the same effect while being much more concise.
Unfortunately the cocoa crate doesn't (yet?) have bindings for this
function, so objc::msg_send! had to be used directly.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1162>
2022-12-11 22:09:54 +01:00
Sebastian Dröge 0fa8d0d62f gstreamer: Fix formatting if a string literal needs formatting
E.g. "blabla {some_variable}" is a string literal but needs formatting,
so we can't just pass it as a literal to the logger.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1161>
2022-12-11 12:20:35 +02:00
Sebastian Dröge 2a935320e7 gstreamer: Replace some generic function parameters with impl trait
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1160>
2022-12-10 20:18:11 +02:00
Sebastian Dröge ef5d5f50e4 gstreamer: Actually log the function name instead of the module name
As there is no way to get the function name as a string literal
currently, we have to copy locally into a NUL-terminated array.
Up to 256 bytes this is managed on the stack, otherwise a heap
allocation is necessary.

For the <256 bytes case the compiler is optimizing most of this away.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1160>
2022-12-10 20:18:11 +02:00
Sebastian Dröge 355ebc243f gstreamer: Add DebugCategory::above_threshold() to check if the category's threshold is above the given level
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1160>
2022-12-10 20:18:11 +02:00
Sebastian Dröge b58d518aa3 gstreamer: Use glib::GStr for DebugMessage string API too
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1160>
2022-12-10 20:18:11 +02:00
Sebastian Dröge de04e3f827 gstreamer: Reduce allocations in custom logging functions for the file/function strings
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1160>
2022-12-10 20:18:11 +02:00
Sebastian Dröge 0e7f5a19df gstreamer: Require using a NUL-terminated UTF-8 string or a string literal for the logging ID
Otherwise each log will involve a new allocation just for the ID.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1160>
2022-12-10 20:18:11 +02:00
Sebastian Dröge 2be477b753 gstreamer: Make logging of messages from a string literal allocation-free if using GStreamer 1.20 or newer
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1160>
2022-12-10 20:18:11 +02:00
Sebastian Dröge 3a61276cdd gstreamer: Reduce some allocations for passing the filename/module name to the logging functions
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1160>
2022-12-10 20:18:11 +02:00
Sebastian Dröge 750422d8eb gstreamer: Reduce some code duplication in the logging code
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1160>
2022-12-10 15:48:02 +02:00
Jordan Petridis 1935e04dd8 ci: Fix DAG deps for contianer build jobs
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1159>
2022-12-09 17:37:01 +02:00
Sebastian Dröge 3ab7bc7648 gstreamer: Add bindings for new 1.22 debug log ID API
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1159>
2022-12-09 17:37:01 +02:00
Sebastian Dröge a54c234fc6 gstreamer: Directly use fields for DebugCategory getters
This allows for better optimizations as it doesn't go through an opaque
FFI function.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1159>
2022-12-09 17:37:01 +02:00
Sebastian Dröge e8859951d3 gstreamer: Ignore EventType::to_sticky_ordering
This is handled manually via the `PartialOrd` impl.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1159>
2022-12-09 17:37:01 +02:00
Sebastian Dröge 7012fa638e Regenerate with latest gir/gir-files/gst-gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1159>
2022-12-09 17:37:01 +02:00
Sebastian Dröge 40a5a9edaa ci: Update Windows docker base image
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1159>
2022-12-09 17:37:01 +02:00
Sebastian Dröge 6a5d16d817 ci: Update image version to get newer GStreamer
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1159>
2022-12-08 20:03:54 +02:00
Sebastian Dröge 73ac98218f Update gst-gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1159>
2022-12-08 20:03:54 +02:00
Sebastian Dröge 407f03af0c Update gir-files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1159>
2022-12-08 20:03:54 +02:00
Sebastian Dröge 9d1cc19162 Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1159>
2022-12-08 20:03:54 +02:00
Sebastian Dröge b89b98b6e9 Update CHANGELOG.md for 0.19.3 2022-11-28 10:16:21 +02:00
Sebastian Dröge b5fcbc9657 gstreamer: Get rid of some unnecessary unsafe API usage
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1157>
2022-11-27 00:59:38 +02:00
Sebastian Dröge 0bc16c65f0 gstreamer: Add some API for add new items to a gst::Array and gst::List
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1157>
2022-11-27 00:59:38 +02:00
Sebastian Dröge ae4dd88f3d Update for GLib Into<Value> changes
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1156>
2022-11-26 15:19:35 +02:00
Sebastian Dröge 0b013001b7 Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1156>
2022-11-26 15:01:10 +02:00
Sebastian Dröge 92d8df4ac3 Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1156>
2022-11-26 15:01:10 +02:00
Jordan Petridis e87de384e1 ci: avoid always running build/test jobs
Introduce a trigger job with rules that will allow it to always
run when the MR is assigned to Marge and the final tests will be
run before being merge.

This means that Post-merge pipelines and MR pipelines that are
not assigned to Marge, will require a manual run of the trigger
job before the build/test will execute.

This should help easy the load on the gitlab runners.

Related to gstreamer/gstreamer-rs#417

Close gstreamer/gstreamer-rs#401

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1155>
2022-11-23 18:44:12 +02:00
Sebastian Dröge 3da927a856 gstreamer: Fix sticky event ordering for instant-rate-change
The event type for instant-rate-change events was poorly chosen, leading
to them being re-sent too late and even after EOS.

See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3387

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1154>
2022-11-21 13:43:22 +02:00
Sebastian Dröge cbfc19ccfc Regenerate with latest GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1153>
2022-11-21 13:29:38 +02:00
Sebastian Dröge 1ee4845544 video: Remove gst_video_format_info_get_tile_sizes() bindings and bind new VideoTileInfo API
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1153>
2022-11-21 13:29:38 +02:00
Sebastian Dröge 1fb531bba2 base: Add manual bindings for new 1.22 typefind helper API
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1153>
2022-11-21 13:23:38 +02:00
Sebastian Dröge e763e4fdde audio/video: Hide force-live property of Audio/VideoAggregator
The base class already provides a getter/setter for this.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1153>
2022-11-21 13:04:49 +02:00
Sebastian Dröge d388cbda13 ci: Rebuild for new GStreamer version
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1153>
2022-11-21 13:04:49 +02:00
Sebastian Dröge b482ef4af5 Update GStreamer gir files
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1153>
2022-11-21 13:04:49 +02:00
Sebastian Dröge fa5491e6b3 Use borrowed miniobject/structure types in more places
When the function does not keep around an additional reference of the
value this is correct and more flexible for callers.

https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/420

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1152>
2022-11-21 12:40:37 +02:00
Sebastian Dröge 5a0152b469 gstreamer: tracer: Pass &QueryRef instead of &Query to the functions
To make it impossible for implementor to keep around a reference to the
query as that would break element code that actually tries to answer the
query.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1152>
2022-11-21 12:40:37 +02:00
Sebastian Dröge 1264eb10ac gstreamer: Add PartialEq impls between owned/borrowed miniobjects/structures
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1152>
2022-11-21 12:40:37 +02:00
Sebastian Dröge 56b9b66027 gstreamer: Implement FromIterator<Caps> and Extend<Caps> for Caps
This allows easily generating new/extending existing caps from an
iterator.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1151>
2022-11-21 10:10:04 +02:00
Sebastian Dröge 774fafd987 gstreamer: Implement From<T> for Signed<T>
This makes usage simpler in a few places.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1150>
2022-11-18 12:07:13 +02:00
Edward Hervey 77fd187986 format: Add Signed<T> <=> signed integer conversions
Co-authored-by: Sebastian Dröge <sebastian@centricular.com>
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1149>
2022-11-16 16:32:24 +02:00
Sebastian Dröge 88791294a5 Update CHANGELOG.md for 0.19.2 2022-11-13 20:13:29 +02:00
Sebastian Dröge 9ba448427d Regenerate with latest gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1148>
2022-11-12 17:40:16 +02:00
Sebastian Dröge a6ef6dd1ec Update gir
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1148>
2022-11-12 17:39:12 +02:00
Sebastian Dröge c69ff617f5 ges: Don't generate version constants in the -sys crate
They will change with every new version and make the tests fail if
running against a different version.

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

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1146>
2022-11-12 16:48:33 +02:00
Elie Génard f1c8869447 gstreamer: Add gst::Allocator subclassing support 2022-11-08 19:28:42 +00:00
Sebastian Dröge 58e51417c0 ci: Rebuild image to get updated GStreamer version 2022-11-08 19:07:48 +02:00
Sebastian Dröge d3543efec2 gstreamer: Manually implement Allocator::register()
Due to a bug it causes use-after-free in versions < 1.20.5, so work
around that here.
2022-11-08 19:07:48 +02:00
Sebastian Dröge 32c432655f Regenerate with latest GStreamer gir files 2022-11-08 18:15:34 +02:00
Sebastian Dröge 220da7f1e0 Update GStreamer gir files 2022-11-08 18:13:10 +02:00
Sebastian Dröge e2b38774cf ci: Update to gtk 4.8.2 2022-11-03 17:06:53 +02:00
Sebastian Dröge 7079768dd7 ci: Update to meson 0.63.3 2022-11-03 17:06:53 +02:00
Sebastian Dröge 19949fa2c9 ci: Update to Rust 1.65 2022-11-03 17:06:44 +02:00
Sebastian Dröge efb85f416e ci: Only warn about unknown lints instead of denying 2022-11-01 11:14:31 +02:00
Sebastian Dröge 01e24d2018 Fix various new clippy warnings 2022-11-01 11:10:57 +02:00
Sebastian Dröge 951f000622 examples: glupload: Set sync point on the GL buffer as soon as possible
And also add API for getting the GL context from a `GLBaseMemory`.
2022-10-25 06:51:39 +00:00
Sebastian Dröge c6cbf86012 examples: glupload: Fix iterating over elements inside glsinkbin
Some elements might not have a factory so handle this gracefully instead
of erroring out.
2022-10-25 06:51:39 +00:00
Sebastian Dröge 2cad43cd0f ci: Remove 0.16 and 0.17 docs
Otherwise the pages are too big.
2022-10-24 20:09:15 +03:00
Sebastian Dröge 2bffc4e5ec Fix 0.19.1 release date in the changelog 2022-10-24 12:34:21 +03:00
Sebastian Dröge 708ad14422 Update CHANGELOG.md for 0.19.1 2022-10-24 12:32:45 +03:00
Sebastian Dröge 90b8ee2022 Move from imp.instance() to imp.obj()
It's doing the same thing and is shorter.
2022-10-23 23:06:44 +03:00
François Laignel 87ea535bc1 gst/log: accept non-ref obj in macros 2022-10-23 20:44:38 +02:00
Sebastian Dröge 67ecf0823d ci: Add 0.19 release to the docs job 2022-10-22 21:12:40 +03:00
Sebastian Dröge 92215f4a63 Add missing README.md to new crates 2022-10-22 21:12:23 +03:00
Sebastian Dröge 031133c179 Update versions to 0.20.0 2022-10-22 20:27:42 +03:00
1055 changed files with 59323 additions and 35131 deletions

1
.gitignore vendored
View file

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

View file

@ -17,7 +17,7 @@
# Updating the nightly image should be done by simply running a scheduled ci
# pipeline on the upstream repo with the $UPDATE_NIGHTLY variable defined.
.templates_sha: &templates_sha 567700e483aabed992d0a4fea84994a0472deff6
.templates_sha: &templates_sha b2e24205598dc1d80b5f2c88cf7618051e30e9fd
include:
- project: 'freedesktop/ci-templates'
@ -49,18 +49,17 @@ 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"
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.18=0.18
0.17=0.17
0.16=0.16
0.22=0.22
stages:
- "trigger"
- "container-base"
- "container-final"
- "lint"
@ -68,41 +67,56 @@ stages:
- "extras"
- "deploy"
.debian:11:
# This is an empty job that is used to trigger the pipeline.
trigger:
image: alpine:latest
stage: 'trigger'
variables:
FDO_DISTRIBUTION_VERSION: 'bullseye-slim'
GIT_STRATEGY: none
tags: [ 'placeholder-job' ]
script:
- echo "Trigger job done, now running the pipeline."
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
# If the MR is assigned to the Merge bot, trigger the pipeline automatically
- if: '$CI_MERGE_REQUEST_ASSIGNEES == "gstreamer-merge-bot"'
# Require explicit action to trigger tests post merge
- if: '$CI_PROJECT_NAMESPACE == "gstreamer" && $CI_COMMIT_BRANCH == "main"'
when: 'manual'
# When the assignee isn't the merge bot, require an explicit action to trigger the pipeline
# to avoid wasting CI resources
- if: '$CI_MERGE_REQUEST_ASSIGNEES != "gstreamer-merge-bot"'
when: 'manual'
allow_failure: false
.debian:12:
needs: []
variables:
FDO_DISTRIBUTION_VERSION: 'bookworm-slim'
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:11-base:
extends: .debian:11
.debian:12-base:
extends: .debian:12
variables:
FDO_DISTRIBUTION_TAG: 'base-$GST_RS_IMG_TAG'
.debian:11-stable:
extends: .debian:11
.debian:12-stable:
extends: .debian:12
variables:
RUST_IMAGE_FULL: "1"
FDO_DISTRIBUTION_TAG: '$GST_RS_STABLE-$GST_RS_IMG_TAG'
FDO_DISTRIBUTION_EXEC: 'bash ci/install-rust.sh $GST_RS_STABLE $RUST_IMAGE_FULL'
.debian:11-msrv:
extends: .debian:11
.debian:12-msrv:
extends: .debian:12
variables:
FDO_DISTRIBUTION_TAG: '$GST_RS_MSRV-$GST_RS_IMG_TAG'
FDO_DISTRIBUTION_EXEC: 'bash ci/install-rust.sh $GST_RS_MSRV $RUST_IMAGE_FULL'
.debian:11-nightly:
extends: .debian:11
.debian:12-nightly:
extends: .debian:12
variables:
FDO_DISTRIBUTION_TAG: 'nightly-$GST_RS_IMG_TAG'
FDO_DISTRIBUTION_EXEC: 'bash ci/install-rust.sh nightly $RUST_IMAGE_FULL'
@ -112,38 +126,58 @@ stages:
- .fdo.container-build@debian
stage: container-base
variables:
FDO_DISTRIBUTION_PACKAGES: "build-essential curl python3-setuptools liborc-0.4-dev libglib2.0-dev libxml2-dev libgtk-3-dev libegl1-mesa libgles2-mesa libgl1-mesa-dri libgl1-mesa-glx libwayland-egl1-mesa xz-utils libssl-dev git wget ca-certificates ninja-build python3-pip flex bison libglib2.0-dev libx11-dev libx11-xcb-dev libsoup2.4-dev libvorbis-dev libogg-dev libtheora-dev libmatroska-dev libvpx-dev libopus-dev libgraphene-1.0-dev libjpeg-dev libwayland-dev python3-gi"
FDO_DISTRIBUTION_PACKAGES: >-
build-essential curl python3-setuptools libglib2.0-dev libxml2-dev
libdrm-dev libegl1-mesa-dev libgl1-mesa-dev libgbm-dev libgles2-mesa-dev
libgl1-mesa-dri libegl-dev libgl1-mesa-glx libwayland-egl1-mesa xz-utils
libssl-dev git wget ca-certificates ninja-build python3-pip flex bison
libglib2.0-dev libx11-dev libx11-xcb-dev libsoup2.4-dev libvorbis-dev
libogg-dev libtheora-dev libmatroska-dev libvpx-dev libopus-dev
libgraphene-1.0-dev libjpeg-dev libwayland-dev wayland-protocols
python3-gi libavcodec-dev libavformat-dev libavutil-dev libavfilter-dev
libswscale-dev yasm libx264-dev libfontconfig-dev libfreetype-dev
libxkbcommon-dev libxi-dev libxcb-render0-dev libxcb-shm0-dev
libxcb1-dev libxext-dev libxrender-dev libxrandr-dev libxcursor-dev
libxdamage-dev libxfixes-dev libxinerama-dev libgudev-1.0-dev
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-gtk4.sh &&
pip3 install git+http://gitlab.freedesktop.org/freedesktop/ci-templates
bash ci/install-dav1d.sh &&
pip3 install --break-system-packages git+http://gitlab.freedesktop.org/freedesktop/ci-templates &&
pip3 install --break-system-packages tomli
.build-final-image:
extends:
- .fdo.container-build@debian
stage: container-final
variables:
FDO_BASE_IMAGE: '$CI_REGISTRY_IMAGE/debian/bullseye-slim:base-$GST_RS_IMG_TAG'
FDO_BASE_IMAGE: '$CI_REGISTRY_IMAGE/debian/bookworm-slim:base-$GST_RS_IMG_TAG'
build-base:
extends:
- .build-base-image
- .debian:11-base
- .debian:12-base
build-stable:
needs: ["build-base"]
extends:
- .build-final-image
- .debian:11-stable
- .debian:12-stable
build-msrv:
needs: ["build-base"]
extends:
- .build-final-image
- .debian:11-msrv
- .debian:12-msrv
build-nightly:
needs: ["build-base"]
extends:
- .build-final-image
- .debian:11-nightly
- .debian:12-nightly
update-nightly:
extends: build-nightly
@ -160,109 +194,21 @@ update-nightly:
.img-stable:
extends:
- .debian:11-stable
- .debian:12-stable
- .dist-debian-container
.img-msrv:
extends:
- .debian:11-msrv
- .debian:12-msrv
- .dist-debian-container
.img-nightly:
extends:
- .debian:11-nightly
- .debian:12-nightly
- .dist-debian-container
# GST_PLUGINS_RS_TOKEN is a variable of type 'Var' defined in gstreamer-rs CI
# settings and containing a gst-plugins-rs pipeline trigger token
.plugins-update:
stage: deploy
script:
- |
# FDO_DISTRIBUTION_IMAGE still has indirections
- echo $FDO_DISTRIBUTION_IMAGE
- DISTRO_IMAGE=$(eval echo ${FDO_DISTRIBUTION_IMAGE})
- echo $DISTRO_IMAGE
# retrieve the infos from the registry
- JSON_IMAGE=$(skopeo inspect docker://$DISTRO_IMAGE)
- IMAGE_PIPELINE_ID=$(echo $JSON_IMAGE | jq -r '.Labels["fdo.pipeline_id"]')
- echo $IMAGE_PIPELINE_ID
- echo $CI_PIPELINE_ID
- |
if [[ x"$IMAGE_PIPELINE_ID" == x"$CI_PIPELINE_ID" ]]; then
echo "Image has been updated, notify gst-plugins-rs"
curl -X POST -F "token=$GST_PLUGINS_RS_TOKEN" -F "ref=main" -F "variables[UPDATE_IMG]=$UPDATE_IMG" https://gitlab.freedesktop.org/api/v4/projects/1400/trigger/pipeline
else
echo "Image has not been updated, ignore"
fi
rules:
- if: '$CI_COMMIT_REF_NAME == "main" && $CI_PROJECT_PATH == "gstreamer/gstreamer-rs"'
# Those jobs need to use another image as ours doesn't have 'skopeo'
# and it's not easily installable in Debian stable for now.
plugins-update-stable:
extends:
- .plugins-update
- .img-stable
image: quay.io/freedesktop.org/ci-templates:container-build-base-2021-07-29.0
variables:
UPDATE_IMG: "stable"
plugins-update-msrv:
extends:
- .plugins-update
- .img-msrv
image: quay.io/freedesktop.org/ci-templates:container-build-base-2021-07-29.0
variables:
UPDATE_IMG: "msrv"
plugins-update-nightly:
extends:
- .plugins-update
- .img-nightly
image: quay.io/freedesktop.org/ci-templates:container-build-base-2021-07-29.0
variables:
UPDATE_IMG: "nightly"
.cargo_test_var: &cargo_test
- rustc --version
# First build and test all the crates with their relevant features
# Keep features in sync with below
- |
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_22"
;;
gstreamer-validate)
echo ""
;;
*)
echo "--features=v1_22"
;;
esac
}
for crate in gstreamer* gstreamer-gl/{egl,wayland,x11}; do
if [ -e $crate/Cargo.toml ]; then
if [ -n "$ALL_FEATURES" ]; then
FEATURES="$(get_features $crate)"
else
FEATURES=""
fi
echo "Building and testing $crate with $FEATURES"
cargo build --locked --color=always --manifest-path $crate/Cargo.toml $FEATURES
G_DEBUG=fatal_warnings cargo test --color=always --manifest-path $crate/Cargo.toml $FEATURES
fi
done
- |
if [ -n "$EXAMPLES_TUTORIALS" ]; then
cargo build --locked --color=always --manifest-path examples/Cargo.toml --bins --examples --all-features
cargo build --locked --color=always --manifest-path tutorials/Cargo.toml --bins --examples --all-features
fi
- ./ci/run-cargo-test.sh
.cargo test:
stage: "test"
@ -274,6 +220,8 @@ test msrv:
- '.cargo test'
- .img-msrv
needs:
- job: 'trigger'
artifacts: false
- job: 'build-msrv'
artifacts: false
@ -282,6 +230,8 @@ test stable:
- '.cargo test'
- .img-stable
needs:
- job: 'trigger'
artifacts: false
- job: 'build-stable'
artifacts: false
@ -293,6 +243,8 @@ test stable all-features:
- '.cargo test'
- .img-stable
needs:
- job: 'trigger'
artifacts: false
- job: 'build-stable'
artifacts: false
@ -303,6 +255,8 @@ test nightly:
- '.cargo test'
- .img-nightly
needs:
- job: 'trigger'
artifacts: false
- job: 'build-nightly'
artifacts: false
@ -316,65 +270,23 @@ test nightly all-features:
- '.cargo test'
- .img-nightly
needs:
- job: 'trigger'
artifacts: false
- job: 'build-nightly'
artifacts: false
.cargo test sys:
stage: "test"
script:
- rustc --version
- |
get_features() {
module=${1%%/sys}
case "$module" in
gstreamer-validate)
echo ""
;;
*)
echo "--features=v1_22"
;;
esac
}
# First build and test all the crates with their relevant features
# Keep features in sync with below
for crate in gstreamer*/sys gstreamer-gl/*/sys; do
if [ -e $crate/Cargo.toml ]; then
echo "Building $crate with $(get_features $crate)"
cargo build --locked --color=always --manifest-path $crate/Cargo.toml $(get_features $crate)
fi
done
# Run tests for crates we can currently run.
# Other tests are broken currently.
for crate in gstreamer/sys \
gstreamer-app/sys \
gstreamer-audio/sys \
gstreamer-base/sys \
gstreamer-check/sys \
gstreamer-controller/sys \
gstreamer-gl/sys \
gstreamer-gl/egl/sys \
gstreamer-gl/wayland/sys \
gstreamer-gl/x11/sys \
gstreamer-mpegts/sys \
gstreamer-net/sys \
gstreamer-pbutils/sys \
gstreamer-player/sys \
gstreamer-rtsp-server/sys \
gstreamer-rtsp/sys \
gstreamer-sdp/sys \
gstreamer-tag/sys \
gstreamer-video/sys \
gstreamer-webrtc/sys; do
echo "Testing $crate with $(get_features $crate)"
cargo test --locked --color=always --manifest-path $crate/Cargo.toml $(get_features $crate)
done
- ./ci/run-sys-cargo-test.sh
test stable sys:
extends:
- '.cargo test sys'
- .img-stable
needs:
- job: 'trigger'
artifacts: false
- job: 'build-stable'
artifacts: false
@ -383,6 +295,8 @@ test msrv sys:
- '.cargo test sys'
- .img-msrv
needs:
- job: 'trigger'
artifacts: false
- job: 'build-msrv'
artifacts: false
@ -391,12 +305,15 @@ test nightly sys:
- '.cargo test sys'
- .img-nightly
needs:
- job: 'trigger'
artifacts: false
- job: 'build-nightly'
artifacts: false
rustfmt:
extends: .img-stable
stage: "lint"
tags: [ 'placeholder-job' ]
script:
- cargo fmt --version
- cargo fmt -- --color=always --check
@ -407,51 +324,35 @@ rustfmt:
check commits:
extends: .img-stable
stage: "lint"
tags: [ 'placeholder-job' ]
script:
- ci-fairy check-commits --textwidth 0 --no-signed-off-by
needs:
- job: 'build-stable'
artifacts: false
typos:
extends: .img-stable
stage: "lint"
tags: [ 'placeholder-job' ]
script:
- typos
needs:
- job: 'build-stable'
artifacts: false
clippy:
extends: .img-stable
stage: 'extras'
variables:
CLIPPY_LINTS: -D warnings
CLIPPY_LINTS: -D warnings -W unknown-lints
needs:
- job: 'trigger'
artifacts: false
- job: 'build-stable'
artifacts: false
script:
- cargo clippy --version
# Keep features in sync with above
- |
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_22"
;;
gstreamer-validate)
echo ""
;;
*)
echo "--features=v1_22"
;;
esac
}
for crate in gstreamer* gstreamer-gl/{egl,wayland,x11}; do
if [ -e $crate/Cargo.toml ]; then
FEATURES=$(get_features $crate)
echo "Running clippy on $crate with $FEATURES"
cargo clippy --locked --color=always --manifest-path $crate/Cargo.toml $FEATURES --all-targets -- $CLIPPY_LINTS
fi
done
# And also run over all the examples/tutorials
- |
cargo clippy --locked --color=always --manifest-path examples/Cargo.toml --all-targets --all-features -- $CLIPPY_LINTS
cargo clippy --locked --color=always --manifest-path tutorials/Cargo.toml --all-targets --all-features -- $CLIPPY_LINTS
- ./ci/run-clippy.sh
deny:
extends: .img-stable
@ -462,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
@ -485,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:
@ -494,6 +398,8 @@ coverage:
- .img-stable
stage: 'extras'
needs:
- job: 'trigger'
artifacts: false
- job: 'build-stable'
artifacts: false
variables:
@ -560,8 +466,9 @@ docs:
- PATH=~/.cargo/bin/:$PATH ./generator.py --gir-files-directories gir-files gst-gir-files --embed-docs --no-fmt
- |
RUSTDOCFLAGS="$RUST_DOCS_FLAGS"
RUSTFLAGS="--cfg docsrs"
eval $(./gir-rustdoc.py pre-docs)
cargo +nightly doc --workspace --exclude examples --exclude tutorials --color=always --features=dox --no-deps
cargo +nightly doc --workspace --exclude examples --exclude tutorials --all-features --color=always --no-deps
- mv target/doc docs
artifacts:
paths:
@ -597,6 +504,8 @@ pages:
.windows rust docker build:
stage: 'container-final'
timeout: '2h'
needs: []
variables:
# Unlike the buildah/linux jobs, this file
# needs to be relative to windows-docker/ subdir
@ -605,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'
@ -642,17 +550,7 @@ windows rust docker msrv:
- 'docker'
- 'windows'
- '2022'
parallel:
matrix:
- FEATURES:
- "--features=v1_18,"
- "--features=v1_20,"
- "--features=v1_22,"
- "--no-default-features"
- ""
script:
- echo $env:FEATURES
# Skip -sys tests as they don't work
# https://github.com/gtk-rs/gtk3-rs/issues/54
#
@ -669,12 +567,16 @@ windows rust docker msrv:
test windows msrv:
image: $WINDOWS_RUST_MINIMUM_IMAGE
needs:
- job: 'trigger'
artifacts: false
- job: 'windows rust docker msrv'
artifacts: false
extends: '.msvc2019 build'
test windows stable:
needs:
- job: 'trigger'
artifacts: false
- job: 'windows rust docker stable'
artifacts: false
image: "$WINDOWS_RUST_STABLE_IMAGE"

View file

@ -0,0 +1,33 @@
### Describe your issue
<!-- a clear and concise summary of the bug. -->
<!-- For any GStreamer usage question, please contact the community using the #gstreamer channel on IRC https://www.oftc.net/ or the mailing list on https://gstreamer.freedesktop.org/lists/ -->
#### Expected Behavior
<!-- What did you expect to happen -->
#### Observed Behavior
<!-- What actually happened -->
#### Setup
- **Operating System:**
- **Device:** Computer / Tablet / Mobile / Virtual Machine <!-- Delete as appropriate !-->
- **gstreamer-rs Version:**
- **GStreamer Version:**
- **Command line:**
### Steps to reproduce the bug
<!-- please fill in exact steps which reproduce the bug on your system, for example: -->
1. open terminal
2. type `command`
### How reproducible is the bug?
<!-- The reproducibility of the bug is Always/Intermittent/Only once after doing a very specific set of steps-->
### Screenshots if relevant
### Solutions you have tried
### Related non-duplicate issues
### Additional Information
<!-- Any other information such as logs. Make use of <details> for long output -->

3067
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: '2022-10-12.0'
GST_RS_STABLE: '1.64.0'
GST_RS_MSRV: '1.63.0'
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'

11
ci/install-dav1d.sh Normal file
View file

@ -0,0 +1,11 @@
set -e
RELEASE=1.4.1
git clone https://code.videolan.org/videolan/dav1d.git --branch $RELEASE
cd dav1d
meson build -D prefix=/usr/local
ninja -C build
ninja -C build install
cd ..
rm -rf dav1d

View file

@ -1,21 +1,49 @@
#! /bin/bash
set -e
pip3 install meson==0.63.2
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
pushd .
cd ..
git clone --depth 1 https://gitlab.freedesktop.org/gstreamer/gstreamer.git --branch main
git clone https://gitlab.freedesktop.org/gstreamer/gstreamer.git \
--depth 1 \
--branch "$DEFAULT_BRANCH"
cd gstreamer
# plugins required by tests
PLUGINS="-D gst-plugins-base:ogg=enabled -D gst-plugins-base:vorbis=enabled -D gst-plugins-base:theora=enabled -D gst-plugins-good:matroska=enabled -D gst-plugins-good:vpx=enabled -D gst-plugins-bad:opus=enabled"
PLUGINS="-D gst-plugins-base:ogg=enabled \
-D gst-plugins-base:vorbis=enabled \
-D gst-plugins-base:theora=enabled \
-D gst-plugins-good:matroska=enabled \
-D gst-plugins-good:vpx=enabled \
-D gst-plugins-bad:opus=enabled \
-D gst-plugins-ugly:x264=enabled"
meson build -D prefix=/usr/local -D examples=disabled -D gtk_doc=disabled -D introspection=disabled -D libav=disabled -D python=disabled -D ugly=disabled -D vaapi=disabled $PLUGINS
ninja -C build
ninja -C build install
echo "subproject('gtk')" >> meson.build
meson setup build \
-D prefix=/usr/local \
-D gpl=enabled \
-D ugly=enabled \
-D examples=disabled \
-D gtk_doc=disabled \
-D introspection=disabled \
-D libav=disabled \
-D python=disabled \
-D vaapi=disabled \
$PLUGINS
meson compile -C build
meson install -C build
ldconfig
cd ..
rm -rf gstreamer/
# Check what plugins we installed
gst-inspect-1.0
popd

View file

@ -1,14 +0,0 @@
#! /bin/sh
set -eux
BRANCH=4.8.1
git clone https://gitlab.gnome.org/GNOME/gtk.git --branch $BRANCH --depth=1
cd gtk
meson build -D prefix=/usr/local -Dbuild-tests=false -Dwayland-protocols:tests=false
ninja -C build
ninja -C build install
cd ..
rm -rf gtk/

View file

@ -1,9 +1,11 @@
#! /bin/bash
source ./ci/env.sh
set -e
export CARGO_HOME='/usr/local/cargo'
RUSTUP_VERSION=1.25.1
RUSTUP_VERSION=1.27.1
RUST_VERSION=$1
RUST_IMAGE_FULL=$2
RUST_ARCH="x86_64-unknown-linux-gnu"
@ -24,17 +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 --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
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

30
ci/run-cargo-test.sh Executable file
View file

@ -0,0 +1,30 @@
#! /bin/bash
set -ex
rustc --version
cargo --version
for crate in gstreamer* gstreamer-gl/{egl,wayland,x11}; do
if [ -e "$crate/Cargo.toml" ]; then
if [ -n "$ALL_FEATURES" ]; then
FEATURES="--all-features"
else
FEATURES=""
fi
echo "Building and testing $crate with $FEATURES"
cargo build --locked --color=always --manifest-path "$crate/Cargo.toml" $FEATURES
G_DEBUG=fatal_warnings cargo test --color=always --manifest-path "$crate/Cargo.toml" $FEATURES
fi
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-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
fi

38
ci/run-clippy.sh Executable file
View file

@ -0,0 +1,38 @@
#! /bin/bash
set -ex
rustc --version
cargo --version
cargo clippy --version
# Keep features in sync with run-cargo-test.sh
get_features() {
crate=$1
case "$crate" in
gstreamer-audio|gstreamer-editing-services|gstreamer-gl|gstreamer-pbutils|gstreamer-rtp|gstreamer-rtsp|gstreamer-video|gstreamer)
echo "--features=serde,v1_26"
;;
*)
echo "--features=v1_26"
;;
esac
}
for crate in gstreamer* gstreamer-gl/{egl,wayland,x11}; do
if [ -e "$crate/Cargo.toml" ]; then
FEATURES=$(get_features "$crate")
echo "Running clippy on $crate with $FEATURES"
cargo clippy --locked --color=always --manifest-path "$crate/Cargo.toml" $FEATURES --all-targets -- $CLIPPY_LINTS
fi
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-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
cargo clippy --locked --color=always --manifest-path tutorials/Cargo.toml --all-targets --all-features -- $CLIPPY_LINTS

43
ci/run-sys-cargo-test.sh Executable file
View file

@ -0,0 +1,43 @@
#! /bin/bash
set -ex
rustc --version
cargo --version
for crate in gstreamer*/sys gstreamer-gl/*/sys; do
if [ -e "$crate/Cargo.toml" ]; then
echo "Building $crate with --all-features"
cargo build --locked --color=always --manifest-path "$crate/Cargo.toml" --all-features
fi
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 \
gstreamer-gl/x11/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)"
cargo test --locked --color=always --manifest-path $crate/Cargo.toml --all-features
done

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',
@ -35,47 +33,54 @@
'examples'
)
foreach($crate in $crates)
{
Write-Host "Building crate: $crate"
Write-Host "Features: $env:FEATURES"
$env:LocalFeatures = $env:FEATURES
# "" is the default build, no flags appended
[string[]] $features_matrix = @(
# "--no-default-features",
# "--features=v1_18",
# "--features=v1_20",
"",
"--all-features"
)
# Don't append feature flags if the string is null/empty
# Or when we want to build without default features
if ($env:LocalFeatures -and ($env:LocalFeatures -ne '--no-default-features')) {
if ($crate -eq 'gstreamer') {
$env:LocalFeatures += "serde,"
foreach($features in $features_matrix) {
foreach($crate in $crates)
{
Write-Host "Building crate: $crate"
Write-Host "Features: $features"
$env:LocalFeatures = $features
# Don't append feature flags if the string is null/empty
# Or when we want to build without default features
if ($env:LocalFeatures -and ($env:LocalFeatures -ne '--no-default-features')) {
if ($crate -eq 'examples') {
# FIXME: We can do --all-features for examples once we have gtk3 installed in the image
$env:LocalFeatures = "--features=rtsp-server,rtsp-server-record,pango-cairo,overlay-composition,gst-play,gst-player,ges,image,cairo-rs,gst-video/v1_18,windows"
}
if ($crate -eq 'tutorials') {
$env:LocalFeatures = ''
}
}
if ($crate -eq 'examples') {
# FIXME: We can do --all-features for examples once we have gtk installed in the image
$env:LocalFeatures = "--features=rtsp-server,rtsp-server-record,pango-cairo,overlay-composition"
Write-Host "with features: $env:LocalFeatures"
cargo build --color=always --manifest-path $crate/Cargo.toml --all-targets $env:LocalFeatures
if (!$?) {
Write-Host "Failed to build crate: $crate"
Exit 1
}
if ($crate -eq 'tutorials') {
$env:LocalFeatures = ''
if (($crate -eq "gstreamer-tag/sys") -or ($crate -eq "gstreamer-mpegts/sys")) {
Write-Host "Skipping tests for $crate"
continue
}
}
Write-Host "with features: $env:LocalFeatures"
cargo build --color=always --manifest-path $crate/Cargo.toml --all-targets $env:LocalFeatures
$env:G_DEBUG="fatal_warnings"
cargo test --no-fail-fast --color=always --manifest-path $crate/Cargo.toml $env:LocalFeatures
if (!$?) {
Write-Host "Failed to build crate: $crate"
Exit 1
}
if (($crate -eq "gstreamer-tag/sys") -or ($crate -eq "gstreamer-mpegts/sys")) {
Write-Host "Skipping tests for $crate"
continue
}
$env:G_DEBUG="fatal_warnings"
cargo test --no-fail-fast --color=always --manifest-path $crate/Cargo.toml $env:LocalFeatures
if (!$?) {
Write-Host "Tests failed to for crate: $crate"
Exit 1
if (!$?) {
Write-Host "Tests failed to for crate: $crate"
Exit 1
}
}
}

View file

@ -1,25 +1,22 @@
# escape=`
FROM "registry.freedesktop.org/gstreamer/gstreamer/amd64/windows:2022-09-23.0-main"
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
RUN choco install -y pkgconfiglite nasm llvm openssl
# https://stackoverflow.com/a/50716450
RUN setx PATH '%PATH%;C:\Program Files\NASM;C:\gst-install\bin'
ENV PKG_CONFIG_PATH="C:\gst-install\lib\pkgconfig"
COPY install_pango.ps1 install_gst.ps1 install_gtk.ps1 install_dav1d.ps1 C:\
RUN C:\install_pango.ps1
COPY install_gst.ps1 install_dav1d.ps1 C:\
RUN C:\install_gst.ps1
RUN C:\install_gtk.ps1
RUN C:\install_dav1d.ps1
RUN Invoke-WebRequest -Uri https://win.rustup.rs/x86_64 -OutFile C:\rustup-init.exe
RUN C:\rustup-init.exe -y --profile minimal --default-toolchain $env:RUST_VERSION
RUN cargo install --locked cargo-c --version 0.9.22+cargo-0.72

View file

@ -1,7 +1,7 @@
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
# Download gstreamer and all its subprojects
git clone -b 1.0.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

@ -12,51 +12,60 @@ Set-Location C:\gstreamer
# Copy the cache we already have in the image to avoid massive redownloads
Move-Item C:/subprojects/* C:\gstreamer\subprojects
if (!$?) {
Write-Host "Failed to copy subprojects cache"
Exit 1
}
# Update the subprojects cache
Write-Output "Running meson subproject reset"
meson subprojects update --reset
if (!$?) {
Write-Host "Failed to reset subprojects state"
Write-Host "Failed to update gstreamer subprojects"
Exit 1
}
$env:MESON_ARGS = "--prefix=C:\gst-install\ " +
"-Dglib:installed_tests=false " +
"-Dlibnice:tests=disabled " +
"-Dlibnice:examples=disabled " +
"-Dffmpeg:tests=disabled " +
"-Dopenh264:tests=disabled " +
"-Dpygobject:tests=false " +
"-Dugly=enabled " +
"-Dbad=enabled " +
"-Dges=enabled " +
"-Drtsp_server=enabled " +
"-Ddevtools=enabled " +
"-Dsharp=disabled " +
"-Dpython=disabled " +
"-Dlibav=disabled " +
"-Dvaapi=disabled " +
"-Dgst-plugins-base:pango=enabled " +
"-Dgst-plugins-good:cairo=enabled " +
"-Dgpl=enabled "
$MESON_ARGS = @(`
"--prefix=C:\gst-install", `
"-Dglib:installed_tests=false", `
"-Dlibnice:tests=disabled", `
"-Dlibnice:examples=disabled", `
"-Dffmpeg:tests=disabled", `
"-Dopenh264:tests=disabled", `
"-Dpygobject:tests=false", `
"-Dgpl=enabled", `
"-Dugly=enabled", `
"-Dbad=enabled", `
"-Dges=enabled", `
"-Drtsp_server=enabled", `
"-Ddevtools=enabled", `
"-Dsharp=disabled", `
"-Dpython=disabled", `
"-Dlibav=disabled", `
"-Dvaapi=disabled", `
"-Dgst-plugins-base:pango=enabled", `
"-Dgst-plugins-good:cairo=enabled", `
"-Dgst-plugins-good:lame=disabled"
)
Write-Output "Building gst"
cmd.exe /C "C:\BuildTools\Common7\Tools\VsDevCmd.bat -host_arch=amd64 -arch=amd64 && meson _build $env:MESON_ARGS && meson compile -C _build && ninja -C _build install"
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
echo "subproject('gtk')" >> meson.build
Write-Output "Building gstreamer"
meson setup --vsenv $MESON_ARGS _build
if (!$?) {
Write-Host "Failed to build and install gst"
type "_build\meson-logs\meson-log.txt"
Write-Host "Failed to run meson setup, see log above"
Exit 1
}
cd C:\
cmd /c rmdir /s /q C:\gstreamer
Write-Output "Compiling gstreamer"
meson compile -C _build
if (!$?) {
Write-Host "Failed to remove gst checkout"
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,27 +0,0 @@
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
$env:MESON_ARGS = "--prefix=C:\gst-install\"
# Download gtk and all its subprojects
git clone -b 4.8.1 --depth 1 https://gitlab.gnome.org/gnome/gtk.git C:\gtk
if (!$?) {
Write-Host "Failed to clone gtk"
Exit 1
}
Set-Location C:\gtk
Write-Output "Building gtk"
cmd.exe /C "C:\BuildTools\Common7\Tools\VsDevCmd.bat -host_arch=amd64 -arch=amd64 && meson _build $env:MESON_ARGS && meson compile -C _build && ninja -C _build install"
if (!$?) {
Write-Host "Failed to build and install gtk"
Exit 1
}
cd C:\
cmd /c rmdir /s /q C:\gtk
if (!$?) {
Write-Host "Failed to remove gtk checkout"
Exit 1
}

View file

@ -1,27 +0,0 @@
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
$env:MESON_ARGS = "--prefix=C:\gst-install\"
# Download pango all its subprojects
git clone -b main --depth 1 https://gitlab.gnome.org/gnome/pango.git C:\pango
if (!$?) {
Write-Host "Failed to clone pango"
Exit 1
}
Set-Location C:\pango
Write-Output "Building pango"
cmd.exe /C "C:\BuildTools\Common7\Tools\VsDevCmd.bat -host_arch=amd64 -arch=amd64 && meson _build $env:MESON_ARGS && meson compile -C _build && ninja -C _build install"
if (!$?) {
Write-Host "Failed to build and install pango"
Exit 1
}
cd C:\
cmd /c rmdir /s /q C:\pango
if (!$?) {
Write-Host "Failed to remove gtk checkout"
Exit 1
}

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,6 +23,12 @@ multiple-versions = "deny"
wildcards = "allow"
highlight = "all"
# proc-macro-crate depends on an older version of toml_edit
# https://github.com/bkchr/proc-macro-crate/pull/50
[[bans.skip]]
name = "toml_edit"
version = "0.21"
[sources]
unknown-registry = "deny"
unknown-git = "deny"

View file

@ -1,64 +1,72 @@
[package]
name = "examples"
version = "0.19.0"
version.workspace = true
license = "MIT"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
edition = "2021"
rust-version = "1.63"
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 }
gtk = { git = "https://github.com/gtk-rs/gtk3-rs", optional = true }
gdk = { git = "https://github.com/gtk-rs/gtk3-rs", 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 }
once_cell = "1.0"
image = { version = "0.24", optional = true }
memmap2 = { version = "0.5", 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"] }
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.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",
"Win32_Graphics_Imaging", "Win32_System_Com", "Foundation_Numerics"], optional = true }
[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.24"
cocoa = "0.25"
objc = "0.2.7"
[build-dependencies]
gl_generator = { version = "0.14", optional = true }
[features]
default = []
gtksink = ["gtk", "gio"]
gtkvideooverlay = ["gtk", "gdk", "gio"]
gtkvideooverlay-x11 = ["gtkvideooverlay"]
gtkvideooverlay-quartz = ["gtkvideooverlay"]
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"]
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]]
@ -85,14 +93,6 @@ name = "encodebin"
[[bin]]
name = "events"
[[bin]]
name = "gtksink"
required-features = ["gtksink"]
[[bin]]
name = "gtkvideooverlay"
required-features = ["gtkvideooverlay"]
[[bin]]
name = "iterator"
@ -136,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"
@ -163,6 +167,10 @@ required-features = ["pango-cairo"]
name = "overlay-composition"
required-features = ["overlay-composition"]
[[bin]]
name = "overlay-composition-d2d"
required-features = ["windows"]
[[bin]]
name = "ges"
required-features = ["ges"]
@ -192,3 +200,10 @@ required-features = ["allocators"]
[[bin]]
name = "cairo_compositor"
required-features = ["cairo-rs", "gst-video/v1_18"]
[[bin]]
name = "d3d11videosink"
required-features = ["windows"]
[[bin]]
name = "audio_multichannel_interleave"

View file

@ -1,7 +1,7 @@
#[cfg(feature = "gl")]
fn generate_gl_bindings() {
let dest = std::path::PathBuf::from(&std::env::var("OUT_DIR").unwrap());
let mut file = std::fs::File::create(&dest.join("test_gl_bindings.rs")).unwrap();
let mut file = std::fs::File::create(dest.join("test_gl_bindings.rs")).unwrap();
gl_generator::Registry::new(
gl_generator::Api::Gles2,
(3, 0),

View file

@ -10,26 +10,22 @@
// This is the format we request:
// Audio / Signed 16bit / 1 channel / arbitrary sample rate
use gst::element_error;
use gst::prelude::*;
use byte_slice_cast::*;
use std::i16;
use anyhow::Error;
use byte_slice_cast::*;
use derive_more::{Display, Error};
use gst::{element_error, prelude::*};
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
fn create_pipeline() -> Result<gst::Pipeline, Error> {
@ -50,7 +46,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
)
.build();
pipeline.add_many(&[&src, appsink.upcast_ref()])?;
pipeline.add_many([&src, appsink.upcast_ref()])?;
src.link(&appsink)?;
// Getting data out of the appsink is done by setting callbacks on it.
@ -95,7 +91,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to interprete buffer as S16 PCM")
("Failed to interpret buffer as S16 PCM")
);
gst::FlowError::Error
@ -111,7 +107,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
})
.sum();
let rms = (sum / (samples.len() as f64)).sqrt();
println!("rms: {}", rms);
println!("rms: {rms}");
Ok(gst::FlowSuccess::Ok)
})
@ -138,11 +134,10 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
return Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into());
}
@ -158,7 +153,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
fn example_main() {
match create_pipeline().and_then(main_loop) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -10,21 +10,20 @@
// The application provides data of the following format:
// Video / BGRx (4 bytes) / 2 fps
use gst::prelude::*;
use anyhow::Error;
use derive_more::{Display, Error};
use gst::prelude::*;
use gst_video::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
const WIDTH: usize = 320;
@ -51,8 +50,8 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
let videoconvert = gst::ElementFactory::make("videoconvert").build()?;
let sink = gst::ElementFactory::make("autovideosink").build()?;
pipeline.add_many(&[appsrc.upcast_ref(), &videoconvert, &sink])?;
gst::Element::link_many(&[appsrc.upcast_ref(), &videoconvert, &sink])?;
pipeline.add_many([appsrc.upcast_ref(), &videoconvert, &sink])?;
gst::Element::link_many([appsrc.upcast_ref(), &videoconvert, &sink])?;
// Our frame counter, that is stored in the mutable environment
// of the closure of the need-data callback
@ -77,7 +76,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
return;
}
println!("Producing frame {}", i);
println!("Producing frame {i}");
let r = if i % 2 == 0 { 0 } else { 255 };
let g = if i % 3 == 0 { 0 } else { 255 };
@ -152,11 +151,10 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
return Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into());
}
@ -172,7 +170,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
fn example_main() {
match create_pipeline().and_then(main_loop) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

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

@ -1,29 +1,24 @@
// This example demonstrates how to implement a custom compositor based on cairo.
#![allow(clippy::non_send_fields_in_send_ty)]
use anyhow::{Context, Error};
use gst::prelude::*;
use gst_base::prelude::*;
use anyhow::{Context, Error};
#[path = "../examples-common.rs"]
mod examples_common;
// Our custom compositor element is defined in this module.
mod cairo_compositor {
use super::*;
use gst_base::subclass::prelude::*;
use gst_video::prelude::*;
use gst_video::subclass::prelude::*;
use once_cell::sync::Lazy;
use gst_video::{prelude::*, subclass::prelude::*};
// In the imp submodule we include the actual implementation of the compositor.
mod imp {
use super::*;
use std::sync::Mutex;
use super::*;
// Settings of the compositor.
#[derive(Clone)]
struct Settings {
@ -57,19 +52,20 @@ mod cairo_compositor {
// Implementation of glib::Object virtual methods.
impl ObjectImpl for CairoCompositor {
// Specfication of the compositor properties.
// Specification of the compositor properties.
// 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.
@ -104,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.
@ -152,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.
@ -164,14 +162,14 @@ mod cairo_compositor {
name: Option<&str>,
caps: Option<&gst::Caps>,
) -> Option<gst::Pad> {
let element = self.instance();
let element = self.obj();
let pad = self.parent_request_new_pad(templ, name, caps)?;
element.child_added(&pad, &pad.name());
Some(pad)
}
fn release_pad(&self, pad: &gst::Pad) {
let element = self.instance();
let element = self.obj();
element.child_removed(pad, &pad.name());
self.parent_release_pad(pad);
}
@ -239,7 +237,7 @@ mod cairo_compositor {
token: &gst_video::subclass::AggregateFramesToken,
outbuf: &mut gst::BufferRef,
) -> Result<gst::FlowSuccess, gst::FlowError> {
let element = self.instance();
let element = self.obj();
let pads = element.sink_pads();
// Map the output frame writable.
@ -306,12 +304,12 @@ mod cairo_compositor {
// This allows accessing the pads and their properties from e.g. gst-launch.
impl ChildProxyImpl for CairoCompositor {
fn children_count(&self) -> u32 {
let object = self.instance();
let object = self.obj();
object.num_pads() as u32
}
fn child_by_name(&self, name: &str) -> Option<glib::Object> {
let object = self.instance();
let object = self.obj();
object
.pads()
.into_iter()
@ -320,7 +318,7 @@ mod cairo_compositor {
}
fn child_by_index(&self, index: u32) -> Option<glib::Object> {
let object = self.instance();
let object = self.obj();
object
.pads()
.into_iter()
@ -404,7 +402,7 @@ mod cairo_compositor {
impl CairoCompositor {
// Creates a new instance of our compositor with the given name.
pub fn new(name: Option<&str>) -> Self {
glib::Object::new(&[("name", &name)])
glib::Object::builder().property("name", name).build()
}
}
@ -413,9 +411,10 @@ mod cairo_compositor {
// This doesn't implement any additional logic but only provides properties for configuring the
// appearance of the stream corresponding to this pad and the storage of the property values.
mod imp_pad {
use super::*;
use std::sync::Mutex;
use super::*;
// Settings of our pad.
#[derive(Clone)]
pub(super) struct Settings {
@ -456,11 +455,14 @@ mod cairo_compositor {
// Implementation of glib::Object virtual methods.
impl ObjectImpl for CairoCompositorPad {
// Specfication of the compositor pad properties.
// Specification of the compositor pad properties.
// 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")
@ -498,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.
@ -579,7 +579,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
comp.set_property("background-color", 0xff_33_33_33u32);
pipeline.add_many(&[&src1, &src2, comp.upcast_ref(), &conv, &sink])?;
pipeline.add_many([&src1, &src2, comp.upcast_ref(), &conv, &sink])?;
// Link everything together.
src1.link_filtered(

View file

@ -21,7 +21,7 @@ impl ExampleCustomEvent {
#[allow(clippy::new_ret_no_self)]
pub fn new(send_eos: bool) -> gst::Event {
let s = gst::Structure::builder(Self::EVENT_NAME)
.field("send_eos", &send_eos)
.field("send_eos", send_eos)
.build();
gst::event::CustomDownstream::new(s)
}
@ -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,56 +115,53 @@ 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::Continue(false),
let Some(pipeline) = pipeline_weak.upgrade() else {
return glib::ControlFlow::Break;
};
println!(
"Sending custom event to the pipeline with send_eos={}",
send_eos
);
println!("Sending custom event to the pipeline with send_eos={send_eos}");
let ev = ExampleCustomEvent::new(*send_eos);
if !pipeline.send_event(ev) {
println!("Warning: Failed to send custom event");
}
// Remove this handler, the pipeline will shutdown once our pad probe catches the custom
// event and sends EOS
glib::Continue(false)
glib::ControlFlow::Break
});
}
let main_loop_clone = main_loop.clone();
// This sets the bus's signal handler (don't be mislead by the "add", there can only be one).
// Every message from the bus is passed through this function. Its returnvalue determines
// whether the handler wants to be called again. If glib::Continue(false) is returned, the
// whether the handler wants to be called again. If glib::ControlFlow::Break is returned, the
// handler is removed and will never be called again. The mainloop still runs though.
bus.add_watch(move |_, msg| {
use gst::MessageView;
let _bus_watch = bus
.add_watch(move |_, msg| {
use gst::MessageView;
let main_loop = &main_loop_clone;
match msg.view() {
MessageView::Eos(..) => {
println!("received eos");
// An EndOfStream event was sent to the pipeline, so we tell our main loop
// to stop execution here.
main_loop.quit()
}
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
main_loop.quit();
}
_ => (),
};
let main_loop = &main_loop_clone;
match msg.view() {
MessageView::Eos(..) => {
println!("received eos");
// An EndOfStream event was sent to the pipeline, so we tell our main loop
// to stop execution here.
main_loop.quit()
}
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
main_loop.quit();
}
_ => (),
};
// Tell the mainloop to continue executing this callback.
glib::Continue(true)
})
.expect("Failed to add bus watch");
// Tell the mainloop to continue executing this callback.
glib::ControlFlow::Continue
})
.expect("Failed to add bus watch");
// Operate GStreamer's bus, facilitating GLib's mainloop here.
// This function call will block until you tell the mainloop to quit
@ -172,11 +171,6 @@ fn example_main() {
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
// Remove the watch function from the bus.
// Again: There can always only be one watch function.
// Thus we don't have to tell him which function to remove.
bus.remove_watch().unwrap();
}
fn main() {

View file

@ -4,16 +4,15 @@
// an appsrc and retrieves them again from an appsink.
#![allow(clippy::non_send_fields_in_send_ty)]
use gst::element_error;
use gst::prelude::*;
use gst::{element_error, prelude::*};
#[path = "../examples-common.rs"]
mod examples_common;
mod custom_meta {
use std::{fmt, mem};
use gst::prelude::*;
use std::fmt;
use std::mem;
// Public Rust type for the custom meta.
#[repr(transparent)]
@ -70,10 +69,9 @@ mod custom_meta {
// Actual unsafe implementation of the meta.
mod imp {
use std::{mem, ptr};
use glib::translate::*;
use once_cell::sync::Lazy;
use std::mem;
use std::ptr;
pub(super) struct CustomMetaParams {
pub label: String,
@ -88,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.
@ -99,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
@ -158,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()
}
}
}
@ -201,13 +202,13 @@ fn example_main() {
return;
}
println!("Producing buffer {}", i);
println!("Producing buffer {i}");
// Add a custom meta with a label to this buffer.
let mut buffer = gst::Buffer::new();
{
let buffer = buffer.get_mut().unwrap();
custom_meta::CustomMeta::add(buffer, format!("This is buffer {}", i));
custom_meta::CustomMeta::add(buffer, format!("This is buffer {i}"));
}
i += 1;

View file

@ -0,0 +1,364 @@
// This example demonstrates the use of the d3d11videosink's "present"
// signal and the use of Direct2D/DirectWrite APIs in Rust.
//
// Application can perform various hardware-accelerated 2D graphics operation
// (e.g., like cairo can support) and text rendering via the Windows APIs.
// In this example, 2D graphics operation and text rendering will happen
// directly to the on the DXGI swapchain's backbuffer via Windows API in
// strictly zero-copy manner
use std::{
collections::VecDeque,
sync::{Arc, Mutex},
time::SystemTime,
};
use gst::{glib, prelude::*};
use windows::{
core::*,
Win32::Graphics::{
Direct2D::{Common::*, *},
Direct3D11::*,
DirectWrite::*,
Dxgi::{Common::*, *},
},
};
struct OverlayContext {
d2d_factory: ID2D1Factory,
dwrite_factory: IDWriteFactory,
text_format: IDWriteTextFormat,
texture_desc: D3D11_TEXTURE2D_DESC,
text_layout: Option<IDWriteTextLayout>,
timestamp_queue: VecDeque<SystemTime>,
avg_fps: f32,
display_fps: f32,
font_size: f32,
}
fn create_overlay_context() -> Arc<Mutex<OverlayContext>> {
// Lots of DirectX APIs are marked as unsafe but the below operations
// are not expected to be failed unless GPU hang or device remove condition
// happens
let d2d_factory = unsafe {
D2D1CreateFactory::<ID2D1Factory>(D2D1_FACTORY_TYPE_MULTI_THREADED, None).unwrap()
};
let dwrite_factory =
unsafe { DWriteCreateFactory::<IDWriteFactory>(DWRITE_FACTORY_TYPE_SHARED).unwrap() };
// Font size can be updated later
let text_format = unsafe {
dwrite_factory
.CreateTextFormat(
w!("Consolas"),
None,
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
12f32,
w!("en-us"),
)
.unwrap()
};
Arc::new(Mutex::new(OverlayContext {
d2d_factory,
dwrite_factory,
text_format,
texture_desc: D3D11_TEXTURE2D_DESC::default(),
text_layout: None,
timestamp_queue: VecDeque::with_capacity(10),
avg_fps: 0f32,
display_fps: 0f32,
font_size: 12f32,
}))
}
fn main() -> Result<()> {
gst::init().unwrap();
let args: Vec<String> = std::env::args().collect();
if args.len() != 2 {
println!("URI must be specified");
return Ok(());
}
let main_loop = glib::MainLoop::new(None, false);
let overlay_context = create_overlay_context();
let overlay_context_weak = Arc::downgrade(&overlay_context);
// Needs BGRA or RGBA swapchain for D2D interop,
// and "present" signal must be explicitly enabled
let videosink = gst::ElementFactory::make("d3d11videosink")
.property("emit-present", true)
.property_from_str("display-format", "DXGI_FORMAT_B8G8R8A8_UNORM")
.build()
.unwrap();
// Listen "present" signal and draw overlay from the callback
// Required operations here:
// 1) Gets IDXGISurface and ID3D11Texture2D interface from
// given ID3D11RenderTargetView COM object
// - ID3D11Texture2D: To get texture resolution
// - IDXGISurface: To create Direct2D render target
// 2) Creates or reuses IDWriteTextLayout interface
// - This object represents text layout we want to draw on render target
// 3) Draw rectangle (overlay background) and text on render target
//
// NOTE: ID2D1Factory, IDWriteFactory, IDWriteTextFormat, and
// IDWriteTextLayout objects are device-independent. Which can be created
// earlier instead of creating them in the callback.
// But ID2D1RenderTarget is a device-dependent resource.
// The client should not hold the d2d render target object outside of
// this callback scope because the resource must be cleared before
// releasing/resizing DXGI swapchain.
videosink.connect_closure(
"present",
false,
glib::closure!(move |_sink: &gst::Element,
_device: &gst::Object,
rtv_raw: glib::Pointer| {
let overlay_context = overlay_context_weak.upgrade().unwrap();
let mut context = overlay_context.lock().unwrap();
let dwrite_factory = context.dwrite_factory.clone();
let d2d_factory = context.d2d_factory.clone();
// SAFETY: transmute() below is clearly unsafe operation here.
// Regarding the other part of the below block, all DirectX
// APIs are marked as unsafe, except for cast.
//
// In theory, all the Direct3D/Direct2D APIs could fail for
// some reasons (it's hardware!), but in practice, it's very unexpected
// situation and any of failure below would mean we are doing
// something in wrong way or driver bug or so.
unsafe {
let rtv = ID3D11RenderTargetView::from_raw_borrowed(&rtv_raw).unwrap();
let resource = rtv.GetResource().unwrap();
let texture = resource.cast::<ID3D11Texture2D>().unwrap();
let desc = {
let mut desc = D3D11_TEXTURE2D_DESC::default();
texture.GetDesc(&mut desc);
desc
};
// Window size was updated, creates new text layout
let calculate_font_size = if desc != context.texture_desc {
context.texture_desc = desc;
context.text_layout = None;
true
} else {
false
};
// New fps, creates new layout
if context.avg_fps != context.display_fps {
context.display_fps = context.avg_fps;
context.text_layout = None;
}
if context.text_layout.is_none() {
let overlay_string = format!("TextOverlay, Fps {:.1}", context.display_fps);
let overlay_wstring = overlay_string.encode_utf16().collect::<Vec<_>>();
let layout = dwrite_factory
.CreateTextLayout(
&overlay_wstring,
&context.text_format,
desc.Width as f32,
desc.Height as f32 / 5f32,
)
.unwrap();
// Adjust alignment
layout
.SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER)
.unwrap();
layout
.SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER)
.unwrap();
// XXX: This is not an efficient approach.
// The font size can be pre-calculated for a pre-defined
// window size and string length
let mut range = DWRITE_TEXT_RANGE {
startPosition: 0u32,
length: overlay_wstring.len() as u32,
};
if calculate_font_size {
let mut font_size = 12f32;
let mut was_decreased = false;
loop {
let mut metrics = DWRITE_TEXT_METRICS::default();
layout.GetMetrics(&mut metrics).unwrap();
layout
.GetFontSize(0, &mut font_size, Some(&mut range))
.unwrap();
if metrics.widthIncludingTrailingWhitespace >= desc.Width as f32 {
if font_size > 1f32 {
font_size -= 0.5f32;
was_decreased = true;
layout.SetFontSize(font_size, range).unwrap();
continue;
}
break;
}
if was_decreased {
break;
}
if metrics.widthIncludingTrailingWhitespace < desc.Width as f32 {
if metrics.widthIncludingTrailingWhitespace
>= desc.Width as f32 * 0.7f32
{
break;
}
font_size += 0.5f32;
layout.SetFontSize(font_size, range).unwrap();
}
}
context.font_size = font_size;
} else {
layout.SetFontSize(context.font_size, range).unwrap();
}
context.text_layout = Some(layout);
};
let dxgi_surf = resource.cast::<IDXGISurface>().unwrap();
let render_target = d2d_factory
.CreateDxgiSurfaceRenderTarget(
&dxgi_surf,
&D2D1_RENDER_TARGET_PROPERTIES {
r#type: D2D1_RENDER_TARGET_TYPE_DEFAULT,
pixelFormat: D2D1_PIXEL_FORMAT {
format: DXGI_FORMAT_B8G8R8A8_UNORM,
alphaMode: D2D1_ALPHA_MODE_PREMULTIPLIED,
},
// zero means default DPI
dpiX: 0f32,
dpiY: 0f32,
usage: D2D1_RENDER_TARGET_USAGE_NONE,
minLevel: D2D1_FEATURE_LEVEL_DEFAULT,
},
)
.unwrap();
let text_brush = render_target
.CreateSolidColorBrush(
&D2D1_COLOR_F {
r: 0f32,
g: 0f32,
b: 0f32,
a: 1f32,
},
None,
)
.unwrap();
let overlay_brush = render_target
.CreateSolidColorBrush(
&D2D1_COLOR_F {
r: 0f32,
g: 0.5f32,
b: 0.5f32,
a: 0.3f32,
},
None,
)
.unwrap();
render_target.BeginDraw();
// Draws overlay background. It will blend overlay's background
// color with already rendred video frame
render_target.FillRectangle(
&D2D_RECT_F {
left: 0f32,
top: 0f32,
right: desc.Width as f32,
bottom: desc.Height as f32 / 5f32,
},
&overlay_brush,
);
// Then, renders text
render_target.DrawTextLayout(
D2D_POINT_2F { x: 0f32, y: 0f32 },
context.text_layout.as_ref(),
&text_brush,
D2D1_DRAW_TEXT_OPTIONS_NONE,
);
// EndDraw may not be successful for some reasons.
// Ignores any error in this example
let _ = render_target.EndDraw(None, None);
}
}),
);
// Add pad probe to calculate framerate
let sinkpad = videosink.static_pad("sink").unwrap();
let overlay_context_weak = Arc::downgrade(&overlay_context);
sinkpad.add_probe(gst::PadProbeType::BUFFER, move |_, probe_info| {
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
});
let playbin = gst::ElementFactory::make("playbin")
.property("uri", &args[1])
.property("video-sink", &videosink)
.build()
.unwrap();
let main_loop_clone = main_loop.clone();
let bus = playbin.bus().unwrap();
let _bus_watch = bus
.add_watch(move |_, msg| {
use gst::MessageView;
let main_loop = &main_loop_clone;
match msg.view() {
MessageView::Eos(..) => {
println!("received eos");
main_loop.quit()
}
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
main_loop.quit();
}
_ => (),
};
glib::ControlFlow::Continue
})
.unwrap();
playbin.set_state(gst::State::Playing).unwrap();
main_loop.run();
playbin.set_state(gst::State::Null).unwrap();
Ok(())
}

View file

@ -5,10 +5,10 @@
//
// It's possible to dump the logs at any time in an application,
// not just on exit like is done here.
use gst::prelude::*;
use std::process;
use gst::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -19,21 +19,21 @@ 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>() {
println!("Missing element(s): {:?}", context.missing_elements());
} else {
println!("Failed to parse pipeline: {}", err);
println!("Failed to parse pipeline: {err}");
}
process::exit(-1)
@ -73,8 +73,8 @@ 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() {
println!("{}\n------------------", s);
for s in gst::log::ring_buffer_logger_get_logs().iter() {
println!("{s}\n------------------");
}
}

View file

@ -29,26 +29,24 @@
// Especially Windows APIs tend to be quite picky about samplerate and sample-format.
// The same applies to videostreams.
use gst::element_error;
use gst::element_warning;
use gst::prelude::*;
use std::env;
use std::sync::{Arc, Mutex};
use std::{
env,
sync::{Arc, Mutex},
};
use anyhow::Error;
use derive_more::{Display, Error};
use gst::{element_error, element_warning, prelude::*};
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
#[derive(Clone, Debug, glib::Boxed)]
@ -72,8 +70,8 @@ fn example_main() -> Result<(), Error> {
.build()?;
let decodebin = gst::ElementFactory::make("decodebin").build()?;
pipeline.add_many(&[&src, &decodebin])?;
gst::Element::link_many(&[&src, &decodebin])?;
pipeline.add_many([&src, &decodebin])?;
gst::Element::link_many([&src, &decodebin])?;
// Need to move a new reference into the closure.
// !!ATTENTION!!:
@ -92,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
@ -235,11 +232,10 @@ fn example_main() -> Result<(), Error> {
_ => Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into()),
}?;
@ -267,6 +263,6 @@ fn main() {
// (but not necessary in normal Cocoa applications where this is set up automatically)
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -8,21 +8,17 @@
// Discovered information could for example contain the stream's duration or whether it is
// seekable (filesystem) or not (some http servers).
use gst_pbutils::prelude::*;
use gst_pbutils::DiscovererInfo;
use gst_pbutils::DiscovererStreamInfo;
use std::env;
use anyhow::Error;
use derive_more::{Display, Error};
use std::env;
use gst_pbutils::{prelude::*, DiscovererInfo, DiscovererStreamInfo};
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Discoverer error {}", _0)]
#[display(fmt = "Discoverer error {_0}")]
struct DiscovererError(#[error(not(source))] &'static str);
fn print_tags(info: &DiscovererInfo) {
@ -31,7 +27,7 @@ fn print_tags(info: &DiscovererInfo) {
let tags = info.tags();
match tags {
Some(taglist) => {
println!(" {}", taglist); // FIXME use an iterator
println!(" {taglist}"); // FIXME use an iterator
}
None => {
println!(" no tags");
@ -41,12 +37,16 @@ fn print_tags(info: &DiscovererInfo) {
fn print_stream_info(stream: &DiscovererStreamInfo) {
println!("Stream: ");
println!(" Stream id: {}", stream.stream_id());
if let Some(stream_id) = stream.stream_id() {
println!(" Stream id: {}", stream_id);
}
let caps_str = match stream.caps() {
Some(caps) => caps.to_string(),
None => String::from("--"),
};
println!(" Format: {}", caps_str);
println!(" Format: {caps_str}");
}
fn print_discoverer_info(info: &DiscovererInfo) -> Result<(), Error> {
@ -89,7 +89,7 @@ fn run_discoverer() -> Result<(), Error> {
fn example_main() {
match run_discoverer() {
Ok(_) => (),
Err(e) => eprintln!("Error: {}", e),
Err(e) => eprintln!("Error: {e}"),
}
}

View file

@ -12,27 +12,25 @@
// {uridecodebin} -| {encodebin}-{filesink}
// \-{queue}-{videoconvert}-{videoscale}----/
use gst::element_error;
use gst::element_warning;
use gst_pbutils::prelude::*;
use std::env;
use std::sync::{Arc, Mutex};
use std::{
env,
sync::{Arc, Mutex},
};
use anyhow::Error;
use derive_more::{Display, Error};
use gst::{element_error, element_warning};
use gst_pbutils::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
#[derive(Clone, Debug, glib::Boxed)]
@ -62,8 +60,8 @@ fn configure_encodebin(encodebin: &gst::Element) {
&gst::Caps::builder("video/x-matroska").build(),
)
.name("container")
.add_profile(&(video_profile))
.add_profile(&(audio_profile))
.add_profile(video_profile)
.add_profile(audio_profile)
.build();
// Finally, apply the EncodingProfile onto our encodebin element.
@ -99,13 +97,13 @@ fn example_main() -> Result<(), Error> {
configure_encodebin(&encodebin);
pipeline
.add_many(&[&src, &encodebin, &sink])
.add_many([&src, &encodebin, &sink])
.expect("failed to add elements to pipeline");
// It is clear from the start, that encodebin has only one src pad, so we can
// directly link it to our filesink without problems.
// The caps of encodebin's src-pad are set after we configured the encoding-profile.
// (But filesink doesn't really care about the caps at its input anyway)
gst::Element::link_many(&[&encodebin, &sink])?;
gst::Element::link_many([&encodebin, &sink])?;
// Need to move a new reference into the closure.
// !!ATTENTION!!:
@ -122,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) = {
@ -191,7 +188,7 @@ fn example_main() -> Result<(), Error> {
// Request a sink pad from our encodebin, that can handle a raw videostream.
// The encodebin will then automatically create an internal pipeline, that encodes
// the audio stream in the format we specified in the EncodingProfile.
// the video stream in the format we specified in the EncodingProfile.
let enc_sink_pad = encodebin
.request_pad_simple("video_%u")
.expect("Could not get video pad from encodebin");
@ -252,11 +249,10 @@ fn example_main() -> Result<(), Error> {
_ => Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into()),
}?;
@ -284,6 +280,6 @@ fn main() {
// (but not necessary in normal Cocoa applications where this is set up automatically)
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

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
@ -50,14 +50,13 @@ fn example_main() {
// Add a timeout to the main loop. This closure will be executed
// in an interval of 5 seconds. The return value of the handler function
// determines whether the handler still wants to be called:
// - glib::Continue(false) - stop calling this handler, remove timeout
// - glib::Continue(true) - continue calling this handler
// - glib::ControlFlow::Break - stop calling this handler, remove timeout
// - glib::ControlFlow::Continue- continue calling this handler
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::Continue(false),
let Some(pipeline) = pipeline_weak.upgrade() else {
return glib::ControlFlow::Break;
};
println!("sending eos");
@ -77,7 +76,7 @@ fn example_main() {
// Remove this handler, the pipeline will shutdown anyway, now that we
// sent the EOS event.
glib::Continue(false)
glib::ControlFlow::Break
});
//bus.add_signal_watch();
@ -85,35 +84,36 @@ fn example_main() {
let main_loop_clone = main_loop.clone();
// This sets the bus's signal handler (don't be mislead by the "add", there can only be one).
// Every message from the bus is passed through this function. Its returnvalue determines
// whether the handler wants to be called again. If glib::Continue(false) is returned, the
// whether the handler wants to be called again. If glib::ControlFlow::Break is returned, the
// handler is removed and will never be called again. The mainloop still runs though.
bus.add_watch(move |_, msg| {
use gst::MessageView;
let _bus_watch = bus
.add_watch(move |_, msg| {
use gst::MessageView;
let main_loop = &main_loop_clone;
match msg.view() {
MessageView::Eos(..) => {
println!("received eos");
// An EndOfStream event was sent to the pipeline, so we tell our main loop
// to stop execution here.
main_loop.quit()
}
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
main_loop.quit();
}
_ => (),
};
let main_loop = &main_loop_clone;
match msg.view() {
MessageView::Eos(..) => {
println!("received eos");
// An EndOfStream event was sent to the pipeline, so we tell our main loop
// to stop execution here.
main_loop.quit()
}
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
main_loop.quit();
}
_ => (),
};
// Tell the mainloop to continue executing this callback.
glib::Continue(true)
})
.expect("Failed to add bus watch");
// Tell the mainloop to continue executing this callback.
glib::ControlFlow::Continue
})
.expect("Failed to add bus watch");
// Operate GStreamer's bus, facilliating GLib's mainloop here.
// This function call will block until you tell the mainloop to quit
@ -123,11 +123,6 @@ fn example_main() {
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
// Remove the watch function from the bus.
// Again: There can always only be one watch function.
// Thus we don't have to tell him which function to remove.
bus.remove_watch().unwrap();
}
fn main() {

View file

@ -14,32 +14,20 @@
// how the file descriptor of FdMemory can be accessed in a pipeline.
// Note that instead of manual mapping the file descriptor it is also possible
// to use map_writable, which will also map the file descriptor.
use futures::StreamExt;
use gst::{element_error, prelude::*};
use anyhow::Error;
use derive_more::{Display, Error};
use memmap2::MmapMut;
use uds::UnixStreamExt;
use std::{
os::unix::{net::UnixStream, prelude::AsRawFd},
sync::{Arc, Mutex},
};
use anyhow::Error;
use futures::StreamExt;
use gst::{element_error, prelude::*};
use memmap2::MmapMut;
use uds::UnixStreamExt;
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
}
fn create_receiver_pipeline(
video_info: &gst_video::VideoInfo,
receiver: UnixStream,
@ -57,8 +45,8 @@ fn create_receiver_pipeline(
let queue = gst::ElementFactory::make("queue").build()?;
let sink = gst::ElementFactory::make("autovideosink").build()?;
pipeline.add_many(&[src.upcast_ref(), &filter, &convert, &queue, &sink])?;
gst::Element::link_many(&[src.upcast_ref(), &filter, &convert, &queue, &sink])?;
pipeline.add_many([src.upcast_ref(), &filter, &convert, &queue, &sink])?;
gst::Element::link_many([src.upcast_ref(), &filter, &convert, &queue, &sink])?;
let fd_allocator = gst_allocators::FdAllocator::new();
let video_info = video_info.clone();
@ -127,8 +115,8 @@ fn create_sender_pipeline(
.ok_or_else(|| anyhow::anyhow!("is not a appsink"))?
.set_caps(Some(&caps));
pipeline.add_many(&[&src, &sink])?;
gst::Element::link_many(&[&src, &sink])?;
pipeline.add_many([&src, &sink])?;
gst::Element::link_many([&src, &sink])?;
let appsink = sink
.downcast::<gst_app::AppSink>()
@ -353,7 +341,7 @@ fn main() {
// (but not necessary in normal Cocoa applications where this is set up automatically)
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}
@ -370,12 +358,12 @@ mod video_filter {
}
}
mod imp {
use std::{cmp, mem::ManuallyDrop, os::unix::prelude::FromRawFd};
use std::{mem::ManuallyDrop, os::unix::prelude::FromRawFd};
use anyhow::Error;
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;
@ -430,9 +418,9 @@ mod video_filter {
let mut mmap = MmapMut::map_mut(mfd.as_file())?;
for pixel in mmap.chunks_exact_mut(4) {
pixel[0] = cmp::max(0, cmp::min(255, (pixel[0] as f64 * factor) as u8));
pixel[1] = cmp::max(0, cmp::min(255, (pixel[1] as f64 * factor) as u8));
pixel[2] = cmp::max(0, cmp::min(255, (pixel[2] as f64 * factor) as u8));
pixel[0] = (pixel[0] as f64 * factor).clamp(0.0, 255.0) as u8;
pixel[1] = (pixel[1] as f64 * factor).clamp(0.0, 255.0) as u8;
pixel[2] = (pixel[2] as f64 * factor).clamp(0.0, 255.0) as u8;
}
}
@ -442,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();
@ -452,9 +443,7 @@ mod video_filter {
PadTemplate::new("src", PadDirection::Src, PadPresence::Always, &caps)
.unwrap(),
]
});
PAD_TEMPLATES.as_ref()
})
}
}

View file

@ -3,13 +3,11 @@
// or for an EOS message. When a message notifying about either of both
// is received, the future is resolved.
use gst::prelude::*;
use futures::executor::LocalPool;
use futures::prelude::*;
use std::env;
use futures::{executor::LocalPool, prelude::*};
use gst::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -44,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

@ -35,12 +35,10 @@
// those with lowers (higher number). Thus, Layers with higher priority are "in the front".
// - The timeline is the enclosing element, grouping all layers and providing a timeframe.
use gst::prelude::*;
use std::env;
use ges::prelude::*;
use std::env;
#[allow(unused_imports)]
#[path = "../examples-common.rs"]
mod examples_common;
@ -60,12 +58,12 @@ fn configure_pipeline(pipeline: &ges::Pipeline, output_name: &str) {
let container_profile =
gst_pbutils::EncodingContainerProfile::builder(&gst::Caps::builder("video/webm").build())
.name("container")
.add_profile(&video_profile)
.add_profile(&audio_profile)
.add_profile(video_profile)
.add_profile(audio_profile)
.build();
// Apply the EncodingProfile to the pipeline, and set it to render mode
let output_uri = format!("{}.webm", output_name);
let output_uri = format!("{output_name}.webm");
pipeline
.set_render_settings(&output_uri, &container_profile)
.expect("Failed to set render settings");
@ -170,7 +168,7 @@ fn example_main() {
match main_loop(input_uri, output) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -1,5 +1,7 @@
#![allow(clippy::non_send_fields_in_send_ty)]
use anyhow::Result;
#[path = "../glupload.rs"]
mod glupload;
use glupload::*;
@ -28,16 +30,18 @@ void main () {
"#;
mod mirror {
use super::{gl, FRAGMENT_SHADER};
use gst_base::subclass::BaseTransformMode;
use gst_gl::prelude::*;
use gst_gl::subclass::prelude::*;
use gst_gl::subclass::GLFilterMode;
use gst_gl::*;
use once_cell::sync::Lazy;
use std::sync::Mutex;
use gst_base::subclass::BaseTransformMode;
use gst_gl::{
prelude::*,
subclass::{prelude::*, GLFilterMode},
*,
};
use once_cell::sync::Lazy;
use super::{gl, FRAGMENT_SHADER};
pub static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
gst::DebugCategory::new(
"rsglmirrorfilter",
@ -52,7 +56,7 @@ mod mirror {
impl GLMirrorFilter {
pub fn new(name: Option<&str>) -> Self {
glib::Object::new(&[("name", &name)])
glib::Object::builder().property("name", name).build()
}
}
@ -124,7 +128,7 @@ mod mirror {
}
impl GLBaseFilterImpl for GLMirrorFilter {
fn gl_start(&self) -> Result<(), gst::LoggableError> {
let filter = self.instance();
let filter = self.obj();
// Create a shader when GL is started, knowing that the OpenGL context is
// available.
@ -141,7 +145,7 @@ mod mirror {
input: &gst_gl::GLMemory,
output: &gst_gl::GLMemory,
) -> Result<(), gst::LoggableError> {
let filter = self.instance();
let filter = self.obj();
let shader = self.shader.lock().unwrap();
// Use the underlying filter implementation to transform the input texture into
@ -159,14 +163,12 @@ mod mirror {
}
}
fn example_main() {
fn example_main() -> Result<()> {
gst::init().unwrap();
let glfilter = mirror::GLMirrorFilter::new(Some("foo"));
App::new(Some(glfilter.as_ref()))
.and_then(main_loop)
.unwrap_or_else(|e| eprintln!("Error! {}", e))
let glfilter = mirror::GLMirrorFilter::new(Some("Mirror filter"));
App::new(Some(glfilter.as_ref())).and_then(main_loop)
}
fn main() {
examples_common::run(example_main);
fn main() -> Result<()> {
examples_common::run(example_main)
}

View file

@ -1,8 +1,7 @@
use gst::prelude::*;
use std::env;
use futures::prelude::*;
use std::env;
use gst::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -43,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

@ -1,179 +0,0 @@
// This example demonstrates how to use gstreamer in conjunction with the gtk widget toolkit.
// This example shows the video produced by a videotestsrc within a small gtk gui.
// For this, the gtkglsink is used, which creates a gtk widget one can embed the gtk gui.
// For this, there multiple types of widgets. gtkglsink uses OpenGL to render frames, and
// gtksink uses the CPU to render the frames (which is way slower).
// So the example application first tries to use OpenGL, and when that fails, fall back.
// The pipeline looks like the following:
// gtk-gui: {gtkglsink}-widget
// (|)
// {videotestsrc} - {glsinkbin}
use gst::prelude::*;
use gio::prelude::*;
use gtk::prelude::*;
use std::cell::RefCell;
fn create_ui(app: &gtk::Application) {
let pipeline = gst::Pipeline::default();
let src = gst::ElementFactory::make("videotestsrc").build().unwrap();
// Create the gtk sink and retrieve the widget from it. The sink element will be used
// in the pipeline, and the widget will be embedded in our gui.
// Gstreamer then displays frames in the gtk widget.
// First, we try to use the OpenGL version - and if that fails, we fall back to non-OpenGL.
let (sink, widget) = if let Ok(gtkglsink) = gst::ElementFactory::make("gtkglsink").build() {
// Using the OpenGL widget succeeded, so we are in for a nice playback experience with
// low cpu usage. :)
// The gtkglsink essentially allocates an OpenGL texture on the GPU, that it will display.
// Now we create the glsinkbin element, which is responsible for conversions and for uploading
// video frames to our texture (if they are not already in the GPU). Now we tell the OpenGL-sink
// about our gtkglsink element, form where it will retrieve the OpenGL texture to fill.
let glsinkbin = gst::ElementFactory::make("glsinkbin")
.property("sink", &gtkglsink)
.build()
.unwrap();
// The gtkglsink creates the gtk widget for us. This is accessible through a property.
// So we get it and use it later to add it to our gui.
let widget = gtkglsink.property::<gtk::Widget>("widget");
(glsinkbin, widget)
} else {
// Unfortunately, using the OpenGL widget didn't work out, so we will have to render
// our frames manually, using the CPU. An example why this may fail is, when
// the PC doesn't have proper graphics drivers installed.
let sink = gst::ElementFactory::make("gtksink").build().unwrap();
// The gtksink creates the gtk widget for us. This is accessible through a property.
// So we get it and use it later to add it to our gui.
let widget = sink.property::<gtk::Widget>("widget");
(sink, widget)
};
pipeline.add_many(&[&src, &sink]).unwrap();
src.link(&sink).unwrap();
// Create a simple gtk gui window to place our widget into.
let window = gtk::Window::new(gtk::WindowType::Toplevel);
window.set_default_size(320, 240);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
// Add our widget to the gui
vbox.pack_start(&widget, true, true, 0);
let label = gtk::Label::new(Some("Position: 00:00:00"));
vbox.pack_start(&label, true, true, 5);
window.add(&vbox);
window.show_all();
app.add_window(&window);
// Need to move a new reference into the closure.
// !!ATTENTION!!:
// It might seem appealing to use pipeline.clone() here, because that greatly
// simplifies the code within the callback. What this actually does, however, is creating
// a memory leak. The clone of a pipeline is a new strong reference on the pipeline.
// Storing this strong reference of the pipeline within the callback (we are moving it in!),
// which is in turn stored in another strong reference on the pipeline is creating a
// reference cycle.
// DO NOT USE pipeline.clone() TO USE THE PIPELINE WITHIN A CALLBACK
let pipeline_weak = pipeline.downgrade();
// Add a timeout to the main loop that will periodically (every 500ms) be
// executed. This will query the current position within the stream from
// the underlying pipeline, and display it in our gui.
// Since this closure is called by the mainloop thread, we are allowed
// to modify the gui widgets here.
let timeout_id = glib::timeout_add_local(std::time::Duration::from_millis(500), 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::Continue(true),
};
// Query the current playing position from the underlying pipeline.
let position = pipeline.query_position::<gst::ClockTime>();
// Display the playing position in the gui.
label.set_text(&format!("Position: {:.0}", position.display()));
// Tell the callback to continue calling this closure.
glib::Continue(true)
});
let bus = pipeline.bus().unwrap();
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
let app_weak = app.downgrade();
bus.add_watch_local(move |_, msg| {
use gst::MessageView;
let app = match app_weak.upgrade() {
Some(app) => app,
None => return glib::Continue(false),
};
match msg.view() {
MessageView::Eos(..) => app.quit(),
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
app.quit();
}
_ => (),
};
glib::Continue(true)
})
.expect("Failed to add bus watch");
// Pipeline reference is owned by the closure below, so will be
// destroyed once the app is destroyed
let timeout_id = RefCell::new(Some(timeout_id));
let pipeline = RefCell::new(Some(pipeline));
app.connect_shutdown(move |_| {
// Optional, by manually destroying the window here we ensure that
// the gst element is destroyed when shutting down instead of having to wait
// for the process to terminate, allowing us to use the leaks tracer.
unsafe {
window.destroy();
}
// GTK will keep the Application alive for the whole process lifetime.
// Wrapping the pipeline in a RefCell<Option<_>> and removing it from it here
// ensures the pipeline is actually destroyed when shutting down, allowing us
// to use the leaks tracer for example.
if let Some(pipeline) = pipeline.borrow_mut().take() {
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
pipeline.bus().unwrap().remove_watch().unwrap();
}
if let Some(timeout_id) = timeout_id.borrow_mut().take() {
timeout_id.remove();
}
});
}
fn main() {
// Initialize gstreamer and the gtk widget toolkit libraries.
gst::init().unwrap();
gtk::init().unwrap();
{
let app = gtk::Application::new(None, gio::ApplicationFlags::FLAGS_NONE);
app.connect_activate(create_ui);
app.run();
}
// Optional, can be used to detect leaks using the leaks tracer
unsafe {
gst::deinit();
}
}

View file

@ -1,290 +0,0 @@
// This example demonstrates another type of combination of gtk and gstreamer,
// in comparision to the gtksink example.
// This example uses regions that are managed by the window system, and uses
// the window system's api to insert a videostream into these regions.
// So essentially, the window system of the system overlays our gui with
// the video frames - within the region that we tell it to use.
// Disadvantage of this method is, that it's highly platform specific, since
// the big platforms all have their own window system. Thus, this example
// has special code to handle differences between platforms.
// Windows could theoretically be supported by this example, but is not yet implemented.
// One of the very few (if not the single one) platform, that can not provide the API
// needed for this are Linux desktops using Wayland.
// TODO: Add Windows support
// In this case, a testvideo is displayed within our gui, using the
// following pipeline:
// {videotestsrc} - {xvimagesink(on linux)}
// {videotestsrc} - {glimagesink(on mac)}
use gst_video::prelude::*;
use gio::prelude::*;
use gtk::prelude::*;
use std::os::raw::c_void;
use std::cell::RefCell;
use std::process;
#[cfg(all(target_os = "linux", feature = "gtkvideooverlay-x11"))]
fn create_video_sink() -> gst::Element {
// When we are on linux with the Xorg display server, we use the
// X11 protocol's XV extension, which allows to overlay regions
// with video streams. For this, we use the xvimagesink element.
gst::ElementFactory::make("xvimagesink").build().unwrap()
}
#[cfg(all(target_os = "linux", feature = "gtkvideooverlay-x11"))]
fn set_window_handle(video_overlay: &gst_video::VideoOverlay, gdk_window: &gdk::Window) {
let display_type_name = gdk_window.display().type_().name();
// Check if we're using X11 or ...
if display_type_name == "GdkX11Display" {
extern "C" {
pub fn gdk_x11_window_get_xid(window: *mut glib::gobject_ffi::GObject) -> *mut c_void;
}
// This is unsafe because the "window handle" we pass here is basically like a raw pointer.
// If a wrong value were to be passed here (and you can pass any integer), then the window
// system will most likely cause the application to crash.
#[allow(clippy::cast_ptr_alignment)]
unsafe {
// Here we ask gdk what native window handle we got assigned for
// our video region from the window system, and then we will
// pass this unique identifier to the overlay provided by our
// sink - so the sink can then arrange the overlay.
let xid = gdk_x11_window_get_xid(gdk_window.as_ptr() as *mut _);
video_overlay.set_window_handle(xid as usize);
}
} else {
println!("Add support for display type '{}'", display_type_name);
process::exit(-1);
}
}
#[cfg(all(target_os = "macos", feature = "gtkvideooverlay-quartz"))]
fn create_video_sink() -> gst::Element {
// On Mac, this is done by overlaying a window region with an
// OpenGL-texture, using the glimagesink element.
gst::ElementFactory::make("glimagesink").build().unwrap()
}
#[cfg(all(target_os = "macos", feature = "gtkvideooverlay-quartz"))]
fn set_window_handle(video_overlay: &gst_video::VideoOverlay, gdk_window: &gdk::Window) {
let display_type_name = gdk_window.display().type_().name();
if display_type_name == "GdkQuartzDisplay" {
extern "C" {
pub fn gdk_quartz_window_get_nsview(
window: *mut glib::gobject_ffi::GObject,
) -> *mut c_void;
}
// This is unsafe because the "window handle" we pass here is basically like a raw pointer.
// If a wrong value were to be passed here (and you can pass any integer), then the window
// system will most likely cause the application to crash.
#[allow(clippy::cast_ptr_alignment)]
unsafe {
// Here we ask gdk what native window handle we got assigned for
// our video region from the windowing system, and then we will
// pass this unique identifier to the overlay provided by our
// sink - so the sink can then arrange the overlay.
let window = gdk_quartz_window_get_nsview(gdk_window.as_ptr() as *mut _);
video_overlay.set_window_handle(window as usize);
}
} else {
println!("Unsupported display type '{}", display_type_name);
process::exit(-1);
}
}
fn create_ui(app: &gtk::Application) {
let pipeline = gst::Pipeline::default();
let src = gst::ElementFactory::make("videotestsrc").build().unwrap();
// Since using the window system to overlay our gui window is making
// direct contact with the windowing system, this is highly platform-
// specific. This example supports Linux and Mac (using X11 and Quartz).
let sink = create_video_sink();
pipeline.add_many(&[&src, &sink]).unwrap();
src.link(&sink).unwrap();
// First, we create our gtk window - which will contain a region where
// our overlayed video will be displayed in.
let window = gtk::Window::new(gtk::WindowType::Toplevel);
window.set_default_size(320, 240);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
// This creates the widget we will display our overlay in.
// Later, we will try to tell our window system about this region, so
// it can overlay it with our video stream.
let video_window = gtk::DrawingArea::new();
video_window.set_size_request(320, 240);
// Use the platform-specific sink to create our overlay.
// Since we only use the video_overlay in the closure below, we need a weak reference.
// !!ATTENTION!!:
// It might seem appealing to use .clone() here, because that greatly
// simplifies the code within the callback. What this actually does, however, is creating
// a memory leak.
let video_overlay = sink
.dynamic_cast::<gst_video::VideoOverlay>()
.unwrap()
.downgrade();
// Connect to this widget's realize signal, which will be emitted
// after its display has been initialized. This is neccessary, because
// the window system doesn't know about our region until it was initialized.
video_window.connect_realize(move |video_window| {
// Here we temporarily retrieve a strong reference on the video-overlay from the
// weak reference that we moved into the closure.
let video_overlay = match video_overlay.upgrade() {
Some(video_overlay) => video_overlay,
None => return,
};
// Gtk uses gdk under the hood, to handle its drawing. Drawing regions are
// called gdk windows. We request this underlying drawing region from the
// widget we will overlay with our video.
let gdk_window = video_window.window().unwrap();
// This is where we tell our window system about the drawing-region we
// want it to overlay. Most often, the window system would only know
// about our most outer region (or: our window).
if !gdk_window.ensure_native() {
println!("Can't create native window for widget");
process::exit(-1);
}
set_window_handle(&video_overlay, &gdk_window);
});
vbox.pack_start(&video_window, true, true, 0);
let label = gtk::Label::new(Some("Position: 00:00:00"));
vbox.pack_start(&label, true, true, 5);
window.add(&vbox);
window.show_all();
app.add_window(&window);
// Need to move a new reference into the closure.
// !!ATTENTION!!:
// It might seem appealing to use pipeline.clone() here, because that greatly
// simplifies the code within the callback. What this actually does, however, is creating
// a memory leak. The clone of a pipeline is a new strong reference on the pipeline.
// Storing this strong reference of the pipeline within the callback (we are moving it in!),
// which is in turn stored in another strong reference on the pipeline is creating a
// reference cycle.
// DO NOT USE pipeline.clone() TO USE THE PIPELINE WITHIN A CALLBACK
let pipeline_weak = pipeline.downgrade();
// Add a timeout to the main loop that will periodically (every 500ms) be
// executed. This will query the current position within the stream from
// the underlying pipeline, and display it in our gui.
// Since this closure is called by the mainloop thread, we are allowed
// to modify the gui widgets here.
let timeout_id = glib::timeout_add_local(std::time::Duration::from_millis(500), 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::Continue(false),
};
// Query the current playing position from the underlying pipeline.
let position = pipeline.query_position::<gst::ClockTime>();
// Display the playing position in the gui.
label.set_text(&format!("Position: {:.0}", position.display()));
// Tell the timeout to continue calling this callback.
glib::Continue(true)
});
let bus = pipeline.bus().unwrap();
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
let app_weak = app.downgrade();
bus.add_watch_local(move |_, msg| {
use gst::MessageView;
let app = match app_weak.upgrade() {
Some(app) => app,
None => return glib::Continue(false),
};
match msg.view() {
MessageView::Eos(..) => app.quit(),
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
app.quit();
}
_ => (),
};
glib::Continue(true)
})
.expect("Failed to add bus watch");
// Pipeline reference is owned by the closure below, so will be
// destroyed once the app is destroyed
let timeout_id = RefCell::new(Some(timeout_id));
let pipeline = RefCell::new(Some(pipeline));
app.connect_shutdown(move |_| {
// Optional, by manually destroying the window here we ensure that
// the gst element is destroyed when shutting down instead of having to wait
// for the process to terminate, allowing us to use the leaks tracer.
unsafe {
window.destroy();
}
// GTK will keep the Application alive for the whole process lifetime.
// Wrapping the pipeline in a RefCell<Option<_>> and removing it from it here
// ensures the pipeline is actually destroyed when shutting down, allowing us
// to use the leaks tracer for example.
if let Some(pipeline) = pipeline.borrow_mut().take() {
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
pipeline.bus().unwrap().remove_watch().unwrap();
}
if let Some(timeout_id) = timeout_id.borrow_mut().take() {
timeout_id.remove();
}
});
}
fn main() {
#[cfg(not(unix))]
{
println!("Add support for target platform");
process::exit(-1);
}
// Initialize gstreamer and the gtk widget toolkit libraries.
gst::init().unwrap();
gtk::init().unwrap();
{
let app = gtk::Application::new(None, gio::ApplicationFlags::FLAGS_NONE);
app.connect_activate(create_ui);
app.run();
}
// Optional, can be used to detect leaks using the leaks tracer
unsafe {
gst::deinit();
}
}

View file

@ -1,5 +1,5 @@
// This example demonstrates how to use GStreamer's iteration APIs.
// This is used at multiple occassions - for example to iterate an
// This is used at multiple occasions - for example to iterate an
// element's pads.
use gst::prelude::*;

View file

@ -3,10 +3,9 @@
// as launch syntax.
// When the parsing succeeded, the pipeline is run until the stream ends or an error happens.
use gst::prelude::*;
use std::{env, process};
use std::env;
use std::process;
use gst::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -18,7 +17,7 @@ fn example_main() {
gst::init().unwrap();
// Let GStreamer create a pipeline from the parsed launch syntax on the cli.
// In comparision to the launch_glib_main example, this is using the advanced launch syntax
// In comparison to the launch_glib_main example, this is using the advanced launch syntax
// parsing API of GStreamer. The function returns a Result, handing us the pipeline if
// parsing and creating succeeded, and hands us detailed error information if something
// went wrong. The error is passed as gst::ParseError. In this example, we separately
@ -27,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

@ -7,10 +7,10 @@
// things from the main loop (timeouts, UI events, socket events, ...) instead
// of just handling messages from GStreamer's bus.
use gst::prelude::*;
use std::env;
use gst::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -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
@ -35,38 +35,34 @@ fn example_main() {
//bus.add_signal_watch();
//bus.connect_message(None, move |_, msg| {
bus.add_watch(move |_, msg| {
use gst::MessageView;
let _bus_watch = bus
.add_watch(move |_, msg| {
use gst::MessageView;
let main_loop = &main_loop_clone;
match msg.view() {
MessageView::Eos(..) => main_loop.quit(),
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
main_loop.quit();
}
_ => (),
};
let main_loop = &main_loop_clone;
match msg.view() {
MessageView::Eos(..) => main_loop.quit(),
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
main_loop.quit();
}
_ => (),
};
glib::Continue(true)
})
.expect("Failed to add bus watch");
glib::ControlFlow::Continue
})
.expect("Failed to add bus watch");
main_loop.run();
pipeline
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
// Here we remove the bus watch we added above. This avoids a memory leak, that might
// otherwise happen because we moved a strong reference (clone of main_loop) into the
// callback closure above.
bus.remove_watch().unwrap();
}
fn main() {

View file

@ -0,0 +1,359 @@
// This example demonstrates how to draw an overlay on a video stream using
// Direct2D/DirectWrite/WIC and the overlay composition element.
// {videotestsrc} - {overlaycomposition} - {capsfilter} - {videoconvert} - {autovideosink}
// The capsfilter element allows us to dictate the video resolution we want for the
// videotestsrc and the overlaycomposition element.
use std::sync::{Arc, Mutex};
use byte_slice_cast::*;
use anyhow::Error;
use derive_more::{Display, Error};
use gst::prelude::*;
use windows::{
Foundation::Numerics::*,
Win32::{
Graphics::{
Direct2D::{Common::*, *},
DirectWrite::*,
Dxgi::Common::*,
Imaging::*,
},
System::Com::*,
},
};
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
struct ErrorMessage {
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
struct DrawingContext {
// Factory for creating render target
d2d_factory: ID2D1Factory,
// Used to create WIC bitmap surface
wic_factory: IWICImagingFactory,
// text layout holding text information (string, font, size, etc)
text_layout: IDWriteTextLayout,
// Holding rendred image
bitmap: Option<IWICBitmap>,
// Bound to bitmap and used to actual Direct2D rendering
render_target: Option<ID2D1RenderTarget>,
info: Option<gst_video::VideoInfo>,
}
// Required for IWICBitmap
unsafe impl Send for DrawingContext {}
fn create_pipeline() -> Result<gst::Pipeline, Error> {
gst::init()?;
let pipeline = gst::Pipeline::default();
// The videotestsrc supports multiple test patterns. In this example, we will use the
// pattern with a white ball moving around the video's center point.
let src = gst::ElementFactory::make("videotestsrc")
.property_from_str("pattern", "ball")
.build()?;
let overlay = gst::ElementFactory::make("overlaycomposition").build()?;
let caps = gst_video::VideoCapsBuilder::new()
.width(800)
.height(800)
.framerate((30, 1).into())
.build();
let capsfilter = gst::ElementFactory::make("capsfilter")
.property("caps", &caps)
.build()?;
let videoconvert = gst::ElementFactory::make("videoconvert").build()?;
let sink = gst::ElementFactory::make("autovideosink").build()?;
pipeline.add_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
gst::Element::link_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
// Most Direct2D/DirectWrite APIs (including factory methods) are marked as
// "unsafe", but they shouldn't fail in practice
let drawer = unsafe {
let d2d_factory =
D2D1CreateFactory::<ID2D1Factory>(D2D1_FACTORY_TYPE_MULTI_THREADED, None).unwrap();
let dwrite_factory =
DWriteCreateFactory::<IDWriteFactory>(DWRITE_FACTORY_TYPE_SHARED).unwrap();
let text_format = dwrite_factory
.CreateTextFormat(
windows::core::w!("Arial"),
None,
DWRITE_FONT_WEIGHT_BOLD,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
32f32,
windows::core::w!("en-us"),
)
.unwrap();
let text_layout = dwrite_factory
.CreateTextLayout(
windows::core::w!("GStreamer").as_wide(),
&text_format,
// Size will be updated later on "caps-changed" signal
800f32,
800f32,
)
.unwrap();
// Top (default) and center alignment
text_layout
.SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER)
.unwrap();
let wic_factory: IWICImagingFactory =
CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_ALL).unwrap();
Arc::new(Mutex::new(DrawingContext {
d2d_factory,
wic_factory,
text_layout,
bitmap: None,
render_target: None,
info: None,
}))
};
overlay.connect_closure(
"draw",
false,
glib::closure!(@strong drawer => move |_overlay: &gst::Element,
sample: &gst::Sample| {
use std::f64::consts::PI;
let drawer = drawer.lock().unwrap();
let buffer = sample.buffer().unwrap();
let timestamp = buffer.pts().unwrap();
let info = drawer.info.as_ref().unwrap();
let text_layout = &drawer.text_layout;
let bitmap = drawer.bitmap.as_ref().unwrap();
let render_target = drawer.render_target.as_ref().unwrap();
let global_angle = 360. * (timestamp % (10 * gst::ClockTime::SECOND)).nseconds() as f64
/ (10.0 * gst::ClockTime::SECOND.nseconds() as f64);
let center_x = (info.width() / 2) as f32;
let center_y = (info.height() / 2) as f32;
let top_margin = (info.height() / 20) as f32;
unsafe {
// Begin drawing
render_target.BeginDraw();
// Clear background
render_target.Clear(Some(&D2D1_COLOR_F {
r: 0f32,
g: 0f32,
b: 0f32,
a: 0f32,
}));
// This loop will render 10 times the string "GStreamer" in a circle
for i in 0..10 {
let angle = (360. * f64::from(i)) / 10.0;
let red = ((1.0 + f64::cos((angle - 60.0) * PI / 180.0)) / 2.0) as f32;
let text_brush = render_target
.CreateSolidColorBrush(
&D2D1_COLOR_F {
r: red,
g: 0f32,
b: 1f32 - red,
a: 1f32,
},
None,
)
.unwrap();
let angle = (angle + global_angle) as f32;
let matrix = Matrix3x2::rotation(angle, center_x, center_y);
render_target.SetTransform(&matrix);
render_target.DrawTextLayout(
D2D_POINT_2F { x: 0f32, y: top_margin },
text_layout,
&text_brush,
D2D1_DRAW_TEXT_OPTIONS_NONE,
);
}
// EndDraw may not be successful for some reasons.
// Ignores any error in this example
let _ = render_target.EndDraw(None, None);
// Make sure all operations is completed before copying
// bitmap to buffer
let _ = render_target.Flush(None::<*mut u64>, None::<*mut u64>);
}
let mut buffer = gst::Buffer::with_size((info.width() * info.height() * 4) as usize).unwrap();
{
let buffer_mut = buffer.get_mut().unwrap();
let mut map = buffer_mut.map_writable().unwrap();
let dst = map.as_mut_slice_of::<u8>().unwrap();
unsafe {
// Bitmap size is equal to the background image size.
// Copy entire memory
bitmap.CopyPixels(std::ptr::null(), info.width() * 4, dst).unwrap();
}
}
gst_video::VideoMeta::add_full(
buffer.get_mut().unwrap(),
gst_video::VideoFrameFlags::empty(),
gst_video::VideoFormat::Bgra,
info.width(),
info.height(),
&[0],
&[(info.width() * 4) as i32],
)
.unwrap();
// Turn the buffer into a VideoOverlayRectangle, then place
// that into a VideoOverlayComposition and return it.
//
// A VideoOverlayComposition can take a Vec of such rectangles
// spaced around the video frame, but we're just outputting 1
// here
let rect = gst_video::VideoOverlayRectangle::new_raw(
&buffer,
0,
0,
info.width(),
info.height(),
gst_video::VideoOverlayFormatFlags::PREMULTIPLIED_ALPHA,
);
gst_video::VideoOverlayComposition::new(Some(&rect))
.unwrap()
}),
);
// Add a signal handler to the overlay's "caps-changed" signal. This could e.g.
// be called when the sink that we render to does not support resizing the image
// itself - but the user just changed the window-size. The element after the overlay
// will then change its caps and we use the notification about this change to
// resize our canvas's size.
// Another possibility for when this might happen is, when our video is a network
// stream that dynamically changes resolution when enough bandwidth is available.
overlay.connect_closure(
"caps-changed",
false,
glib::closure!(move |_overlay: &gst::Element,
caps: &gst::Caps,
_width: u32,
_height: u32| {
let mut drawer = drawer.lock().unwrap();
let info = gst_video::VideoInfo::from_caps(caps).unwrap();
unsafe {
// Update text layout to be identical to new video resolution
drawer.text_layout.SetMaxWidth(info.width() as f32).unwrap();
drawer
.text_layout
.SetMaxHeight(info.height() as f32)
.unwrap();
// Create new WIC bitmap with PBGRA format (pre-multiplied BGRA)
let bitmap = drawer
.wic_factory
.CreateBitmap(
info.width(),
info.height(),
&GUID_WICPixelFormat32bppPBGRA,
WICBitmapCacheOnDemand,
)
.unwrap();
let render_target = drawer
.d2d_factory
.CreateWicBitmapRenderTarget(
&bitmap,
&D2D1_RENDER_TARGET_PROPERTIES {
r#type: D2D1_RENDER_TARGET_TYPE_DEFAULT,
pixelFormat: D2D1_PIXEL_FORMAT {
format: DXGI_FORMAT_B8G8R8A8_UNORM,
alphaMode: D2D1_ALPHA_MODE_PREMULTIPLIED,
},
// zero means default DPI
dpiX: 0f32,
dpiY: 0f32,
usage: D2D1_RENDER_TARGET_USAGE_NONE,
minLevel: D2D1_FEATURE_LEVEL_DEFAULT,
},
)
.unwrap();
drawer.render_target = Some(render_target);
drawer.bitmap = Some(bitmap);
}
drawer.info = Some(info);
}),
);
Ok(pipeline)
}
fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
pipeline.set_state(gst::State::Playing)?;
let bus = pipeline
.bus()
.expect("Pipeline without bus. Shouldn't happen!");
for msg in bus.iter_timed(gst::ClockTime::NONE) {
use gst::MessageView;
match msg.view() {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
pipeline.set_state(gst::State::Null)?;
return Err(ErrorMessage {
src: msg
.src()
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
}
.into());
}
_ => (),
}
}
pipeline.set_state(gst::State::Null)?;
Ok(())
}
fn main() {
// WIC requires COM initialization
unsafe {
CoInitializeEx(None, COINIT_MULTITHREADED).unwrap();
}
match create_pipeline().and_then(main_loop) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
}
unsafe {
CoUninitialize();
}
}

View file

@ -8,26 +8,25 @@
// The capsfilter element allows us to dictate the video resolution we want for the
// videotestsrc and the overlaycomposition element.
use gst::prelude::*;
use pango::prelude::*;
use std::ops;
use std::sync::{Arc, Mutex};
use std::{
ops,
sync::{Arc, Mutex},
};
use anyhow::Error;
use derive_more::{Display, Error};
use gst::prelude::*;
use pango::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
struct DrawingContext {
@ -78,8 +77,8 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
let videoconvert = gst::ElementFactory::make("videoconvert").build()?;
let sink = gst::ElementFactory::make("autovideosink").build()?;
pipeline.add_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
gst::Element::link_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
pipeline.add_many([&src, &overlay, &capsfilter, &videoconvert, &sink])?;
gst::Element::link_many([&src, &overlay, &capsfilter, &videoconvert, &sink])?;
// The PangoFontMap represents the set of fonts available for a particular rendering system.
let fontmap = pangocairo::FontMap::new();
@ -151,7 +150,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// The image we draw (the text) will be static, but we will change the
// transformation on the drawing context, which rotates and shifts everything
// that we draw afterwards. Like this, we have no complicated calulations
// that we draw afterwards. Like this, we have no complicated calculations
// in the actual drawing below.
// Calling multiple transformation methods after each other will apply the
// new transformation on top. If you repeat the cr.rotate(angle) line below
@ -178,9 +177,9 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// Update the text layout. This function is only updating pango's internal state.
// So e.g. that after a 90 degree rotation it knows that what was previously going
// to end up as a 200x100 rectangle would now be 100x200.
pangocairo::functions::update_layout(&cr, &**layout);
pangocairo::functions::update_layout(&cr, layout);
let (width, _height) = layout.size();
// Using width and height of the text, we can properly possition it within
// Using width and height of the text, we can properly position it within
// our canvas.
cr.move_to(
-(f64::from(width) / f64::from(pango::SCALE)) / 2.0,
@ -188,7 +187,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
);
// After telling the layout object where to draw itself, we actually tell
// it to draw itself into our cairo context.
pangocairo::functions::show_layout(&cr, &**layout);
pangocairo::functions::show_layout(&cr, layout);
// Here we go one step up in our stack of transformations, removing any
// changes we did to them since the last call to cr.save();
@ -242,7 +241,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// will then change its caps and we use the notification about this change to
// resize our canvas's size.
// Another possibility for when this might happen is, when our video is a network
// stream that dynamically changes resolution when enough bandwith is available.
// stream that dynamically changes resolution when enough bandwidth is available.
overlay.connect_closure(
"caps-changed",
false,
@ -275,11 +274,10 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
return Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into());
}
@ -295,7 +293,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
fn example_main() {
match create_pipeline().and_then(main_loop) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -8,11 +8,10 @@
// {audiotestsrc} - {fakesink}
#![allow(clippy::question_mark)]
use gst::prelude::*;
use std::i16;
use byte_slice_cast::*;
use std::i16;
use gst::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -23,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
))
@ -39,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

@ -11,26 +11,25 @@
// The capsfilter element allows us to dictate the video resolution we want for the
// videotestsrc and the cairooverlay element.
use gst::prelude::*;
use pango::prelude::*;
use std::ops;
use std::sync::{Arc, Mutex};
use std::{
ops,
sync::{Arc, Mutex},
};
use anyhow::Error;
use derive_more::{Display, Error};
use gst::prelude::*;
use pango::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
struct DrawingContext {
@ -77,8 +76,8 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
let videoconvert = gst::ElementFactory::make("videoconvert").build()?;
let sink = gst::ElementFactory::make("autovideosink").build()?;
pipeline.add_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
gst::Element::link_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
pipeline.add_many([&src, &overlay, &capsfilter, &videoconvert, &sink])?;
gst::Element::link_many([&src, &overlay, &capsfilter, &videoconvert, &sink])?;
// The PangoFontMap represents the set of fonts available for a particular rendering system.
let fontmap = pangocairo::FontMap::new();
@ -135,7 +134,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// The image we draw (the text) will be static, but we will change the
// transformation on the drawing context, which rotates and shifts everything
// that we draw afterwards. Like this, we have no complicated calulations
// that we draw afterwards. Like this, we have no complicated calculations
// in the actual drawing below.
// Calling multiple transformation methods after each other will apply the
// new transformation on top. If you repeat the cr.rotate(angle) line below
@ -162,9 +161,9 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// Update the text layout. This function is only updating pango's internal state.
// So e.g. that after a 90 degree rotation it knows that what was previously going
// to end up as a 200x100 rectangle would now be 100x200.
pangocairo::functions::update_layout(&cr, &**layout);
pangocairo::functions::update_layout(&cr, layout);
let (width, _height) = layout.size();
// Using width and height of the text, we can properly possition it within
// Using width and height of the text, we can properly position it within
// our canvas.
cr.move_to(
-(f64::from(width) / f64::from(pango::SCALE)) / 2.0,
@ -172,7 +171,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
);
// After telling the layout object where to draw itself, we actually tell
// it to draw itself into our cairo context.
pangocairo::functions::show_layout(&cr, &**layout);
pangocairo::functions::show_layout(&cr, layout);
// Here we go one step up in our stack of transformations, removing any
// changes we did to them since the last call to cr.save();
@ -188,7 +187,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// will then change its caps and we use the notification about this change to
// resize our canvas's size.
// Another possibility for when this might happen is, when our video is a network
// stream that dynamically changes resolution when enough bandwith is available.
// stream that dynamically changes resolution when enough bandwidth is available.
overlay.connect("caps-changed", false, move |args| {
let _overlay = args[0].get::<gst::Element>().unwrap();
let caps = args[1].get::<gst::Caps>().unwrap();
@ -219,11 +218,10 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
return Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into());
}
@ -239,7 +237,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
fn example_main() {
match create_pipeline().and_then(main_loop) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -17,7 +17,7 @@ use gst_play::{Play, PlayMessage, PlayVideoRenderer};
fn main_loop(uri: &str) -> Result<(), Error> {
gst::init()?;
let play = Play::new(PlayVideoRenderer::NONE);
let play = Play::new(None::<PlayVideoRenderer>);
play.set_uri(Some(uri));
play.play();
@ -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())
}
@ -51,7 +56,7 @@ fn example_main() {
match main_loop(uri) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -9,10 +9,10 @@
// Much of the playbin's behavior can be controlled by so-called flags, as well
// as the playbin's properties and signals.
use gst::prelude::*;
use std::env;
use gst::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -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.
@ -59,13 +59,13 @@ fn example_main() {
let playbin = values[0]
.get::<glib::Object>()
.expect("playbin \"audio-tags-changed\" signal values[1]");
// This gets the index of the stream that changed. This is neccessary, since
// This gets the index of the stream that changed. This is necessary, since
// there could e.g. be multiple audio streams (english, spanish, ...).
let idx = values[1]
.get::<i32>()
.expect("playbin \"audio-tags-changed\" signal values[1]");
println!("audio tags of audio stream {} changed:", idx);
println!("audio tags of audio stream {idx} changed:");
// HELP: is this correct?
// We were only notified about the change of metadata. If we want to do
@ -121,7 +121,7 @@ fn example_main() {
MessageView::StateChanged(state_changed) =>
// We are only interested in state-changed messages from playbin
{
if state_changed.src().map(|s| s == playbin).unwrap_or(false)
if state_changed.src().map(|s| s == &playbin).unwrap_or(false)
&& state_changed.current() == gst::State::Playing
{
// Generate a dot graph of the pipeline to GST_DEBUG_DUMP_DOT_DIR if defined

View file

@ -5,12 +5,13 @@
// audio / subtitle streams or changing the volume) are all supported by simple
// one-line function calls on the GstPlayer.
use gst::prelude::*;
use std::env;
use std::sync::{Arc, Mutex};
use std::{
env,
sync::{Arc, Mutex},
};
use anyhow::Error;
use gst::prelude::*;
#[allow(unused_imports)]
#[path = "../examples-common.rs"]
@ -23,8 +24,8 @@ fn main_loop(uri: &str) -> Result<(), Error> {
let dispatcher = gst_player::PlayerGMainContextSignalDispatcher::new(None);
let player = gst_player::Player::new(
gst_player::PlayerVideoRenderer::NONE,
Some(&dispatcher.upcast::<gst_player::PlayerSignalDispatcher>()),
None::<gst_player::PlayerVideoRenderer>,
Some(dispatcher.upcast::<gst_player::PlayerSignalDispatcher>()),
);
// Tell the player what uri to play.
@ -75,7 +76,7 @@ fn example_main() {
match main_loop(uri) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -12,10 +12,10 @@
// For convenience, the API has a set of pre-defined queries, but also
// allows custom queries (which can be defined and used by your own elements).
use gst::prelude::*;
use std::env;
use gst::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -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::Continue(true),
let Some(pipeline) = pipeline_weak.upgrade() else {
return glib::ControlFlow::Break;
};
//let pos = pipeline.query_position(gst::Format::Time).unwrap_or(-1);
@ -87,34 +86,35 @@ fn example_main() {
println!("{} / {}", pos.display(), dur.display());
glib::Continue(true)
glib::ControlFlow::Continue
});
// Need to move a new reference into the closure.
let main_loop_clone = main_loop.clone();
//bus.add_signal_watch();
//bus.connect_message(None, move |_, msg| {
bus.add_watch(move |_, msg| {
use gst::MessageView;
let _bus_watch = bus
.add_watch(move |_, msg| {
use gst::MessageView;
let main_loop = &main_loop_clone;
match msg.view() {
MessageView::Eos(..) => main_loop.quit(),
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
main_loop.quit();
}
_ => (),
};
let main_loop = &main_loop_clone;
match msg.view() {
MessageView::Eos(..) => main_loop.quit(),
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
main_loop.quit();
}
_ => (),
};
glib::Continue(true)
})
.expect("Failed to add bus watch");
glib::ControlFlow::Continue
})
.expect("Failed to add bus watch");
main_loop.run();
@ -122,7 +122,6 @@ fn example_main() {
.set_state(gst::State::Null)
.expect("Unable to set the pipeline to the `Null` state");
bus.remove_watch().unwrap();
timeout_id.remove();
}

View file

@ -1,8 +1,7 @@
use gst::element_error;
use gst::prelude::*;
use std::env;
use gst::{element_error, prelude::*};
#[path = "../examples-common.rs"]
mod examples_common;
@ -10,24 +9,23 @@ use anyhow::Error;
use derive_more::{Display, Error};
#[derive(Debug, Display, Error)]
#[display(fmt = "No such pad {} in {}", _0, _1)]
#[display(fmt = "No such pad {_0} in {_1}")]
struct NoSuchPad(#[error(not(source))] &'static str, String);
#[derive(Debug, Display, Error)]
#[display(fmt = "Unknown payload type {}", _0)]
#[display(fmt = "Unknown payload type {_0}")]
struct UnknownPT(#[error(not(source))] u32);
#[derive(Debug, Display, Error)]
#[display(fmt = "Usage: {} (play | record) DROP_PROBABILITY", _0)]
#[display(fmt = "Usage: {_0} (play | record) DROP_PROBABILITY")]
struct UsageError(#[error(not(source))] String);
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
fn static_pad(element: &gst::Element, pad_name: &'static str) -> Result<gst::Pad, Error> {
@ -116,8 +114,8 @@ fn example_main() -> Result<(), Error> {
.property("caps", &video_caps)
.build()?;
pipeline.add_many(&[&src, &netsim, &rtpbin, &depay, &dec, &conv, &scale, &filter])?;
gst::Element::link_many(&[&depay, &dec, &conv, &scale, &filter])?;
pipeline.add_many([&src, &netsim, &rtpbin, &depay, &dec, &conv, &scale, &filter])?;
gst::Element::link_many([&depay, &dec, &conv, &scale, &filter])?;
match args[1].as_str() {
"play" => {
@ -134,8 +132,8 @@ fn example_main() -> Result<(), Error> {
.property("location", "out.mkv")
.build()?;
pipeline.add_many(&[&enc, &mux, &sink])?;
gst::Element::link_many(&[&filter, &enc, &mux, &sink])?;
pipeline.add_many([&enc, &mux, &sink])?;
gst::Element::link_many([&filter, &enc, &mux, &sink])?;
eprintln!("Recording to out.mkv");
}
_ => return Err(Error::from(UsageError(args[0].clone()))),
@ -205,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) {
@ -244,23 +241,18 @@ fn example_main() -> Result<(), Error> {
return Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into());
}
MessageView::StateChanged(s) => {
if let Some(element) = msg.src() {
if element == pipeline && s.current() == gst::State::Playing {
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");
}
}
}
@ -278,6 +270,6 @@ fn example_main() -> Result<(), Error> {
fn main() {
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -1,5 +1,4 @@
use gst::element_error;
use gst::prelude::*;
use gst::{element_error, prelude::*};
#[path = "../examples-common.rs"]
mod examples_common;
@ -10,20 +9,19 @@ use anyhow::Error;
use derive_more::{Display, Error};
#[derive(Debug, Display, Error)]
#[display(fmt = "No such pad {} in {}", _0, _1)]
#[display(fmt = "No such pad {_0} in {_1}")]
struct NoSuchPad(&'static str, String);
#[derive(Debug, Display, Error)]
#[display(fmt = "Usage: {} URI FEC_PERCENTAGE", _0)]
#[display(fmt = "Usage: {_0} URI FEC_PERCENTAGE")]
struct UsageError(#[error(not(source))] String);
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
fn static_pad(element: &gst::Element, pad_name: &'static str) -> Result<gst::Pad, Error> {
@ -101,7 +99,7 @@ fn example_main() -> Result<(), Error> {
.property("sync", true)
.build()?;
pipeline.add_many(&[&src, &conv, &q1, &enc, &q2, &pay, &rtpbin, &sink])?;
pipeline.add_many([&src, &conv, &q1, &enc, &q2, &pay, &rtpbin, &sink])?;
conv.link(&q1)?;
q1.link(&enc)?;
@ -170,23 +168,18 @@ fn example_main() -> Result<(), Error> {
return Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into());
}
MessageView::StateChanged(s) => {
if let Some(element) = msg.src() {
if element == pipeline && s.current() == gst::State::Playing {
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");
}
}
}
@ -204,6 +197,6 @@ fn example_main() -> Result<(), Error> {
fn main() {
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

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

@ -5,13 +5,10 @@
// to this example's cli is spawned and the client's media is streamed into it.
use std::env;
use std::ptr;
use glib::translate::*;
use gst_rtsp_server::prelude::*;
use anyhow::Error;
use derive_more::{Display, Error};
use gst_rtsp_server::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -21,7 +18,7 @@ mod examples_common;
struct NoMountPoints;
#[derive(Debug, Display, Error)]
#[display(fmt = "Usage: {} LAUNCH_LINE", _0)]
#[display(fmt = "Usage: {_0} LAUNCH_LINE")]
struct UsageError(#[error(not(source))] String);
fn main_loop() -> Result<(), Error> {
@ -47,12 +44,11 @@ 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 propery authentication, we want to use encryption. And there's no
// For proper authentication, we want to use encryption. And there's no
// encryption without a certificate!
let cert = gio::TlsCertificate::from_pem(
"-----BEGIN CERTIFICATE-----\
@ -80,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);
@ -121,7 +107,7 @@ fn main_loop() -> Result<(), Error> {
// Now we add a new mount-point and tell the RTSP server to use the factory
// we configured beforehand. This factory will take on the job of creating
// a pipeline, which will take on the incoming data of connected clients.
mounts.add_factory("/test", &factory);
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
@ -154,6 +140,6 @@ fn example_main() -> Result<(), Error> {
fn main() {
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -8,10 +8,9 @@
// the client machinery and printing some status.
#![allow(clippy::non_send_fields_in_send_ty)]
use gst_rtsp_server::prelude::*;
use anyhow::Error;
use derive_more::{Display, Error};
use gst_rtsp_server::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -20,10 +19,6 @@ mod examples_common;
#[display(fmt = "Could not get mount points")]
struct NoMountPoints;
#[derive(Debug, Display, Error)]
#[display(fmt = "Usage: {} LAUNCH_LINE", _0)]
struct UsageError(#[error(not(source))] String);
fn main_loop() -> Result<(), Error> {
let main_loop = glib::MainLoop::new(None, false);
let server = server::Server::default();
@ -54,7 +49,7 @@ fn main_loop() -> Result<(), Error> {
// 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);
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
@ -81,10 +76,10 @@ fn main_loop() -> Result<(), Error> {
// Our custom media factory that creates a media input manually
mod media_factory {
use super::*;
use gst_rtsp_server::subclass::prelude::*;
use super::*;
// In the imp submodule we include the actual implementation
mod imp {
use super::*;
@ -108,7 +103,7 @@ mod media_factory {
fn constructed(&self) {
self.parent_constructed();
let factory = self.instance();
let factory = self.obj();
// All media created by this factory are our custom media type. This would
// not require a media factory subclass and can also be called on the normal
// RTSPMediaFactory.
@ -138,8 +133,8 @@ mod media_factory {
.build()
.unwrap();
bin.add_many(&[&src, &enc, &pay]).unwrap();
gst::Element::link_many(&[&src, &enc, &pay]).unwrap();
bin.add_many([&src, &enc, &pay]).unwrap();
gst::Element::link_many([&src, &enc, &pay]).unwrap();
Some(bin.upcast())
}
@ -155,7 +150,7 @@ mod media_factory {
impl Default for Factory {
// Creates a new instance of our factory
fn default() -> Factory {
glib::Object::new(&[])
glib::Object::new()
}
}
}
@ -211,10 +206,10 @@ mod media {
// Our custom RTSP server subclass that reports when clients are connecting and uses
// our custom RTSP client subclass for each client
mod server {
use super::*;
use gst_rtsp_server::subclass::prelude::*;
use super::*;
// In the imp submodule we include the actual implementation
mod imp {
use super::*;
@ -239,7 +234,7 @@ mod server {
// Implementation of gst_rtsp_server::RTSPServer virtual methods
impl RTSPServerImpl for Server {
fn create_client(&self) -> Option<gst_rtsp_server::RTSPClient> {
let server = self.instance();
let server = self.obj();
let client = super::client::Client::default();
// Duplicated from the default implementation
@ -253,7 +248,7 @@ mod server {
fn client_connected(&self, client: &gst_rtsp_server::RTSPClient) {
self.parent_client_connected(client);
println!("Client {:?} connected", client);
println!("Client {client:?} connected");
}
}
}
@ -267,7 +262,7 @@ mod server {
impl Default for Server {
// Creates a new instance of our factory
fn default() -> Server {
glib::Object::new(&[])
glib::Object::new()
}
}
}
@ -300,9 +295,15 @@ mod client {
// Implementation of gst_rtsp_server::RTSPClient virtual methods
impl RTSPClientImpl for Client {
fn closed(&self) {
let client = self.instance();
let client = self.obj();
self.parent_closed();
println!("Client {:?} closed", client);
println!("Client {client:?} closed");
}
fn describe_request(&self, ctx: &gst_rtsp_server::RTSPContext) {
self.parent_describe_request(ctx);
let request_uri = ctx.uri().unwrap().request_uri();
println!("Describe request for uri: {request_uri:?}");
}
}
}
@ -316,7 +317,7 @@ mod client {
impl Default for Client {
// Creates a new instance of our factory
fn default() -> Client {
glib::Object::new(&[])
glib::Object::new()
}
}
}
@ -347,7 +348,7 @@ mod mount_points {
// Implementation of gst_rtsp_server::RTSPClient virtual methods
impl RTSPMountPointsImpl for MountPoints {
fn make_path(&self, url: &gst_rtsp::RTSPUrl) -> Option<glib::GString> {
println!("Make path called for {:?} ", url);
println!("Make path called for {url:?} ");
self.parent_make_path(url)
}
}
@ -360,7 +361,7 @@ mod mount_points {
impl Default for MountPoints {
// Creates a new instance of our factory
fn default() -> Self {
glib::Object::new(&[])
glib::Object::new()
}
}
}
@ -373,6 +374,6 @@ fn example_main() -> Result<(), Error> {
fn main() {
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -5,10 +5,9 @@
use std::env;
use gst_rtsp_server::prelude::*;
use anyhow::Error;
use derive_more::{Display, Error};
use gst_rtsp_server::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -18,7 +17,7 @@ mod examples_common;
struct NoMountPoints;
#[derive(Debug, Display, Error)]
#[display(fmt = "Usage: {} LAUNCH_LINE", _0)]
#[display(fmt = "Usage: {_0} LAUNCH_LINE")]
struct UsageError(#[error(not(source))] String);
fn main_loop() -> Result<(), Error> {
@ -57,7 +56,7 @@ fn main_loop() -> Result<(), Error> {
// 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);
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
@ -90,6 +89,6 @@ fn example_main() -> Result<(), Error> {
fn main() {
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -7,20 +7,17 @@
// coefficients are provided via Rust API on the filter as a Vec<f32>.
#![allow(clippy::non_send_fields_in_send_ty)]
use gst::prelude::*;
use anyhow::Error;
use derive_more::{Display, Error};
use gst::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
// Our custom FIR filter element is defined in this module
mod fir_filter {
use gst_base::subclass::prelude::*;
use byte_slice_cast::*;
use gst_base::subclass::prelude::*;
use once_cell::sync::Lazy;
// The debug category we use below for our filter
@ -34,9 +31,9 @@ mod fir_filter {
// In the imp submodule we include the actual implementation
mod imp {
use std::{collections::VecDeque, sync::Mutex};
use super::*;
use std::collections::VecDeque;
use std::sync::Mutex;
// This is the private data of our filter
#[derive(Default)]
@ -63,23 +60,27 @@ mod fir_filter {
// Implementation of gst::Element virtual methods
impl ElementImpl for FirFilter {
// The element specific metadata. This information is what is visible from
// gst-inspect-1.0 and can also be programatically retrieved from the gst::Registry
// 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.
@ -110,9 +111,7 @@ mod fir_filter {
)
.unwrap(),
]
});
PAD_TEMPLATES.as_ref()
})
}
}
@ -219,7 +218,7 @@ mod fir_filter {
impl FirFilter {
// Creates a new instance of our filter with the given name
pub fn new(name: Option<&str>) -> FirFilter {
glib::Object::new(&[("name", &name)])
glib::Object::builder().property("name", name).build()
}
// Sets the coefficients by getting access to the private
@ -232,12 +231,11 @@ mod fir_filter {
}
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
fn create_pipeline() -> Result<gst::Pipeline, Error> {
@ -252,7 +250,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
let conv = gst::ElementFactory::make("audioconvert").build()?;
let sink = gst::ElementFactory::make("autoaudiosink").build()?;
pipeline.add_many(&[&src, filter.upcast_ref(), &conv, &sink])?;
pipeline.add_many([&src, filter.upcast_ref(), &conv, &sink])?;
src.link(&filter)?;
filter.link(&conv)?;
conv.link(&sink)?;
@ -306,11 +304,10 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
return Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into());
}
@ -326,7 +323,7 @@ fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> {
fn example_main() {
match create_pipeline().and_then(main_loop) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

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

@ -18,26 +18,23 @@
// (More modes of operation are possible, see: gst::TagMergeMode)
// This merge-mode can also be supplied to any method that adds new tags.
use gst::prelude::*;
use anyhow::anyhow;
use anyhow::Error;
use anyhow::{anyhow, Error};
use derive_more::{Display, Error};
use gst::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Missing element {}", _0)]
#[display(fmt = "Missing element {_0}")]
struct MissingElement(#[error(not(source))] String);
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
fn example_main() -> Result<(), Error> {
@ -45,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(),
@ -79,7 +76,8 @@ fn example_main() -> Result<(), Error> {
// Set the "title" tag to "Special randomized white-noise".
// The second parameter gst::TagMergeMode::Append tells the tagsetter to append this title
// if there already is one.
tagsetter.add::<gst::tags::Title>(&"Special randomized white-noise", gst::TagMergeMode::Append);
tagsetter
.add_tag::<gst::tags::Title>(&"Special randomized white-noise", gst::TagMergeMode::Append);
let bus = pipeline.bus().unwrap();
@ -92,14 +90,12 @@ fn example_main() -> Result<(), Error> {
MessageView::Eos(..) => break,
MessageView::Error(err) => {
return Err(ErrorMessage {
src: err
src: msg
.src()
.map(|s| s.path_string())
.unwrap_or_else(|| "None".into())
.to_string(),
error: err.error().to_string(),
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into());
}
@ -117,6 +113,6 @@ fn main() {
// (but not necessary in normal Cocoa applications where this is set up automatically)
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -7,31 +7,28 @@
// with the correct stride from GStreamer to the image crate as GStreamer does not necessarily
// produce tightly packed pixels, and in case of RGBx never.
use gst::element_error;
use gst::prelude::*;
use anyhow::Error;
use derive_more::{Display, Error};
use gst::{element_error, prelude::*};
use gst_video::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
fn create_pipeline(uri: String, out_path: std::path::PathBuf) -> Result<gst::Pipeline, Error> {
gst::init()?;
// Create our pipeline from a pipeline description string.
let pipeline = gst::parse_launch(&format!(
"uridecodebin uri={} ! videoconvert ! appsink name=sink",
uri
let pipeline = gst::parse::launch(&format!(
"uridecodebin uri={uri} ! videoconvert ! appsink name=sink"
))?
.downcast::<gst::Pipeline>()
.expect("Expected a gst::Pipeline");
@ -177,7 +174,7 @@ fn main_loop(pipeline: gst::Pipeline, position: u64) -> Result<(), Error> {
MessageView::AsyncDone(..) => {
if !seeked {
// AsyncDone means that the pipeline has started now and that we can seek
println!("Got AsyncDone message, seeking to {}s", position);
println!("Got AsyncDone message, seeking to {position}s");
if pipeline
.seek_simple(gst::SeekFlags::FLUSH, position * gst::ClockTime::SECOND)
@ -204,11 +201,10 @@ fn main_loop(pipeline: gst::Pipeline, position: u64) -> Result<(), Error> {
return Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into());
}
@ -244,7 +240,7 @@ fn example_main() {
match create_pipeline(uri, out_path).and_then(|pipeline| main_loop(pipeline, position)) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

View file

@ -9,10 +9,10 @@
// {filesrc} - {decodebin} - {queue} - {fakesink}
// \- ...
use gst::prelude::*;
use std::env;
use gst::prelude::*;
#[path = "../examples-common.rs"]
mod examples_common;
@ -34,8 +34,8 @@ fn example_main() {
.unwrap();
let decodebin = gst::ElementFactory::make("decodebin").build().unwrap();
pipeline.add_many(&[&src, &decodebin]).unwrap();
gst::Element::link_many(&[&src, &decodebin]).unwrap();
pipeline.add_many([&src, &decodebin]).unwrap();
gst::Element::link_many([&src, &decodebin]).unwrap();
// Need to move a new reference into the closure.
// !!ATTENTION!!:
@ -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
@ -109,7 +108,7 @@ fn example_main() {
println!("\nReceived toc: {:?} - updated: {}", toc.scope(), updated);
// Get a list of tags that are ToC specific.
if let Some(tags) = toc.tags() {
println!("- tags: {}", tags);
println!("- tags: {tags}");
}
// ToCs do not have a fixed structure. Depending on the format that
// they were parsed from, they might have different tree-like structures,
@ -124,11 +123,11 @@ fn example_main() {
println!("\t{:?} - {}", toc_entry.entry_type(), toc_entry.uid());
// Every ToC entry can have a set of timestamps (start, stop).
if let Some((start, stop)) = toc_entry.start_stop_times() {
println!("\t- start: {}, stop: {}", start, stop);
println!("\t- start: {start}, stop: {stop}");
}
// Every ToC entry can have tags to it.
if let Some(tags) = toc_entry.tags() {
println!("\t- tags: {}", tags);
println!("\t- tags: {tags}");
}
// Every ToC entry can have a set of child entries.
// With this structure, you can create trees of arbitrary depth.
@ -139,10 +138,10 @@ fn example_main() {
toc_sub_entry.uid()
);
if let Some((start, stop)) = toc_sub_entry.start_stop_times() {
println!("\t\t- start: {}, stop: {}", start, stop);
println!("\t\t- start: {start}, stop: {stop}");
}
if let Some(tags) = toc_sub_entry.tags() {
println!("\t\t- tags: {}", tags);
println!("\t\t- tags: {tags}");
}
}
}

View file

@ -17,24 +17,21 @@
// {src} - {typefind} - {demuxer} -| {multiqueue} - {matroskamux} - {filesink}
// \-[video]-/
use gst::element_error;
use gst::prelude::*;
use std::env;
use anyhow::Error;
use derive_more::{Display, Error};
use gst::{element_error, prelude::*};
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Display, Error)]
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
fn example_main() -> Result<(), Error> {
@ -69,7 +66,7 @@ fn example_main() -> Result<(), Error> {
// Increase the queue capacity to 100MB to avoid a stalling pipeline
pipeline
.add_many(&[&src, &typefinder, &queue, &muxer, &sink])
.add_many([&src, &typefinder, &queue, &muxer, &sink])
.expect("failed to add elements to pipeline");
src.link(&typefinder)?;
@ -89,7 +86,7 @@ fn example_main() -> Result<(), Error> {
.expect("typefinder \"have-type\" signal values[2]");
let format_name = caps.structure(0).expect("Failed to get format name").name();
let demuxer = match format_name {
let demuxer = match format_name.as_str() {
"video/x-matroska" | "video/webm" => gst::ElementFactory::make("matroskademux")
.build()
.expect("matroskademux missing"),
@ -142,11 +139,10 @@ fn example_main() -> Result<(), Error> {
return Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into());
}
@ -216,6 +212,6 @@ fn main() {
// (but not necessary in normal Cocoa applications where this is set up automatically)
match examples_common::run(example_main) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
Err(e) => eprintln!("Error! {e}"),
}
}

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",
)

229
examples/src/bin/zoom.rs Normal file
View file

@ -0,0 +1,229 @@
// Zoom example using navigation events and a compositor
// Use can change the video player zoom using the next keys:
// * +: Zoom in
// * -: Zoom out
// * Up/Down/Right/Left: Move the frame
// * r: reset the zoom
// Also mouse navigation events can be used for a better UX.
use gst::prelude::*;
use gst_video::video_event::NavigationEvent;
use std::sync::Mutex;
#[path = "../examples-common.rs"]
mod examples_common;
const WIDTH: i32 = 1280;
const HEIGHT: i32 = 720;
#[derive(Default)]
struct MouseState {
clicked: bool,
clicked_x: f64,
clicked_y: f64,
clicked_xpos: i32,
clicked_ypos: i32,
}
fn zoom(mixer_sink_pad: gst::Pad, x: i32, y: i32, zoom_in: bool) {
let xpos = mixer_sink_pad.property::<i32>("xpos");
let ypos = mixer_sink_pad.property::<i32>("ypos");
let width = mixer_sink_pad.property::<i32>("width");
let height = mixer_sink_pad.property::<i32>("height");
let (width_offset, height_offset) = if zoom_in {
(WIDTH / 10, HEIGHT / 10)
} else {
(-WIDTH / 10, -HEIGHT / 10)
};
if width_offset + width <= 0 {
return;
}
mixer_sink_pad.set_property("width", width + width_offset);
mixer_sink_pad.set_property("height", height + height_offset);
let xpos_offset = ((x as f32 / WIDTH as f32) * width_offset as f32) as i32;
let new_xpos = xpos - xpos_offset;
let ypos_offset = ((y as f32 / HEIGHT as f32) * height_offset as f32) as i32;
let new_ypos = ypos - ypos_offset;
if new_xpos != xpos {
mixer_sink_pad.set_property("xpos", new_xpos);
}
if new_ypos != ypos {
mixer_sink_pad.set_property("ypos", new_ypos);
}
}
fn reset_zoom(mixer_sink_pad: gst::Pad) {
let xpos = mixer_sink_pad.property::<i32>("xpos");
let ypos = mixer_sink_pad.property::<i32>("ypos");
let width = mixer_sink_pad.property::<i32>("width");
let height = mixer_sink_pad.property::<i32>("height");
if 0 != xpos {
mixer_sink_pad.set_property("xpos", 0);
}
if 0 != ypos {
mixer_sink_pad.set_property("ypos", 0);
}
if WIDTH != width {
mixer_sink_pad.set_property("width", WIDTH);
}
if HEIGHT != height {
mixer_sink_pad.set_property("height", HEIGHT);
}
}
fn example_main() {
let clicked = Mutex::new(MouseState::default());
gst::init().unwrap();
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();
let mixer = pipeline.by_name("mix").unwrap();
let mixer_src_pad = mixer.static_pad("src").unwrap();
let mixer_sink_pad_weak = mixer.static_pad("sink_0").unwrap().downgrade();
// Probe added in the sink pad to get direct navigation events w/o transformation done by the mixer
mixer_src_pad.add_probe(gst::PadProbeType::EVENT_UPSTREAM, move |_, probe_info| {
let mixer_sink_pad = mixer_sink_pad_weak.upgrade().unwrap();
let Some(ev) = probe_info.event() else {
return gst::PadProbeReturn::Ok;
};
if ev.type_() != gst::EventType::Navigation {
return gst::PadProbeReturn::Ok;
};
let Ok(nav_event) = NavigationEvent::parse(ev) else {
return gst::PadProbeReturn::Ok;
};
match nav_event {
NavigationEvent::KeyPress { key, .. } => match key.as_str() {
"Left" => {
let xpos = mixer_sink_pad.property::<i32>("xpos");
mixer_sink_pad.set_property("xpos", xpos - 10);
}
"Right" => {
let xpos = mixer_sink_pad.property::<i32>("xpos");
mixer_sink_pad.set_property("xpos", xpos + 10);
}
"Up" => {
let ypos = mixer_sink_pad.property::<i32>("ypos");
mixer_sink_pad.set_property("ypos", ypos - 10);
}
"Down" => {
let ypos = mixer_sink_pad.property::<i32>("ypos");
mixer_sink_pad.set_property("ypos", ypos + 10);
}
"plus" => {
zoom(mixer_sink_pad, WIDTH / 2, HEIGHT / 2, true);
}
"minus" => {
zoom(mixer_sink_pad, WIDTH / 2, HEIGHT / 2, false);
}
"r" => {
reset_zoom(mixer_sink_pad);
}
_ => (),
},
NavigationEvent::MouseMove { x, y, .. } => {
let state = clicked.lock().unwrap();
if state.clicked {
let xpos = mixer_sink_pad.property::<i32>("xpos");
let ypos = mixer_sink_pad.property::<i32>("ypos");
let new_xpos = state.clicked_xpos + (x - state.clicked_x) as i32;
let new_ypos = state.clicked_ypos + (y - state.clicked_y) as i32;
if new_xpos != xpos {
mixer_sink_pad.set_property("xpos", new_xpos);
}
if new_ypos != ypos {
mixer_sink_pad.set_property("ypos", new_ypos);
}
}
}
NavigationEvent::MouseButtonPress { button, x, y, .. } => {
if button == 1 || button == 272 {
let mut state = clicked.lock().unwrap();
state.clicked = true;
state.clicked_x = x;
state.clicked_y = y;
state.clicked_xpos = mixer_sink_pad.property("xpos");
state.clicked_ypos = mixer_sink_pad.property("ypos");
} else if button == 2 || button == 3 || button == 274 || button == 273 {
reset_zoom(mixer_sink_pad);
} else if button == 4 {
zoom(mixer_sink_pad, x as i32, y as i32, true);
} else if button == 5 {
zoom(mixer_sink_pad, x as i32, y as i32, false);
}
}
NavigationEvent::MouseButtonRelease { button, .. } => {
if button == 1 || button == 272 {
let mut state = clicked.lock().unwrap();
state.clicked = false;
}
}
#[cfg(feature = "v1_18")]
NavigationEvent::MouseScroll { x, y, delta_y, .. } => {
if delta_y > 0.0 {
zoom(mixer_sink_pad, x as i32, y as i32, true);
} else if delta_y < 0.0 {
zoom(mixer_sink_pad, x as i32, y as i32, false);
}
}
_ => (),
}
gst::PadProbeReturn::Ok
});
pipeline
.set_state(gst::State::Playing)
.expect("Unable to set the pipeline to the `Playing` state");
let bus = pipeline.bus().unwrap();
for msg in bus.iter_timed(gst::ClockTime::NONE) {
use gst::MessageView;
match msg.view() {
MessageView::Eos(..) => {
println!("received 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

@ -17,13 +17,47 @@ pub fn run<T, F: FnOnce() -> T + Send + 'static>(main: F) -> T
where
T: Send + 'static,
{
use cocoa::appkit::NSApplication;
use std::{
ffi::c_void,
sync::mpsc::{channel, Sender},
thread,
};
use std::thread;
use cocoa::{
appkit::{NSApplication, NSWindow},
base::id,
delegate,
};
use objc::{
class, msg_send,
runtime::{Object, Sel},
sel, sel_impl,
};
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,28 +1,37 @@
// 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 gst::element_error;
use std::{
ffi::{CStr, CString},
mem,
num::NonZeroU32,
ptr,
};
use gst_gl::prelude::*;
use std::ffi::CStr;
use std::mem;
use std::ptr;
use std::sync;
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 {}: {} (debug: {:?})", src, error, debug)]
#[display(fmt = "Received error from {src}: {error} (debug: {debug:?})")]
struct ErrorMessage {
src: String,
error: String,
debug: Option<String>,
source: glib::Error,
src: glib::GString,
error: glib::Error,
debug: Option<glib::GString>,
}
#[rustfmt::skip]
@ -177,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);
@ -185,17 +194,20 @@ 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);
println!("OpenGL version {version}");
let (program, attr_position, attr_texture, vao, vertex_buffer, vbo_indices) = unsafe {
let vs = gl.CreateShader(gl::VERTEX_SHADER);
@ -212,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 _);
@ -285,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,
@ -308,198 +323,256 @@ fn load(gl_context: &glutin::WindowedContext<glutin::PossiblyCurrent>) -> Gl {
#[derive(Debug)]
enum Message {
Sample(gst::Sample),
Frame(gst_video::VideoInfo, gst::Buffer),
BusEvent,
}
pub(crate) struct App {
pipeline: gst::Pipeline,
appsink: gst_app::AppSink,
glupload: gst::Element,
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, glupload) = App::create_pipeline(gl_element)?;
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") {
use glutin::platform::unix::RawHandle;
#[cfg(any(feature = "gst-gl-x11", feature = "gst-gl-wayland"))]
use glutin::platform::unix::WindowExtUnix;
use glutin::platform::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::<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::<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,
glupload,
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()
.new_sample(move |appsink| {
let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Eos)?;
{
let _buffer = sample.buffer().ok_or_else(|| {
let info = sample
.caps()
.and_then(|caps| gst_video::VideoInfo::from_caps(caps).ok())
.ok_or_else(|| {
element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to get buffer from appsink")
("Failed to get video info from sample")
);
gst::FlowError::Error
gst::FlowError::NotNegotiated
})?;
let _info = sample
.caps()
.and_then(|caps| gst_video::VideoInfo::from_caps(caps).ok())
.ok_or_else(|| {
let mut buffer = sample.buffer_owned().unwrap();
{
let context = match (buffer.n_memory() > 0)
.then(|| buffer.peek_memory(0))
.and_then(|m| m.downcast_memory_ref::<gst_gl::GLBaseMemory>())
.map(|m| m.context())
{
Some(context) => context.clone(),
None => {
element_error!(
appsink,
gst::ResourceError::Failed,
("Failed to get video info from sample")
("Failed to get GL context from buffer")
);
gst::FlowError::Error
})?;
return Err(gst::FlowError::Error);
}
};
if let Some(meta) = buffer.meta::<gst_gl::GLSyncMeta>() {
meta.set_sync_point(&context);
} else {
let buffer = buffer.make_mut();
let meta = gst_gl::GLSyncMeta::add(buffer, &context);
meta.set_sync_point(&context);
}
}
event_proxy
.send_event(Message::Sample(sample))
.send_event(Message::Frame(info, buffer))
.map(|()| gst::FlowSuccess::Ok)
.map_err(|e| {
element_error!(
@ -514,27 +587,38 @@ 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, gst::Element), Error> {
) -> Result<(gst::Pipeline, gst_app::AppSink)> {
let pipeline = gst::Pipeline::default();
let src = gst::ElementFactory::make("videotestsrc").build()?;
let caps = gst_video::VideoCapsBuilder::new()
.features(&[&gst_gl::CAPS_FEATURE_MEMORY_GL_MEMORY])
.features([gst_gl::CAPS_FEATURE_MEMORY_GL_MEMORY])
.format(gst_video::VideoFormat::Rgba)
.field("texture-target", "2D")
.build();
@ -548,7 +632,7 @@ impl App {
if let Some(gl_element) = gl_element {
let glupload = gst::ElementFactory::make("glupload").build()?;
pipeline.add_many(&[&src, &glupload])?;
pipeline.add_many([&src, &glupload])?;
pipeline.add(gl_element)?;
pipeline.add(&appsink)?;
@ -556,34 +640,20 @@ impl App {
glupload.link(gl_element)?;
gl_element.link(&appsink)?;
Ok((pipeline, appsink, glupload))
Ok((pipeline, appsink))
} else {
let sink = gst::ElementFactory::make("glsinkbin")
.property("sink", &appsink)
.build()?;
pipeline.add_many(&[&src, &sink])?;
pipeline.add_many([&src, &sink])?;
src.link(&sink)?;
// get the glupload element to extract later the used context in it
let mut iter = sink.dynamic_cast::<gst::Bin>().unwrap().iterate_elements();
let glupload = loop {
match iter.next() {
Ok(Some(element)) => {
if "glupload" == element.factory().unwrap().name() {
break Some(element);
}
}
Err(gst::IteratorError::Resync) => iter.resync(),
_ => break None,
}
};
Ok((pipeline, appsink, glupload.unwrap()))
Ok((pipeline, appsink))
}
}
fn handle_messages(bus: &gst::Bus) -> Result<(), Error> {
fn handle_messages(bus: &gst::Bus) -> Result<()> {
use gst::MessageView;
for msg in bus.iter() {
@ -593,11 +663,10 @@ impl App {
return Err(ErrorMessage {
src: msg
.src()
.map(|s| String::from(s.path_string()))
.unwrap_or_else(|| String::from("None")),
error: err.error().to_string(),
.map(|s| s.path_string())
.unwrap_or_else(|| glib::GString::from("UNKNOWN")),
error: err.error(),
debug: err.debug(),
source: err.error(),
}
.into());
}
@ -609,94 +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 mut gst_gl_context: Option<gst_gl::GLContext> = None;
let App {
pipeline,
bus,
event_loop,
glupload,
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::Sample(sample)) => {
let buffer = sample.buffer_owned().unwrap();
let info = sample
.caps()
.and_then(|caps| gst_video::VideoInfo::from_caps(caps).ok())
.unwrap();
{
if gst_gl_context.is_none() {
gst_gl_context = glupload.property::<Option<gst_gl::GLContext>>("context");
}
let sync_meta = buffer.meta::<gst_gl::GLSyncMeta>().unwrap();
sync_meta.set_sync_point(gst_gl_context.as_ref().unwrap());
}
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 952ff416b5997f50b9261c62c7589100e35a1459
Subproject commit 5223ce91b97a833b09d6cbd04bbeab1bf18112b7

@ -1 +1 @@
Subproject commit 89a11aa6a36287af891f61f499cefa122be5d3a2
Subproject commit 6cd7b656acd61172ab7f125a7059e4d0ecfc9637

@ -1 +1 @@
Subproject commit 15396abcca88607bc1c5e14b97a9cf925d23492c
Subproject commit c988e03b5e99349efb8ffb6f502879ad4ddbc248

View file

@ -1,25 +1,24 @@
[package]
name = "gstreamer-allocators"
version = "0.19.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.63"
version.workspace = true
categories.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
rust-version.workspace = true
[dependencies]
libc = "0.2"
bitflags = "1.0"
ffi = { package = "gstreamer-allocators-sys", path = "sys" }
glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
gst = { package = "gstreamer", path = "../gstreamer" }
once_cell = "1.0"
glib.workspace = true
gst.workspace = true
once_cell = "1"
[dev-dependencies]
gir-format-check = "0.1"
@ -30,7 +29,10 @@ v1_16 = ["gst/v1_16", "ffi/v1_16"]
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"]
dox = ["ffi/dox", "glib/dox", "gst/dox"]
v1_24 = ["gst/v1_24", "ffi/v1_24", "v1_22"]
v1_26 = ["gst/v1_26", "ffi/v1_26", "v1_24"]
[package.metadata.docs.rs]
features = ["dox"]
all-features = true
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"]

View file

@ -52,6 +52,15 @@ status = "generate"
[[object.function]]
name = "phys_memory_get_phys_addr"
manual = true
[[object.function]]
name = "is_drm_dumb_memory"
manual = true
[[object.function]]
name = "drm_dumb_memory_get_handle"
manual = true
[[object.function]]
name = "drm_dumb_memory_export_dmabuf"
manual = true
[[object]]
name = "GstAllocators.DmaBufAllocator"
@ -64,9 +73,36 @@ cfg_condition = "target_os = \"linux\""
name = "alloc_with_flags"
manual = true
[[object]]
name = "GstAllocators.DRMDumbAllocator"
status = "generate"
cfg_condition = "target_os = \"linux\""
[[object.function]]
name = "alloc"
manual = true
[[object.function]]
name = "new_with_fd"
manual = true
[[object.function]]
name = "new_with_device_path"
[object.function.return]
nullable_return_is_error = "Failed to create allocator"
[[object]]
name = "GstAllocators.FdAllocator"
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

@ -66,6 +66,26 @@ 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
@ -81,19 +101,6 @@ $ brew install gstreamer gst-plugins-base gst-plugins-good \
Make sure the version of these libraries is >= 1.14.
#### GStreamer Binaries
You need to download the *two* `.pkg` files from the GStreamer website and
install them, e.g. `gstreamer-1.0-1.14.0-x86_64.pkg` and
`gstreamer-1.0-devel-1.14.0-x86_64.pkg`.
After installation, you also need to install `pkg-config` (e.g. via Homebrew)
and set the `PKG_CONFIG_PATH` environment variable
```console
$ export PKG_CONFIG_PATH="/Library/Frameworks/GStreamer.framework/Versions/1.0/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
```
<a name="installation-windows"/>
### Windows
@ -103,6 +110,32 @@ 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
@ -120,20 +153,6 @@ Note that the version of `pkg-config` included in `MSYS2` is
compiling GStreamer, so you may need to install another version. One option
would be [`pkg-config-lite`](https://sourceforge.net/projects/pkgconfiglite/).
#### 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.14.0.msi` and
`gstreamer-1.0-devel-x86_64-1.14.0.msi`.
After installation, you also need to install `pkg-config` (e.g. via MSYS2 or
from [here](https://sourceforge.net/projects/pkgconfiglite/))
and set the `PKG_CONFIG_PATH` environment variable
```console
$ export PKG_CONFIG_PATH="c:\\gstreamer\\1.0\\x86_64\\lib\\pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
```
<a name="getting-started"/>
## Getting Started

View file

@ -3,22 +3,19 @@
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT
use std::ffi::CStr;
use glib::GStr;
#[doc(alias = "GST_ALLOCATOR_DMABUF")]
pub static ALLOCATOR_DMABUF: once_cell::sync::Lazy<&'static str> =
once_cell::sync::Lazy::new(|| unsafe {
CStr::from_ptr(ffi::GST_ALLOCATOR_DMABUF).to_str().unwrap()
});
pub static ALLOCATOR_DMABUF: &GStr =
unsafe { GStr::from_utf8_with_nul_unchecked(ffi::GST_ALLOCATOR_DMABUF) };
#[doc(alias = "GST_ALLOCATOR_FD")]
pub static ALLOCATOR_FD: once_cell::sync::Lazy<&'static str> =
once_cell::sync::Lazy::new(|| unsafe {
CStr::from_ptr(ffi::GST_ALLOCATOR_FD).to_str().unwrap()
});
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: once_cell::sync::Lazy<&'static str> =
once_cell::sync::Lazy::new(|| unsafe {
CStr::from_ptr(ffi::GST_CAPS_FEATURE_MEMORY_DMABUF)
.to_str()
.unwrap()
});
pub static CAPS_FEATURE_MEMORY_DMABUF: &GStr =
unsafe { GStr::from_utf8_with_nul_unchecked(ffi::GST_CAPS_FEATURE_MEMORY_DMABUF) };

View file

@ -4,8 +4,7 @@
// DO NOT EDIT
use crate::FdAllocator;
use glib::object::Cast;
use glib::translate::*;
use glib::{prelude::*, translate::*};
glib::wrapper! {
#[doc(alias = "GstDmaBufAllocator")]

View file

@ -0,0 +1,60 @@
// 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::{prelude::*, translate::*};
glib::wrapper! {
#[doc(alias = "GstDRMDumbAllocator")]
pub struct DRMDumbAllocator(Object<ffi::GstDRMDumbAllocator, ffi::GstDRMDumbAllocatorClass>) @extends gst::Allocator;
match fn {
type_ => || ffi::gst_drm_dumb_allocator_get_type(),
}
}
impl DRMDumbAllocator {
#[doc(alias = "gst_drm_dumb_allocator_new_with_device_path")]
#[doc(alias = "new_with_device_path")]
pub fn with_device_path(
drm_device_path: impl AsRef<std::path::Path>,
) -> Result<DRMDumbAllocator, glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
Option::<gst::Allocator>::from_glib_full(
ffi::gst_drm_dumb_allocator_new_with_device_path(
drm_device_path.as_ref().to_glib_none().0,
),
)
.map(|o| o.unsafe_cast())
.ok_or_else(|| glib::bool_error!("Failed to create allocator"))
}
}
#[doc(alias = "gst_drm_dumb_allocator_has_prime_export")]
pub fn has_prime_export(&self) -> bool {
unsafe {
from_glib(ffi::gst_drm_dumb_allocator_has_prime_export(
self.to_glib_none().0,
))
}
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[doc(alias = "drm-device-path")]
pub fn drm_device_path(&self) -> Option<std::path::PathBuf> {
ObjectExt::property(self, "drm-device-path")
}
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
#[doc(alias = "drm-fd")]
pub fn drm_fd(&self) -> i32 {
ObjectExt::property(self, "drm-fd")
}
}
unsafe impl Send for DRMDumbAllocator {}
unsafe impl Sync for DRMDumbAllocator {}

View file

@ -3,8 +3,7 @@
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT
use glib::object::Cast;
use glib::translate::*;
use glib::{prelude::*, translate::*};
glib::wrapper! {
#[doc(alias = "GstFdAllocator")]

View file

@ -3,20 +3,20 @@
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT
use bitflags::bitflags;
use glib::translate::*;
use glib::{bitflags::bitflags, translate::*};
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[doc(alias = "GstFdMemoryFlags")]
pub struct FdMemoryFlags: u32 {
#[doc(alias = "GST_FD_MEMORY_FLAG_NONE")]
const NONE = ffi::GST_FD_MEMORY_FLAG_NONE as u32;
const NONE = ffi::GST_FD_MEMORY_FLAG_NONE as _;
#[doc(alias = "GST_FD_MEMORY_FLAG_KEEP_MAPPED")]
const KEEP_MAPPED = ffi::GST_FD_MEMORY_FLAG_KEEP_MAPPED as u32;
const KEEP_MAPPED = ffi::GST_FD_MEMORY_FLAG_KEEP_MAPPED as _;
#[doc(alias = "GST_FD_MEMORY_FLAG_MAP_PRIVATE")]
const MAP_PRIVATE = ffi::GST_FD_MEMORY_FLAG_MAP_PRIVATE as u32;
const MAP_PRIVATE = ffi::GST_FD_MEMORY_FLAG_MAP_PRIVATE as _;
#[doc(alias = "GST_FD_MEMORY_FLAG_DONT_CLOSE")]
const DONT_CLOSE = ffi::GST_FD_MEMORY_FLAG_DONT_CLOSE as u32;
const DONT_CLOSE = ffi::GST_FD_MEMORY_FLAG_DONT_CLOSE as _;
}
}
@ -24,6 +24,7 @@ bitflags! {
impl IntoGlib for FdMemoryFlags {
type GlibType = ffi::GstFdMemoryFlags;
#[inline]
fn into_glib(self) -> ffi::GstFdMemoryFlags {
self.bits()
}
@ -31,6 +32,7 @@ impl IntoGlib for FdMemoryFlags {
#[doc(hidden)]
impl FromGlib<ffi::GstFdMemoryFlags> for FdMemoryFlags {
#[inline]
unsafe fn from_glib(value: ffi::GstFdMemoryFlags) -> Self {
skip_assert_initialized!();
Self::from_bits_truncate(value)

View file

@ -3,11 +3,22 @@
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT
#[cfg(any(target_os = "linux", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(target_os = "linux")))]
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
mod drm_dumb_allocator;
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
#[cfg(feature = "v1_24")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
pub use self::drm_dumb_allocator::DRMDumbAllocator;
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
mod dma_buf_allocator;
#[cfg(any(target_os = "linux", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(target_os = "linux")))]
#[cfg(target_os = "linux")]
#[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
pub use self::dma_buf_allocator::DmaBufAllocator;
mod fd_allocator;
@ -16,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

@ -3,7 +3,7 @@
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT
use glib::object::IsA;
use glib::prelude::*;
glib::wrapper! {
#[doc(alias = "GstPhysMemoryAllocator")]
@ -21,6 +21,11 @@ impl PhysMemoryAllocator {
unsafe impl Send for PhysMemoryAllocator {}
unsafe impl Sync for PhysMemoryAllocator {}
pub trait PhysMemoryAllocatorExt: 'static {}
mod sealed {
pub trait Sealed {}
impl<T: super::IsA<super::PhysMemoryAllocator>> Sealed for T {}
}
pub trait PhysMemoryAllocatorExt: IsA<PhysMemoryAllocator> + sealed::Sealed + 'static {}
impl<O: IsA<PhysMemoryAllocator>> PhysMemoryAllocatorExt for O {}

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 @ 952ff416b599)
from gir-files (https://github.com/gtk-rs/gir-files @ 89a11aa6a362)
from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 15396abcca88)
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,8 +1,7 @@
// Take a look at the license at the top of the repository in the LICENSE file.
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]));
Lazy::new(|| CapsFeatures::new([crate::CAPS_FEATURE_MEMORY_DMABUF]));

View file

@ -3,12 +3,11 @@ use std::{
os::unix::prelude::{IntoRawFd, RawFd},
};
use glib::{translate::*, Cast};
use glib::{prelude::*, translate::*};
use gst::{Memory, MemoryRef};
#[cfg(any(feature = "v1_16", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_16")))]
#[cfg(feature = "v1_16")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
use crate::FdMemoryFlags;
use crate::{DmaBufAllocator, FdMemory, FdMemoryRef};
@ -38,7 +37,7 @@ impl fmt::Debug for DmaBufMemoryRef {
impl DmaBufMemoryRef {
#[doc(alias = "gst_dmabuf_memory_get_fd")]
pub fn fd(&self) -> RawFd {
assert_initialized_main_thread!();
skip_assert_initialized!();
unsafe { ffi::gst_dmabuf_memory_get_fd(self.as_mut_ptr()) }
}
}
@ -50,7 +49,7 @@ impl DmaBufAllocator {
fd: A,
size: usize,
) -> Result<gst::Memory, glib::BoolError> {
assert_initialized_main_thread!();
skip_assert_initialized!();
Option::<_>::from_glib_full(ffi::gst_dmabuf_allocator_alloc(
self.unsafe_cast_ref::<gst::Allocator>().to_glib_none().0,
fd.into_raw_fd(),
@ -59,8 +58,8 @@ impl DmaBufAllocator {
.ok_or_else(|| glib::bool_error!("Failed to allocate memory"))
}
#[cfg(any(feature = "v1_16", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_16")))]
#[cfg(feature = "v1_16")]
#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
#[doc(alias = "gst_dmabuf_allocator_alloc_with_flags")]
pub unsafe fn alloc_with_flags(
&self,
@ -68,7 +67,7 @@ impl DmaBufAllocator {
size: usize,
flags: FdMemoryFlags,
) -> Result<gst::Memory, glib::BoolError> {
assert_initialized_main_thread!();
skip_assert_initialized!();
Option::<_>::from_glib_full(ffi::gst_dmabuf_allocator_alloc_with_flags(
self.unsafe_cast_ref::<gst::Allocator>().to_glib_none().0,
fd,

View file

@ -0,0 +1,81 @@
use std::{fmt, mem, os::unix::prelude::IntoRawFd};
use glib::{prelude::*, translate::*};
use gst::{Memory, MemoryRef};
use crate::{DRMDumbAllocator, DmaBufMemory};
gst::memory_object_wrapper!(
DRMDumbMemory,
DRMDumbMemoryRef,
gst::ffi::GstMemory,
|mem: &gst::MemoryRef| { unsafe { from_glib(ffi::gst_is_drm_dumb_memory(mem.as_mut_ptr())) } },
Memory,
MemoryRef
);
impl fmt::Debug for DRMDumbMemory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
DRMDumbMemoryRef::fmt(self, f)
}
}
impl fmt::Debug for DRMDumbMemoryRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
MemoryRef::fmt(self, f)
}
}
impl DRMDumbMemoryRef {
#[doc(alias = "gst_drm_dumb_memory_get_handle")]
pub fn fd(&self) -> u32 {
skip_assert_initialized!();
unsafe { ffi::gst_drm_dumb_memory_get_handle(self.as_mut_ptr()) }
}
#[doc(alias = "gst_drm_dumb_memory_export_dmabuf")]
pub fn export_dmabuf(&self) -> Result<DmaBufMemory, glib::BoolError> {
skip_assert_initialized!();
unsafe {
Option::<DmaBufMemory>::from_glib_full(ffi::gst_drm_dumb_memory_export_dmabuf(
self.as_mut_ptr(),
))
.ok_or_else(|| glib::bool_error!("Failed to export as dmabuf"))
}
}
}
impl DRMDumbAllocator {
#[doc(alias = "gst_drm_dumb_allocator_new_with_fd")]
#[doc(alias = "new_with_fd")]
pub fn with_fd<A: IntoRawFd>(drm_fd: A) -> Result<DRMDumbAllocator, glib::BoolError> {
assert_initialized_main_thread!();
unsafe {
Option::<gst::Allocator>::from_glib_full(ffi::gst_drm_dumb_allocator_new_with_fd(
drm_fd.into_raw_fd(),
))
.map(|o| o.unsafe_cast())
.ok_or_else(|| glib::bool_error!("Failed to create allocator"))
}
}
#[doc(alias = "gst_drm_dumb_allocator_alloc")]
pub unsafe fn alloc(
&self,
drm_fourcc: u32,
width: u32,
height: u32,
) -> Result<(gst::Memory, u32), glib::BoolError> {
skip_assert_initialized!();
let mut out_pitch = mem::MaybeUninit::uninit();
Option::<_>::from_glib_full(ffi::gst_drm_dumb_allocator_alloc(
self.to_glib_none().0,
drm_fourcc,
width,
height,
out_pitch.as_mut_ptr(),
))
.ok_or_else(|| glib::bool_error!("Failed to allocate memory"))
.map(|mem| (mem, unsafe { out_pitch.assume_init() }))
}
}

View file

@ -1,7 +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};
@ -40,7 +39,7 @@ impl fmt::Debug for FdMemoryRef {
impl FdMemoryRef {
#[doc(alias = "gst_fd_memory_get_fd")]
pub fn fd(&self) -> RawFd {
assert_initialized_main_thread!();
skip_assert_initialized!();
unsafe { ffi::gst_fd_memory_get_fd(self.as_mut_ptr()) }
}
}
@ -53,7 +52,7 @@ impl FdAllocator {
size: usize,
flags: FdMemoryFlags,
) -> Result<gst::Memory, glib::BoolError> {
assert_initialized_main_thread!();
skip_assert_initialized!();
Option::<_>::from_glib_full(ffi::gst_fd_allocator_alloc(
self.unsafe_cast_ref::<gst::Allocator>().to_glib_none().0,
fd,

View file

@ -1,8 +1,7 @@
// Take a look at the license at the top of the repository in the LICENSE file.
#![cfg_attr(feature = "dox", feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::non_send_fields_in_send_ty)]
#![doc = include_str!("../README.md")]
pub use ffi;
@ -12,12 +11,7 @@ pub use gst;
macro_rules! assert_initialized_main_thread {
() => {
if !gst::INITIALIZED.load(std::sync::atomic::Ordering::SeqCst) {
#[allow(unused_unsafe)]
if unsafe { gst::ffi::gst_is_initialized() } != glib::ffi::GTRUE {
panic!("GStreamer has not been initialized. Call `gst::init` first.");
} else {
gst::INITIALIZED.store(true, std::sync::atomic::Ordering::SeqCst);
}
gst::assert_initialized();
}
};
}
@ -26,11 +20,6 @@ macro_rules! skip_assert_initialized {
() => {};
}
#[allow(clippy::unreadable_literal)]
#[allow(clippy::too_many_arguments)]
#[allow(clippy::match_same_arms)]
#[allow(clippy::type_complexity)]
#[allow(clippy::use_self)]
#[allow(unused_imports)]
mod auto;
pub use crate::auto::*;
@ -41,13 +30,24 @@ pub use crate::caps_features::CAPS_FEATURES_MEMORY_DMABUF;
mod fd_allocator;
pub use fd_allocator::*;
#[cfg(any(target_os = "linux", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(target_os = "linux")))]
#[cfg(any(target_os = "linux", docsrs))]
#[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
mod dma_buf_allocator;
#[cfg(any(target_os = "linux", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(target_os = "linux")))]
#[cfg(any(target_os = "linux", docsrs))]
#[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
pub use dma_buf_allocator::*;
#[cfg(any(all(feature = "v1_24", target_os = "linux"), docsrs))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "v1_24", target_os = "linux"))))]
mod drm_dumb_allocator;
#[cfg(any(all(feature = "v1_24", target_os = "linux"), docsrs))]
#[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::*;
@ -56,4 +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

@ -1,7 +1,6 @@
use std::fmt;
use glib::translate::*;
use gst::{Memory, MemoryRef};
gst::memory_object_wrapper!(
@ -38,7 +37,7 @@ impl fmt::Debug for PhysMemoryRef {
impl PhysMemoryRef {
#[doc(alias = "gst_phys_memory_get_phys_addr")]
pub fn phys_addr(&self) -> libc::uintptr_t {
assert_initialized_main_thread!();
skip_assert_initialized!();
unsafe { ffi::gst_phys_memory_get_phys_addr(self.as_mut_ptr()) }
}
}

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

@ -0,0 +1,6 @@
use glib::subclass::prelude::*;
use crate::{subclass::fd_allocator::FdAllocatorImpl, DmaBufAllocator};
pub trait DmaBufAllocatorImpl: FdAllocatorImpl {}
unsafe impl<T: DmaBufAllocatorImpl> IsSubclassable<T> for DmaBufAllocator {}

View file

@ -0,0 +1,7 @@
use glib::subclass::prelude::*;
use crate::FdAllocator;
use gst::subclass::prelude::AllocatorImpl;
pub trait FdAllocatorImpl: AllocatorImpl {}
unsafe impl<T: FdAllocatorImpl> IsSubclassable<T> for FdAllocator {}

View file

@ -0,0 +1,14 @@
#[cfg(any(target_os = "linux", docsrs))]
#[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
mod dma_buf_allocator;
mod fd_allocator;
pub mod prelude {
#[doc(hidden)]
pub use gst::subclass::prelude::*;
#[cfg(any(target_os = "linux", docsrs))]
#[cfg_attr(docsrs, doc(cfg(target_os = "linux")))]
pub use super::dma_buf_allocator::DmaBufAllocatorImpl;
pub use super::fd_allocator::FdAllocatorImpl;
}

View file

@ -4,28 +4,26 @@ 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"
tempfile = "3"
[features]
dox = ["glib/dox", "gobject/dox", "gst/dox"]
v1_16 = []
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,17 +33,34 @@ 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.63"
version = "0.19.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]
features = ["dox"]
all-features = true
rustc-args = ["--cfg", "docsrs"]
rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"]
[package.metadata.system-deps.gstreamer_allocators_1_0]
name = "gstreamer-allocators-1.0"
version = "1.14"
@ -60,4 +75,10 @@ version = "1.18"
version = "1.20"
[package.metadata.system-deps.gstreamer_allocators_1_0.v1_22]
version = "1.21"
version = "1.22"
[package.metadata.system-deps.gstreamer_allocators_1_0.v1_24]
version = "1.24"
[package.metadata.system-deps.gstreamer_allocators_1_0.v1_26]
version = "1.25"

View file

@ -7,6 +7,8 @@ work_mode = "sys"
single_version_file = true
extra_versions = [
"1.24",
"1.22",
"1.20",
"1.18",
"1.16",

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