gstreamer-0.23.5/.cargo_vcs_info.json0000644000000001470000000000100131160ustar { "git": { "sha1": "8eb8ab921bc627f854bac4e457521e7312403d0a" }, "path_in_vcs": "gstreamer" }gstreamer-0.23.5/CHANGELOG.md000064400000000000000000002533741046102023000135330ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html), specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field). ## [0.23.5] - 2025-02-17 ### Fixed - Properly validate `gst::IntRange::with_step()` step size - Fix `gst::Buffer` serde serialization - Forward gap events by default in `gst_utils::StreamProducer`. - Correctly account for alternate interlace mode in `gst_video::VideoMeta::add_full()`. - Return `Result`s instead of `bool`s in new `gst_play` API. ### Added - Support for `TracerImpl::USE_STRUCTURE_PARAMS` with GStreamer < 1.26. - Bindings for `gst_analytics::ODMtd`. - Bindings for `TopSurroundRight` and `TopSurroundLeft` audio channels. - Bindings for AV1 and H266 codec helpers API. - Bindings for `gst_audio::reorder_channels_with_reorder_map()`. ### Changed - Updated GStreamer gir files for latest 1.26 APIs. - Documentation links URL was updated. ## [0.23.4] - 2024-12-21 ### Fixed - `gst_video::VideoFrame::plane_data()` does not return a truncated buffer for the alpha plane in A420 and similar formats anymore. - `FnMut` closures are now correctly passed via a mutable reference to FFI code. - Order of arguments in `gst_video::VideoFormat::from_mask()` was corrected. ### Added - Bindings for 1.26 `gst_analytics::Tensor` API. - `gst::DebugCategory::as_ptr()` and `Hash` impl, `gst::DebugMessage::as_ptr()`. - Support for hex-dumping `&mut [u8]` in addition to `&[u8]`, `gst::Buffer`, etc. - Functions to work with meta `glib::Type`s. ### Changed - Updated GStreamer gir files for latest 1.26 APIs. ## [0.23.3] - 2024-11-01 ### Fixed - Bind `gst::Pad::proxy_query_caps()` to the correct C function. - Update `gst_utils::StreamProducer` appsrc latency upon appsink latency event. - Fix type of `gst_app::AppSinkBuilder::processing_deadline()`. ### Added - Various new `gst::Iterator` constructors for convenience. ### Changed - Updated GStreamer gir files for latest 1.26 APIs. ## [0.23.2] - 2024-09-28 ### Fixed - Lifetime of `gst::TagList::index()` return value is correctly bound to `&self` now. - Don't assume `gst::Structure` name / field names have `'static` lifetime. - Set pad probe data to `NULL` if `HANDLED` is returned and the item is an event, buffer or buffer list. - Don't unnecessarily add `#[link]` attribute to the `extern "C"` sections to allow linking against gstreamer-full and make static linking easier. ### Changed - Add `#[must_use]` to `gst_video::VideoTimeCode::add_interval()`. ### Added - Add API to take events/buffers from a `gst::PadProbeInfo`. - Add `gst::EventViewMut` and `gst::Event::view_mut()`, and a few setters for event fields. - Add `gst::MessageViewMut` and `gst::Message::view_mut()`, and a few setters for message fields. ## [0.23.1] - 2024-08-27 ### Fixed - Support `gst_utils::StreamProducer` API on platforms without 64 bit atomics. - Fix off-by-one in `gst::BufferList::remove()` range end handling. - Pass an empty tag array instead of NULL in `gst::CustomMeta::register_simple()`. - Fix various new clippy warnings. ### Added - Add getters for `gst::format::Percent`. ## [0.23.0] - 2024-07-11 ### Changed - Compatible with gtk-rs-core 0.20 / gtk4-rs 0.9. - Update GStreamer gir files to latest (upcoming) 1.26 APIs. - Minimum support Rust version is updated from 1.70 to 1.71.1. - Move `gst::Meta` tags into separate modules and improve API around them. - Improve `gst::Meta` transform functions and make the API more generic, and as part of that add support the video meta transform. - Pass an immutable instead of mutable output buffer reference to `gst_rtp::RtpHeaderExtension::write()` function. - Make `gst_net::PtpClock::new()` constructor fallible. - Change `gst_rtsp_server::RTSPToken` API to be consistent with `gst::Structure`, specifically add a builder. - Change `from_glib_ptr_borrow()` functions to work with references instead of raw pointers for improved safety. - Improve code generation when building with `panic=abort`. - Change `gst::BufferList` APIs to work with ranges instead of index+length. - Use various `usize` instead of `u32` for various indices in `gst::Buffer`, `gst::Caps`, `gst::Structure` and related APIs. - `gst::Clock` calibration-related API uses plain `u64` instead of `gst::ClockTime` for the clock rate. - `gst::debug!` and related macros use `obj = x` instead of `obj: x` for specifying the target object now. Similar for `imp` and `id`. The old syntax is still supported but deprecated. The new syntax works better with tooling, especially rustfmt. ### Added - Mutable access to the `gst_webrtc::WebRTCSessionDescription` fields. - `gst::StructureBuilder::field_if_some()` and the same for related builders to only set a value if `Some(x)` is provided. - `gst::StructureBuilder::field_from_iter()` and `field_if_not_empty()` for various builders. - `gst::PadBuilder` API for selecting an automatically generated name. - Adapter for the `log` crate around the GStreamer debug log system. This allows the macros from the `log` crate to be output via the GStreamer debug log system. - Bindings for the double click `gst_video::Navigation` event. - Bindings for `gst_pbutils` missing/install plugins API. - Setters for `gst_editing_services::FrameCompositionMeta`. - `ges::UriClipAsset::new()`. ## [0.22.6] - 2024-06-19 ### Fixed - When logging with an id and a formatted log message this would previously panic. - A couple of clippy warnings. ## [0.22.5] - 2024-05-23 ### Fixed - A couple of clippy warnings and compiler warnings about unused imports with latest rustc. - Memory leak in builder for the `SelectStreams` event. - Add parameter validity assertions to various `BufferList` and `Caps` APIs where these assertions were missing to avoid assertions in C. ### Added - `StreamProducer::set_forward_preroll()` API to configure if the preroll buffer should be directly forwarded or not yet. ### Changed - Remove nonsensical gstreamer-video test that fails with latest GStreamer main. - Update to itertools 0.13. ## [0.22.4] - 2024-04-08 ### Added - Implement `From` / `ToValue` for `gst_audio::AudioConverterConfig` and `gst_video::VideoConverterConfig`. ### Changed - Fixed various 1.77 clippy warnings. ## [0.22.3] - 2024-03-19 ### Changed - Change `ges::CompositionMeta` position fields to `f64`s in correspondence with the C API. - Change `gst_analytics::AnalyticsMtdRef::obj_type()` to an `Option` in correspondence with the C API. ### Added - `gst::Fraction::new_raw()` and `from_integer()` const constructors. ## [0.22.2] - 2024-02-26 ### Changed - Update GStreamer gir files and add more new 1.24 API. ### Fixed - Add `gst::Object` as parent class for various `gst_rtp` types. - Handle all already queued messages in `gst::BusStream` instead of just new messages. ### Added - Add `gst::CustomMeta::is_registered()`. ## [0.22.1] - 2024-02-13 ### Changed - Update GStreamer gir files and add more new 1.24 API. ### Fixed - Make `AnalyticsODLocation` struct fields public. - `MetaRefMut::upcast_mut()` returns a mutable reference now. ## [0.22.0] - 2024-02-08 ### Changed - Compatible with gtk-rs-core 0.19 / gtk4-rs 0.8. - Update GStreamer gir files to latest (upcoming) 1.24 APIs. - Various standalone functions were moved to separate modules or methods. - `gst::Rank` is not implemented as an enum but as a struct with associated constants now. - Optimized `gst::Buffer::from_slice()` and `Memory::from_slice()` implementations that have one heap allocation fewer. - Various `gst::Buffer` and `gst::Memory` functions take ranges now instead of offset/size parameters. ### Added - Bindings for `gst_gl::GLContext::thread_add()`, `GLFrameBuffer::draw_to_texture()`. - New `gst_gl::GLVideoFrame` type that replaces `gst_video::VideoFrame` for GL-specific API, and comes with mostly the same interface. - Basic gstreamer-tag bindings. - `gst::Buffer:dump()` and `dump_range()` together with the same API on `gst::Memory` for hex-dumping the whole buffer/memory content. - Implement `Clone` on `gst::MetaRef`. - Bindings for `gst::Buffer::map_range_readable()` and its writable variant. - Array-based accessor for `gst_video::VideoFrame` and `gst_audio::AudioBuffer` plane data. - Support for handling custom authentication in `gstreamer-rtsp-server`. - Accessors for various base class struct fields. - Owned buffer getter for `AudioBuffer` / `VideoFrame`. - `gst_rtp::RTPSourceMeta` bindings. - `gst::macos_main()` bindings. - gstreamer-analytics bindings. ### Fixed - API typo in owned `gst::ReferenceTimestampMeta` reference getter. - Allow variable expansion in `gst::loggable_error!` macro. - `gstreamer-gl-*` crates can build docs again on stable. ### Removed - `gst::Pad::caps()` property getter. Use `current_caps()` instead which does the same thing. - Various deprecated APIs that were deprecated in previous releases. - Getter for a mutable buffer reference from `AudioBuffer` / `VideoFrame` as that allowed invalidating the buffer map. ### Fixed ## [0.21.3] - 2023-12-18 ### Added - Update GStreamer gir files to latest (upcoming) 1.24 APIs. - Add an example for writing subclasses with virtual methods. - Add `gst::ClockTime::absdiff()` and same for similar types. ### Fixed - In `Play` example, set bus to flushing before dropping `Play` instance. - Add missing `docsrs` configuration for correct documentation generation. - Make `gst_pbutils::element_properties` module public. - Add missing `gst_audio::AudioFilterImpl::parent_allowed_caps()`. - Fix assertions in `gst::Memory` copy/share/resize functions. ### Changed - Update to itertool 0.12, pretty-hex 0.4. ## [0.21.2] - 2023-11-11 ### Changed - Update GStreamer gir files to latest (upcoming) 1.24 APIs. - Update to latest gir code generator from the gtk-rs 0.18 branch. ### Fixed - Big endian video format order is correct again. - `gst::MetaRef::has_tags()` and `tags()` API actually works and works based on the tags of the concrete meta instance. - `gst::MetaRef::tags()` returns strings with arbitrary lifetimes now because they're statically stored anyway. - Fix another potential deadlock in `gst_utils::StreamProducer` when sending force-keyunit events. ### Added - Bindings for `gst_video::VBIEncoder` and `VBIParser`. - Accessors for the different `gst::PadProbeData` types on `PadProbeInfo`. - `Default` impl for `gst::AllocationParams`. - `From` / `TryFrom` implementations between formatted types (e.g. `gst::Bytes`) and `usize`. - `gst::MetaRef::copy()` to copy metas from one buffer to another. - `gst::ElementImpl::catch_panic_future()` to wrap a `Future` in such a way that panics are converted to GStreamer error messages and the element is marked as unusable. - `gst_gl::GLDisplay::handle()` to get a raw display handle. ## [0.21.1] - 2023-10-04 ### Changed - Update GStreamer gir files to latest (upcoming) 1.24 APIs. ### Fixed - Use correct media links in the tutorials code. - Fix a couple of new 1.72/1.73 clippy warnings. - Fix description of gstreamer-validate crate. - Copyright/license files for the gstreamer-gl were added. - Ordering of raw video formats follows the rules of latest libgstvideo now. - Fix potential deadlock in `gst_utils::StreamProducer` when sending force-keyunit events. ### Added - `max-time` / `max-bytes` setters to `gst_app::AppSink` builder. - `gst::CustomMeta::register_simple()`. ## [0.21.0] - 2023-08-08 ### Changed - Minimum supported Rust version is updated to 1.70.0. - Compatible with gtk-rs-core 0.18. - `gst::Bin::add_many()`, `remove_many()` and `gst::Element::link_many()`, `unlink_many()` are more generic now. - `gst_base::Aggregator::src_pad()` returns an `AggregatorPad`. - `gst::Bus::add_watch()` now returns a guard value that automatically removes the watch when it goes out of scope. - `gst::Bin`, `Pipeline` and `Pad` constructors don't take the optional name parameter anymore but it can instead be provided via the builder API. - `gst::Pad` and `GhostPad` builders inherit name from the pad template (or target) if possible and no other name is provided explicitly. - The preroll samples and selected sticky events are forwarded to `StreamProducer` consumers. ### Added - Support for the upcoming GStreamer 1.24 APIs. - Support for inline variable names in format strings for error/warning/info messages. - Methods for converting between floating point seconds and `gst::ClockTime`. - Various additions to the gst-validate bindings. - `Display` implementations for error/warning/info messages. - More useful `Debug` implementations for messages, events and queries and `gst_pbutils::DiscovererInfo` related structs. - API for listing/checking `gst::Meta` tags. ## [0.20.7] - 2023-07-05 ### Fixed - Fix `wait-for-eos` property name string in `appsink`. - Fix various memory leaks in `BaseTransform` subclassing bindings. - Mark some GES APIs as `Send+Sync`. ### Added - Implement `DiscovererInfo::debug()` and on related structs. + Add subclassing bindings for `GESFormatter`. ## [0.20.6] - 2023-06-06 ### Added - Getter for the `gst_rtsp_server::RTSPContext` URI field. ### Fixed - `gst_pbutils::DiscovererStreamInfo::stream_id()` can return `NULL`. This is mapped to the empty string for this release to keep backwards compatibility. - `gst_pbutils::DiscovererStreamInfo` iterator methods can be called on any subclass directly now without casting. - Debug logs use the actual function name against instead of the name of a closure generated by the log macros. ### Changed - Minor performance improvements to debug logging. ## [0.20.5] - 2023-04-22 ### Added - `glib::HasParamSpec` impl for miniobjects to allow using them with the properties derive macro. - `Default` impl for `gst_player::Player`. ## [0.20.4] - 2023-04-07 ### Fixed - Work around `gst_webrtc::WebRTCICE::add_candidate()` API breakage in 1.24. ### Changed - Reduce size of `gst_audio::AudioBuffer` and `gst_video::VideoFrame` by a factor of two by not storing an unnecessary copy of the audio/video info. ## [0.20.3] - 2023-03-14 ### Fixed - `gst::ParamSpecArray` uses the correct `glib::Type` now. - Work around accidental ABI breakage in 1.18 gst-rtsp-server `GstRTSPClient`. ### Added - Document `gst_utils::StreamProducer::forward_eos()` default value. ## [0.20.2] - 2023-02-21 ### Added - `glib::HasParamSpec` impl for `gst::ClockTime` - `Default` impl for `gst_play::Play` - Constructors for non-raw `gst_audio::AudioCapsBuilder` / `gst_video::VideoCapsBuilder` ## [0.20.1] - 2023-02-13 ### Fixed - Fix memory leaks when converting a `gst_audio::AudioBuffer` or `gst_video::VideoFrame` to a `gst::Buffer` or FFI type. ## [0.20.0] - 2023-02-10 ### Fixed - Make `gst_gL::GLDisplay::create_context()` `other_context` parameter optional. - Make allocation query caps optional. ### Added - Conversions between `gst::Signed` and `T` and signed integer types. - Bindings for the object lock via `gst::Object::lock()`. - Various `FromIterator`, `Extend` and `From` impls for creating `Caps`, `Structure`, `Buffer`, `BufferList`, `CapsFeatures` and other types. - `PartialEq` impls between owned/borrowed miniobjects/structures. - API for appending items to `gst::Array` and `gst::List`. ### Changed - Compatible with the 0.17 gtk-rs release. - Updated minimum supported Rust version to 1.64. - Require GStreamer 1.22.0 or newer when enabling the `v1_22` feature. - Require the object lock to be taken for various `gst_gl::GLDisplay` methods. - Renamed `gst::TagSetter::add()` to `add_tags()` to avoid name conflict with `Bin::add()`. - Mark various un-extendable enums as exhaustive. - Make use of `glib::GStr` and related API in caps, structure, tags and logging API to reduce temporary string allocations. - Various code optimizations to reduce generated code size and allow more optimal code to be generated. - Reduce size of various types, including reduction of `gst_audio::AudioInfo` from 832 to 320 bytes. - Use actual function name instead of module name in log output. - Change `gst_utils::StreamProducer` API to forward buffers by default and allow temporarily discarding via new `set_discard()` function. ## [0.19.8] - 2023-02-09 ### Changed - Update GStreamer .gir files to 1.22.0 release. ### Fixed - Marked `gst::MessageType` as non-exhaustive. ### Added - Added bindings for `gst::Message::structure_mut()`. - Added subclassing support for `gst_allocators::FdAllocator` and `DmabufAllocator`. ## [0.19.7] - 2023-01-19 ### Fixed - Work around the possibility that the caps in the allocation query can be `NULL` by returning any caps for now. This will be handled properly with a minimal API change in the 0.20 release. ## [0.19.6] - 2023-01-18 ### Fixed - The `AppSrc` and `AppSink` builders now assert that GStreamer is initialized before creating an instance. ## [0.19.5] - 2022-12-27 ### Fixed - Clear video frame values when mapping as GL texture to avoid out of bounds reads when trying to access the GL texture as raw video frame. - Allow returning `Handled` from `BufferList` pad probes. ### Changed - Update GStreamer .gir files to latest 1.21 git. ## [0.19.4] - 2022-12-16 ### Added - Subclassing bindings for `gst_audio::AudioFilter`. ### Fixed - Various new clippy warnings. ### Changed - Update GStreamer .gir files to 1.21.3 release. ## [0.19.3] - 2022-11-28 ### Added - `FromIterator` and `Extend` for `Caps`. - `PartialEq` impls between owned/borrowed miniobjects/structures. ### Fixed - Sticky event ordering for instant-rate-change. ### Changed - Updated GStreamer .gir files to post 1.22.2 release. ## [0.19.2] - 2022-11-13 ### Added - Subclassing support for `gst::Allocator`. - `gst_gl::GLBaseMemory::context()` to retrieve the GL context used by the memory. ### Changed - Updated GStreamer .gir files to 1.22.2 release. ### Fixed - `gst::Allocator::register()` does not cause use-after free with GStreamer < 1.20.5 anymore. - Don't generate version constants in `gstreamer-editing-services-sys` as they are useless and change with every update. ### Changed - Fixed various new clippy warnings. ## [0.19.1] - 2022-10-24 ### Changed - Make it possible to use objects not just as reference in the logging macros. ## [0.19.0] - 2022-10-22 ### Added - Builders for element construction. `gst::ElementFactory::make()` returns a builder now that allows to easily set the name or any other property at construction time. The old API is available as `make_with_name()`. - Builders for `Bin` and `Pipeline` as well as a `Default` trait implementation to simplify object construction. - Builders for `appsrc` and `appsink`, which allow type-safe construction of both elements while also allowing to easily set all their properties at construction time. - Builders for the GStreamer-specific fraction/array param/property specs. - Infrastructure for casting between `gst::Memory` subtypes/supertypes, and make use of it for GL memory. - Bindings for the `gstreamer-allocator` library with support for file descriptor-based and DMABUF memory. - Complete bindings for `gst_video` `Navigation` events. - Constructors for error/warning/info messages with a pre-built `glib::Error`. This also leads to some minor simplification of the existing API. - Accessors for static pads of various base classes for making accessing them cheaper and less error-prone than getting them by name. - Builder for pad templates. - Static PTP clock API for statistics, initialization and deinitialization. - New `gstreamer-utils` crate that currently contains only a `StreamProducer` API. This allows building 1:N bridges between live pipelines via `appsink` / `appsrc` elements. - Bindings for the new `gstreamer-play` library that was added in 1.20. - `gst::Caps::new_empty_simple()` to create caps without fields and just a name. - `gst_audio::AudioCapsBuilder` and `gst_video::VideoCapsBuilder` for building (possibly) unfixed raw audio/videos caps with typed setters for the various fields. This makes it impossible to mix up types and e.g. use an `u32` instead of an `i32` for the width of video caps. - `gst::Buffer::ptr_eq()` to compare buffers by pointer instead of doing a deep comparison, and also `ptr_eq()` on all other miniobject types. - Accessors for `gst_webrtc::WebRTCICECandidateStats` fields. - Bindings for the `gstreamer-validate` API. - Subclassing bindings for `gst_audio::AudioVisualizer` base class for easily writing audio visualization elements. - `gst_pbutils::EncodingProfile` API for element properties. - Support for returning buffer lists from `BaseSrc` / `PushSrc` subclasses. - Support for implementing `gst::Bin::do_latency()`. - Minimal bindings for the `gstreamer-mpegts` library. ### Fixed - Signature for `gst_base::Aggregator::connect_samples_selected()` to remove unnecessary generic parameter and make it straightforward to use. - Various APIs had optional parameters/return types corrected to match the C API more closely. - Logging does not evaluate its arguments anymore if the debug category is not enabled or below the current threshold. - Registering custom metas is now possible without transform function. - `gst::subclass::ElementImpl::request_new_pad()` signature uses a `&str` instead of an owned `String` now. ### Removed - `fragile` dependency and instead use the same functionality from `glib`. - `gst_audio::AudioAggregator` `ignore_inactive_pads` property, which was duplicated from the `Aggregator` base class. ### Changed - Compatible with the 0.16 gtk-rs release. - Updated minimum supported GStreamer version from 1.8 to 1.14. - Updated to the latest GStreamer 1.22 APIs while still supporting up to GStreamer 1.14. Any new 1.22 APIs might still change until the stable 1.22 release. - Updated minimum supported Rust version to 1.63. - In `EventView` / `QueryView`, getters that return references now return references that can outlive the view and are only bound by the lifetime of the corresponding event/query. - In addition `Query`, `Event` and `Message` views are implemented more consistently now, which makes them easier to use and as a side effect allows to pass e.g. more strongly typed queries to functions that only accept a single query type. - Various improvements to `gst::ClockTime`, `gst::format::Bytes`, `gst::format::Signed` and related types and their usage in the API, which should make its use from applications easier and less error-prone. Check the `gst::format` module-level documentation for details. - `gst::StreamsSelected` event builder takes the selected streams as iterator instead of slice. - For consistency with other macros the `gst` prefix of the logging macros was also removed. - Various iterator implementations were added and the existing ones were optimized by implementing more specialized traits and custom implementations for a couple of iterator functions. - GStreamer initialization safety checks were optimized. - `gst::Bus::post()` takes ownership of the passed messages like the C API. - Better and easier to read `Debug` impls for `Caps`, `TagList`, `Structure` and `Promise`. - `ser_de` feature was renamed to `serde`. - `gst::Tracer` implementations get result enums passed as `Result`s now instead of single enums. - `gst::Pad`, `ProxyPad`, `GhostPad` default functions are all associated functions instead of methods now to avoid conflicts between multiple types with the same method. - `Pad` tasks are catching panics from the task function and if the parent of the pad is an element then the panic is converted into an error message and the task is simply stopped. Otherwise the panic is rethrown. ## [0.18.8] - 2022-04-26 ### Added - Bindings for `RTPBasePayload` and `RTPBaseDepayload`. - Accessors for `RTPBuffer` buffer. - Bindings for `RTPBuffer` length calculation API. - More complete `gst::Task` bindings. ### Fixed - Export `gst::subclass::TaskPoolFunction`. ## [0.18.7] - 2022-04-04 ### Added - Bindings for `VideoAggregator` and the `VideoAggregatorPad`s. - Bindings for `AudioAggregator` and the `AudioAggregatorPad`s. - Bindings for `TaskPool`. - Various helper functions for `VideoFormatInfo`, `VideoInfo` and `VideoFrame`. ## [0.18.6] - 2022-03-08 ### Fixed - Require `Send` and not `Sync` for the values of an `gst::Array` / `gst::List`. ### Changed - Simplify and speed up log message string construction ## [0.18.5] - 2022-02-20 ### Changed - Require GStreamer 1.20.0 at least when building with `v1_20`. Earlier versions were already going to fail due to API mismatches before. ### Added - `gst::BufferPool` subclassing support. - `Debug` impl for `gst::MiniObject`. - `gst_rtsp_server::RTSPOnvifServer` and related API, including subclassing support. ### Fixed - Handle empty slices correctly at the FFI layer. - `MiniObjectRef::downcast_ref()` and similar functions return the correct type now. While this is an API change, the previous API would've never worked. ## [0.18.4] - 2022-02-04 ### Changed - Update gir files to GStreamer 1.20.0 release. ### Added - `gst_video::VideoCodecFrame::input_buffer_owned()` for getting an owned reference. ### Fixed - All documentation links in the `README.md`s are correct again. ## [0.18.3] - 2022-01-31 ### Added - `Default` implementation for `gst_video::VideoOverlayComposition` when targeting GStreamer 1.20. - `gst_video::VideoOverlayComposition::add_rectangle()` in addition to the addition of all rectangles via an iterator during construction. - Subclassing support for `gst_rtp::RTPHeaderExtension`. - `gst_webrtc::WebRTCError` for programmatically handling WebRTC errors. ### Fixed - `gst_rtp::RTPHeaderExtension` has `gst::Element` set as parent class now. - Global functions are re-exported from the `gst_rtp` crate root. ### Changed - GIO-style async operations in GES no longer need `Send`-able closures. ### Removed - `fragile` is no longer a dependency and instead the corresponding GLib API is used. ## [0.18.2] - 2022-01-24 ### Added - `glib::FromValue` for mini object references. - Bindings for `gst::DebugCategory::get_line()`. ## [0.18.1] - 2022-01-18 ### Fixed - `Message::view()` also handles the redirect message now. - `Message` and `Query` view variants that return references now borrow again from the underlying query and not the view enum, allowing to use them in a wider scope. ### Changed - All miniobjects, `VideoTimeCode`, `Structure` and `CapsFeatures` are marked as `#[repr(transparent)]` now to ensure that their memory representation is exactly the underlying raw pointer. ## [0.18.0] - 2022-01-16 ### Added - `gst_rtp::RtpHeaderExtension::read()` and `write()`. - `gst::ElementMetadata` has a `const` constructor now. - `gst_rtp::RtpBuffer` API works on buffer references instead of plain buffers for statically enforcing writability and usage in more places. - `gst_video::VideoCodecAlphaMeta` and `gst::CustomMeta`. - `gst::MiniObject` for generically passing around mini objects instead of their concrete types. - `gst_app::AppSink` `new-event` callback and `pull_object()` function. - `gst_pbutils::PbUtilsCapsDescriptionFlags` and `pb_utils_get_caps_description_flags()`. - `gst_rtp::RtpBuffer::remove_extension_data()`. - `gst_video::VideoDecoder` subframe API. - `gst_webrtc::WebRTCSCTPTransport`. - `gst::ElementFactory` `create_with_properties()` / `make_with_properties()`. - `gst_video::VideoContentLightLevel` and `VideoMasteringDisplayInfo` for HDR signalling. - Lots of missing `GES` API. - `gst::AllocationParams` and support in the allocation query. - `propose_allocation()` and `decide_allocation()` support in the various base classes. - `Iterator` implementation for `gst_video::VideoOverlayComposition`. - `Extend`, `IntoIterator` and `FromIterator` implementations for `Buffer`, `Caps`, `BufferList`, `CapsFeatures`, `StreamCollection` and `Structure` for more natural Rust APIs. - `instant-rate-change` events/messages bindings. - Support for arithmetic operations on `Option` and related types. - `gst_video::ColorBalance`. - `gst::MetaFlags`. - `gst_base::Aggregator::set_position()`. - Convenience getters for `gst::ElementFactory` and `gst::DeviceProviderFactory` metadata. - `gst_rtp::RtpBuffer::set_padding()`, `get_padding()` and `payload_mut()`. - `#[must_use]` to many types and functions. - `gst::Event`, `gst::Message` and `gst::Structure` `has_name()`. - `gst_video::Navigation` subclassing support and API improvements. - `gst::Structure` and `gst::Caps` `foreach()`, `map_in_place()` and `filter_map_in_place()`. - `gst_gl::GLBufferPool` and various GL constants and functions. - `gst_pbutils` codec utils APIs. ### Fixed - `gst_base::BaseTransform::prepare_output_buffer()` correctly reflects buffer writability. ### Changed - Compatible with the 0.15 gtk-rs release. - Updated to the latest GStreamer 1.20 APIs while still supporting up to GStreamer 1.8. Any new 1.20 APIs might still change until the stable 1.20 release. - Update all code to the Rust 2021 edition. This causes no user-facing changes. - `gst::Sample::segment()` returns a reference instead of a copy of the segment. - `gst::Object::set_property_from_str()` returns a `Result` now instead of silently failing like the C version. - Allow handling passed in buffers in `gst_base::PushSrc::create`. - Allow passing in `None` in `gst_player::Player::set_uri()`. - Use `[[f32; 4]; 4]` instead of `[f32; 16]` for affine transformation matrix. - `gst::Pad::sticky_event()` statically gets the event of the requested type instead of requiring to match on it afterwards. - Clean up `gst_pbutils` `EncodingProfile` API to be harder to misuse and less confusing. - Various `gst::Array`, `gst::List`, `gst::IntRange` and `gst::Fraction` API improvements that should reduce some friction. - Directly generate `NUL`-terminated C strings in debug log API instead of having multiple allocations per message. - Various functions return `glib::SList` and `glib::List` now to avoid copying into a `Vec` if only iteration is needed. - `gst::ChildProxy` API is more consistent with object property API. - Improved `gst::Buffer::foreach()`, `gst::Pad::sticky_events_foreach()` and `gst::BufferList::foreach()` APIs. - Don't post error messages from `propose_allocation()` and `decide_allocation()`. ## [0.17.4] - 2021-09-13 ### Added - Add constructor for device provider metadata. ## [0.17.3] - 2021-08-23 ### Fixed - `gst::Value::deserialize()` takes the target type as parameter now. This is technically an API change but the function would've never worked previously. ### Added - The release date-time parameter to `gst::plugin_define!` is optional now like in the C version of the macro. - Bindings to `gst::Tracer` and `gst::TracerFactory` for allowing to implement custom tracers in Rust. - Bindings for the new `gst::Value::deserialize_with_psec()` function from GStreamer 1.20. - serde `Serialize`/`Deserialize` impls for `gst::PadDirection`, `gst::PadPresence`, `gst::URIType` and `gst::Rank`. ## [0.17.2] - 2021-08-05 ### Fixed - Various new clippy warnings. - Compilation of `gstreamer-audio` on big-endian platforms. ### Added - Support for 1.20 `Gap` event `GapFlags`. - Support for 1.20 `Structure::serialize()` / `Caps::serialize()`. ## [0.17.1] - 2021-07-13 ### Fixed - Store 1.19 as plugin version when building plugins with `v1_20`. Otherwise plugins fail to load with GStreamer versions below 1.20.0. - Fix documentation for `gst::Element::request_pad_simple()` to actually show up. ## [0.17.0] - 2021-06-28 ### Fixed - Use `#[repr(transparent)]` where it is more correct and remove unneeded `#[repr(C)]` annotations. - Don't provide direct access to the logged object in logging functions as the object might currently be finalized and might be unsafe to access. - Moved X11/EGL/Wayland-specific GL APIs into their own crates instead of having them inside gstreamer-gl and behind feature flags. This simplifies conditional usage of them in applications. - Various nullability issues: parameters and return values that should've been or shouldn't have been nullable were fixed. - Print source object correctly in `gst::Message` `Debug` impl. - `gst_rtsp_server::RTSPServer::attach()` is fallible. - `gst::ElementFactoryListType` is a proper bitflags type now instead of generic `u64`. - `gst::PluginFeature::load()` returns the same type as the one passed in. - Value returned by `gst::PromiseFuture` can no longer be freed while still in scope. - Only assign to `GError**`s in subclassing code if they're not `NULL`. ### Added - Bindings for the GStreamer Controller library and the corresponding core API. - Subclassing support for `gst_player::PlayerVideoRenderer`. - `gst::PARAM_FLAG_CONTROLLABLE` and related bindings. - `gst_video::VideoOrientation` and `VideoOrientationMethod` bindings. - Support for removing pad probes from inside the pad probe callback. - `gst_check::Harness::pull_until_eos()` bindings. - `ges::TransitionClip` and `OperationClip`. - Bindings for `gst_gl::GLMemory` and related APIs. - Subclassing support for `gst_gl::GLFilter` and `gst_gl::BaseSrc`. - `gst::TagList::remove()`. - `gst::CapsFeatures` and `gst::Structure` API based on `glib::Quark`s instead of strings. - Subclassing support for `gst_video::VideoFilter`. - Bindings for various new 1.20 APIs: `gst_app::LeakyType`, `gst_video::VideoDecoderRequestSyncPointFlags`, `gst_rtp::RTPHeaderExtension`, `gst_audio::AudioLevelMeta`, `gst_webrtc::WebRTCKind` and various other new flags/enum types. - Subclassing support for `gst_rtsp_server::RTSPMountPoints`. ### Removed - Deprecated APIs in 0.16. - Don't declare that `gst_app::AppSink` and `AppSrc` inherit from `gst_base::BaseSink` and `BaseSrc` to avoid exposing API that is meant for subclasses to applications. - `gst_app::AppSrc` and `AppSink` signals that are also covered by the callbacks. The callbacks are more flexible and have lower overhead. - Duplicated getters/setters for `gst_base::BaseSink` and `BaseTransform` properties. ### Changed - Compatible with the 0.14 gtk-rs release. - Updated to the new GStreamer 1.20 APIs while still supporting up to GStreamer 1.8. Any new 1.20 APIs might still change until the stable 1.20 release. - FFI and safe high-level bindings are in the same repository now and use the same version numbers. - The .gir files are shared with gtk-rs and the GStreamer-specific ones are in a separate git submodule. - Update all code to the Rust 2018 edition. As part of this, most macros lost their `gst_` prefix. - Re-export dependency crates from the different preludes. - Getter functions don't have a `get_` prefix anymore and GObject property accessors don't include the `_property_` part in the middle of their function names anymore. Applications developers should use [`fix-getters-calls`](https://crates.io/crates/fix-getters-calls) to ease migration of their applications. Use [`fix-getters-def`](https://crates.io/crates/fix-getters-def) if you also want your `get` functions definition to comply with the API standards applied in this release. - Lots of changes to the subclassing API. Check the various elements in [gst-plugins-rs](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs) for examples. - Major improvements to the documentation infrastructure and generated documentation. - `gst::ClockID` bindings are refactored to use different types for single-shot and periodic clock ids, which makes misuse harder. - `gst::ProxyPad` extension trait uses trait functions instead of associated functions now for usability reasons. - Use `Result` for overriding flow returns from pad probes. - `gst_video::VideoInfo::align()` returns a `Result` instead of a `bool`. - Use actual error types instead of `()` in `gst_sdp` APIs. - `Display` impl for `gst::ClockTime` provides better human-readable strings. - `gst::Element::link_filtered()` and `link_pads_filtered()` takes a non-optional caps now. That's easier to use and for not providing caps the non-filtered variants of the functions exist. - Replace various manual bindings with auto-generated ones. - `gst::Element::get_request_pad()` is replaced by `request_pad_simple()` as a simpler version of `request_pad()` and in accordance with the deprecation in GStreamer 1.20. - `gst::ClockTime` and APIs working on it were changed to make possibility of using `GST_CLOCK_TIME_NONE` expressed in the type system. `Option` can be `None` while `gst::ClockTime` is always a valid time. ## [0.16.7] - 2021-02-13 ### Fixed - Usage of the logging system with a GStreamer library with the logging system compiled out does not crash any longer. - Double-free in `gst_video::VideoTimeCode` API when converting between validated and unvalidated timecodes. ### Added - `gst::Element::get_current_state()` and `get_pending_state()` convenience APIs. - `gst_audio::AudioConverterConfig` for setting the configuration on e.g. the `audiomixer` element. The low-level `AudioConverter` API is still not included in the bindings. ## [0.16.6] - 2020-12-20 ### Fixed - `VideoTimeCodeInterval`'s `Ord` and `PartialEq` implementations compare against the correct fields now. - `SDPMessage::medias_mut()` iterator does not crash any longer. ### Added - `PartialEq` and `Eq` implementations on `VideoAlignment`. - Alignment API for `VideoMeta` and `get_plane_height()` / `get_plane_size()`. - `VideoInfo::align_full()`. ## [0.16.5] - 2020-11-23 ### Fixed - Make sure to use `$crate` in more macros to allow them to work without anything special in scope already. - Update documentation location. - Don't panic if C code stores invalid seqnums in events and the seqnum is used directly or via the `Display` impl. - Fix docs build for some crates on docs.rs. - Fix `Debug` impl for `gst_video::VideoTimeCode` to print the correct type name. - Fix plugin version to be 1.18 instead of 1.17 when compiling a plugin with `v1_18`. ### Added - Event handling support in pad probes, that is returning `PadProbeReturn::Handled` for events. - `EventRef::get_structure_mut()` getter that allows changing the events' structures. ### Changed - Remove unnecessary `PhantomData` markers and use `repr(transparent)` instead of `repr(C)` where it is more correct. ## [0.16.4] - 2020-10-09 ### Fixed - Correctly implement `ExactSizeIterator` on the `AudioFormat` and `VideoFormat` iterators. Previously they returned the overall size instead of the remaining size, and they didn't implement `Iterator::size_hint()`. - Don't implement `ExactSizeIterator` on the buffer `gst::Meta` iterator. The overall length is not known easily and the implementation would've simply panicked in the past. ### Added - `gst::ClockID::wait_async_stream()` for async integration for clock waiting. - `From` / `TryFrom` impls for converting between `gst::ClockTime` and `std::time::Duration`. ## [0.16.3] - 2020-09-08 ### Fixed - Reset vfuncs if calling `BaseTransformClass::configure()` multiple times. - Fix `gst::debug_remove_default_log_function()` to actually remove the default log function. ### Added - Some more new APIs added in 1.18. - API for getting an owned buffer from a readable `gst_video::VideoFrame` / `VideoFrameRef`. ### Changed - Updated bindings to 1.18.0. This stabilized GStreamer 1.18 support and any API behind the "v1_18" feature is considered stable now. - Factor out some common code from `gst::Pad::ProbeInfo` code. This reduces the code generated for each pad probe considerably. - Update paste dependency to 1.0 and pretty-hex to 0.2. ## [0.16.2] - 2020-07-27 ### Fixed - Use correct pointer for the plane data in `gst_audio::AudioBuffer`. ### Added - Add `gst::GhostPad` convenience constructors that take a target pad, similar to the ones that existed in 0.15 and before. - Add `gst::parse_bin_from_description_with_name` that allows setting a name for the created bin without having to use unsafe code in application code. ## [0.16.1] - 2020-07-10 ### Fixed - Allow calling `gst::DebugCategory::new()` before `gst::init()` again. ## [0.16.0] - 2020-07-06 ### Added - Updated bindings to 1.17.2, adding experimental 1.18 support. This can be opted-in via the "v1_18" feature flag but there might still be API changes in the newly added API. - `gst::MemoryRef::dump()` for dumping contents of a memory. - `gst::Bus::stream()` instead of a custom constructor on the `BusStream`. - Use more accurate types for `Seqnum`, `GroupId` and `MetaSeqnum`. These are now proper wrapper types instead of plain integers, which makes misuse harder. - Provide `TryFrom` impls for conversion between `glib::DateTime` and `gst::DateTime`. - Add `get_allocator()` functions to `gst_base::{Aggregator, BaseTransform, BaseSrc}`, and allow overriding `BaseSrc::alloc()`. - Add subclassing bindings for `gst_base::PushSrc`. - Add new `gst::BufferCursor` API that allows to handle a buffer as `Read`, `Write` and `Seek` and accesses the underlying memories of the buffer individually without mapping them all together. - Add `gst::Plugin::get_plugin_name()`. - Support for `gst_video::VideoAFDMeta` and `VideoBarMeta`. - API for getting all / iterating over all `gst_audio::AudioFormat` and `gst_video::VideoFormat`. - Bindings and subclassing bindings for `gst_video::VideoSink`. - `gst::Pad` can be constructed via the builder pattern and `gst::PadBuilder` now, which allows to safely set the pad functions and various other fields during construction. The `PadBuilder` works on any `gst::Pad` subclass and also has special support for `GhostPad`s by allowing to set pad functions of the proxy pad. - `gst::Message`, `gst::Event` and `gst::Query` type constructors are now on the specific target type instead of various `new_XXX()` functions on the basic type. E.g. `gst::message::Eos::new()`. - Support for overriding `gst_audio::AudioSrc/Sink::reset()`. - Support for overriding `gst_base::BaseParse::stop()`. - Support for overriding `gst::Element::post_message()`. - Added bindings for `gst::BufferList::foreach()` and `foreach_mut()`. - Added bindings for `gst::Buffer::foreach_meta()` and `foreach_meta_mut()`. ### Fixed - Allow using any `glib::Object` as target object for logging instead of just `gst::Object`. - Remove restriction API from `gst_pbutils::EncodingContainerProfile`. They are supposed to be used only with the other encoding profiles. - Return `&'static str` for various `gst::StructureRef` functions where the string is backed by a `glib::Quark`. - Fix various `gst::DateTime` functions to actually return `Option`s. - Add support for filling in a buffer passed to the `gst::Pad` getrange function, allow passing one in into `get_range()` and `pull_range()` and provide the corresponding API on `gst_base::BaseSrc` too. - Allocator in audio/video `Decoder` base classes is optional and can return `None`. - `gst_video::ValidVideoTimeCode::add_interval()` always returns a valid timecode again. - Allow resolving a `gst::Promise` with `None` and also handle that correctly in the callback. This is allowed by the API. - Allow calling various debugging related functions before `gst::init()`. - Various enum/function versions were fixed to only show up if the corresponding version feature is enabled. - `gst::Pad` function setters are marked unsafe now as changing the functions is not thread-safe. - Remove `gst::Object::set_name()` as changing the name after construction generally causes problems and is potentially unsafe. - Remove `gst::Pad::set_pad_template()` as changing the pad template after construction is generally unsafe. - `gst::Pad::stream_lock()` borrows the pad now instead of taking a new reference. - Unimplemented `Jitter` and `Buffer` queries were removed from the bindings. These are not implemented in C and only have a type registered. - Various `LAST`, `NONE` variants of enums and flags were removed as these only make sense in C. - Call the parent impl of various vfuncs that were omitted before to not require further subclasses of them to implement them but automatically call the parent ones. ### Changed - Use `NonZeroU64/U32` for various ID types to allow further optimizations. - Use `thiserror` crate for deriving error types. - Switch from `lazy_static` to `once_cell`. - Change various miniobject functions like `gst::Caps::append()` from taking the object by value to modifying it internally. This makes them easier to use and only applies to functions that are defined on the non-reference type and take ownership of the values passed in. - Use `mem::ManuallyDrop` instead of `mem::forget()` everywhere. - Replace most `mem::transmute()` calls with safer alternatives. - `gst:StreamCollection` API was changed to the builder pattern for construction as the collection must not be changed after construction. - `gst::ProxyPad` default functions are plain functions on `ProxyPad` now instead of trait functions to allow easier usage of them. - Use proper error types in various `TryFrom` impls. - `gst_video::VideoMeta::add()` returns a `Result` now instead of panicking. - Various constructors were renamed from `new_with_XXX()` and `new_from_XXX()` to the more idiomatic `with_XXX()` and `from_XXX()`. - Miniobject bindings are simplified now and there is no `gst::GstRc` type anymore, instead everything is directly implemented on the concrete types. As part of this the `gst::MiniObject` trait was also removed as it was unneeded now. ## [0.15.7] - 2020-06-08 ### Fixed - Allow multiple filter types per process with `gst::Iterator::filter()`. - Check that `VideoInfo` is valid when creating a `VideoFrame`. - Don't potentially dereference a `NULL` pointer when getting the format from an invalid `VideoInfo` or `AudioInfo`. - Don't unmap borrowed `VideoFrameRef`s. ### Added - `gst::ProtectionMeta`, `gst_video::VideoAffineTransformationMeta`, `VideoCropMeta` and `VideoRegionOfInterestMeta` bindings. - Various new `gst_rtp::RTPBuffer` methods. - `gst_audio::audio_buffer_truncate()`, `AudioMeta` and `AudioBuffer` bindings. ## [0.15.6] - 2020-05-28 ### Fixed - Assert that the data passed to `VideoCaptionMeta::add()` is not empty. - Don't store strong references to the object in the bus, appsink and appsrc futures `Stream` / `Sink` adapters. This would keep them alive unnecessarily and would prevent the `Stream` / `Sink` to ever "finish" on its own. - Handle receiving a `None` reply in the change function of `gst::Promise`. This is apparently valid. For backwards compatibility reasons this is currently replaced with an empty structure but in 0.16 the API will explicitly handle `None`. ### Added - `gst::Stream::debug()` and `gst::StreamCollection::debug()` for converting into a structured string with the actual contents of each. - `gst::Structure::from_iter()` and `gst::Caps::from_iter()` to create structures/caps from iterators. - `gst::Event` support for getting/setting the `gst::Stream` in the `StreamStart` event. - `gst_video::calculate_display_ratio()` and `::guess_framerate()`. - Various video related `gst::CapsFeatures` in `gst_video`. - `TryFrom`/`From` impls for converting between `gst::Structure` and `gst_video::VideoConverterConfig`. - Various `glib::Value` trait impls for `SDPMessage`, `StructureRef`, `CapsFeatureRef` and all borrowed variants of miniobjects to be able to work with the borrowed, non-owned variants when handling `glib::Value`s. ## [0.15.5] - 2020-05-03 ### Fixed - Revert: Allow logging any `glib::Object` and not just `gst::Object`. This broke API in subtle ways and needs to wait until 0.16 - Replace `%` in log output with `%%` to prevent accidental C formatting - Add missing manual traits to the documentation ### Added - `BufferRef::peek_memory_mut()` to give a mutable reference to a given memory - Different iterators for iterating over the memories of a buffer - Support for `gst_audio::AudioClippingMeta` - `gst::Plugin::get_plugin_name()` was added - `gst::Element::get_current_clock_time()` and `gst::Element::get_current_running_time() helper functions - `gst::State` and `StateChange` API for calculating next/previous state and convert from/to the components of a state change ### Changed - Use `mem::ManuallyDrop` instead of `mem::forget` everywhere ## [0.15.4] - 2020-03-09 ### Fixed - Allow logging any `glib::Object` and not just `gst::Object` - Fix floating reference handling in `RTSPMedia::take_pipeline()` - Hold `GMutex` guards for the remainder of the function and warn if they're directly dropped - Work around empty/any caps handling bugs in `Caps::fixate()` ### Added - Add `BaseTransform::prepare_output_buffer()` subclassing support - `RTSPServer`, `RTSPClient`, `RTSPMedia` and `RTSPMediaFactory` subclassing support - Handle panicking in `appsrc`/`appsink` callbacks by posting an error message instead of killing the process ## [0.15.3] - 2020-02-15 ### Fixed - `UniqueFlowCombiner::clear()` should take a mutable reference. - `AudioStreamAlign` doesn't require mutable references for getters anymore. - Don't use bool return value of `gst_video_info_set_format()` and `gst_video_info_align()` with GStreamer < 1.11.1 as it returned void back then. We'd otherwise use some random value. - Make `VideoInfo::align()` is available since 1.8. - Fix changing/clearing of `AppSrc`, `AppSink` callbacks and `Bus` sync handler. Before 1.16.3 this was not thread-safe and caused crashes. When running with older versions changing them causes a panic now and unsetting the bus sync handler has not effect. With newer versions it works correctly. ### Added - Add `Clone` impls for `BufferPoolConfig` and `PlayerConfig`. - Add `VideoConverter` bindings. - Add `Future`s variant for `gst::Promise` constructor. - Add `Future`s variant for `gst_video::convert_sample_async()`. - Add `submit_input_buffer()`, `generate_output()`, `before_transform()`, `copy_metadata()` and `transform_meta()` virtual method support for `BaseTransform`. - Add `AppSink` `Stream` adapter and `AppSrc` `Sink` adapter for integrating both into Rust async contexts. ### Changed - More generic implementations of `VideoFrame` / `VideoFrameRef` functions to allow usage in more generic contexts. ## [0.15.2] - 2020-01-30 ### Fixed - Fix another race condition in the `gst::Bus` `Stream` that could cause it to not wake up although a message is available. ## [0.15.1] - 2020-01-23 ### Added - Use static inner lifetime for `VideoCodecState` so that it can be stored safely on the heap. - Getters/setters for `BinFlags` on `gst::Bin`. - `gst::Caps::builder_full()` for building caps with multiple structures conveniently. - `gst::Element::call_async_future()` for asynchronously spawning a closure and returning a `Future` for awaiting its return value. ### Fixed - Various clippy warnings. - Getters/setters for `PadFlags` on `gst::Pad` now provide the correct behaviour. - Take mutex before popping messages in the `gst::Bus` `Stream` to close a small race condition that could cause it to not be woken up. - `gst::ChildProxy` implementers do not have to provide `child_added()` and `child_removed()` functions anymore but these are optional now. - Manually implement `Debug` impls for various generic types where to `Debug` impl should not depend on their type parameters also implementing `Debug`. ## [0.15.0] - 2019-12-18 ### Added - `StructureRef::get_optional()` for returning `None` if the field does not exist instead of `Err` - Bindings for `gstreamer-rtp` library, mostly `RTPBuffer` - Support for writing `Preset`, `TagSetter`, `Clock`, `SystemClock` subclasses - Bindings for `Typefind::get_length()` - Bindings for `BaseSrcImpl::get_times()` - Bindings (incl. subclassing) for `AudioSink` and `AudioSrc` - Missing `Send`/`Sync` impl for various types ### Fixed - Cleanup of cargo features/dependencies to improve build times - Serde serialization with optional values. Attention: This changes the format of the serialization! - `VideoEncoder`/`VideoDecoder` `proxy_getcaps()` can't return `None` - Use non-panicking UTF8 conversion in log handler. We don't want to panic just because some C code printed a non-UTF8 string - Re-rexport all traits from the crate level and also ensure that all traits are actually included in the preludes - Actually export `is_video_overlay_prepare_window_handle_message()` function - Use `FnMut` for the `appsink` callbacks instead of `Fn` - `Promise` change function returns the actual reply to the promise now instead of just passing the promise itself - Memory leak in `Iterator::filter()` - `BinImpl::add()` takes ownership of floating references - `DeviceImpl::create_element()` preserves floating flag - `BinImpl::remove()` takes a strong reference of the element now as the last reference might be owned by the bin and otherwise we would potentially have a use-after-free afterwards - `BaseParseFrame` and `VideoCodecFrame` take a `&mut self` now for various functions that actually change the frame ### Changed - Minimum supported Rust version is 1.39 - Allow passing `None` to `VideoEncoder::finish_frame()` - Various `to_string()` methods were moved into the `Display` trait impl and for some types `to_str()` was added to return a `&'static str` - .gir files were updated to 1.16.2 release - `Sample` constructor uses the builder pattern now - `VideoMeta::add_full()` is simplified and requires parameters - `BasetransformImpl::set_caps()` returns a `Result` instead of `bool` - SDP data type getters for strings return an `Option` now as these can be `None` in practice although not allowed by the SDP spec - Various functions returning `Option`s were changed to return `Results` if `None` actually signalled an error instead of just a missing value ### Removed - "subclassing" and "futures" cargo features. These are enabled by default now ## [0.14.5] - 2019-09-17 ### Added - Support subclassing of `gst::Device`, `gst::DeviceProvider`, `gst_audio::AudioDecoder` and `::AudioEncoder` - Support for `Element::set_clock` and `::provide_clock` virtual methods - `ElementClass::add_metadata` was added - `gst_video::VideoDecoder` and `::VideoEncoder` got support for `get_caps`, `negotiate`, `src/sink_query/event` and the `drain` virtual methods - `Element::num_pads`, `::num_src_pads` and `::num_sink_pads` functions - `gst_video::VideoDecoder` and `::VideoEncoder` got `get_allocator` bindings - `gst::Iterator` implements `IntoIterator` now for providing `std::iter::Iterator>` adapter - Error macros for audio/video decoder subclasses to handle decoding errors more gracefully and only actually error out after many consecutive errors ### Fixed - Macros now also work in Rust 2018 edition without `#[macro_use]` but explicit imports - The log handler unit test runs reliable in parallel with other tests - Manually implement `Debug` for `gst::Iterator` to allow it for any `T` instead of `T: Debug` - `Device::create_element` has correct reference count handling now - Return `NotNegotiated` in the video codec base classes if setting the output state fails instead of `Error` ## [0.14.4] - 2019-08-14 ### Added - Bindings for adding/removing custom log functions - Bindings for `calculate_linear_regression()` - Constants for base class custom flow returns ### Fixed - Ownership of pad in `Element::release_pad()` virtual method implementations ## [0.14.3] - 2019-07-16 ### Added - `Buffer::unset_flags()` for unsetting specific buffer flags - `VideoBufferFlags` flags type and `VideoBufferExt::set_video_flags()`, `unset_video_flags()` and `get_video_flags()` for working with video buffer flags from safe code. ### Fixed - Setting buffer flags does not override arbitrary other flags anymore but only sets the flags in question. This is necessary to not override extension buffer flags like `gst_video::VideoBufferFlags`. ## [0.14.2] - 2019-07-15 ### Added - Support for `ReferenceTimestampMeta` ## [0.14.1] - 2019-07-06 ### Added - Various new WebRTC enum types from 1.14.1/1.16.0 ### Fixed - Correctly generate interlaced `VideoInfo` by using `gst_video_info_set_interlaced_format()` instead of the generic function. - serde serialization unit tests for `gst::format` succeed again now. ### Changed - `Debug` impls for `VideoFormatInfo` and `AudioFormatInfo` now print all the details of the format instead of only the name, and the `Debug` impls for `VideoInfo` and `AudioInfo` also print the format now. ## [0.14.0] - 2019-06-24 ### Added - Bindings for `GLSyncMeta`. - Bindings for setting/getting `TagScope` on a `TagList` - Bindings for `GLDisplayWayland` and `GLDisplayX11` in addition to the already existing `GLDisplayEGL` - Bindings for `Bus::pop_filtered()` and related functions - Bindings for getting/setting `Object`, `Element`, `Bin`, `Pipeline` and `Plugin` flags - Bindings for `VideoCaptionMeta` - `Debug` impl of `Buffer` now also shows the metas of the buffers - Expose flow return in `PadProbeInfo` for overriding the return value - Bindings for `VideoDecoder` and `VideoEncoder`, including subclassing support - Bindings for `Memory`, `Allocator` and `VideoBufferPool` - Bindings for `VideoFormatInfo::pack` and `::unpack` for format conversion - Bindings for `BaseParse`, including subclassing support - Various new arithmetic operation impls for fractions, formatted values and `ClockTime` - Bindings for `VideoInfo::align()` ### Changed - The `SDPMessage` and `SDPMedia` bindings were completely rewritten as they were broken before and caused crashes in various usages. As part of this there's also some more convenience API available on these types, like iterators for example, and API to modify the `SDPMedia` contained in a `SDPMessage`. - Update to GStreamer 1.16. - Regenerate with latest gir. - Run all autogenerated code through rustfmt after generation too. - Updated to latest versions of GLib/GIO/etc crates. - Updated to futures 0.3 / `std::future` - `ProxyPad` default functions moved to an extension trait instead of plain functions on `ProxyPad`, making them more in sync with the default `Pad` functions - GStreamer plugins are now exporting the new 1.14+ plugin symbols if they were configured for GStreamer 1.14+ - Arithmetic operations on formatted values and `ClockTime` do overflow checks now and replace the result with the `NONE` value on overflow - `TryFrom`/`TryInto` traits are used in various places now instead of the previous ad-hoc implementations of them. - Registering element/typefind/device monitor factories requires passing a value of `gst::Rank` now instead of an arbitrary `u32` ### Fixed - Use correct type for destroying pad task closure data. This was previously using the wrong type, causing crashes at runtime. - `DeviceAdded`/`DeviceRemoved` message getters are transfer full so we don't need to take an additional reference that would be leaked. - `AppSink` callbacks are correctly marked as `Send` instead of `Send+Sync`, allowing a wider range of closures to be used for them. - Handle `PadProbeReturn::Handled` return values from pad probes more correctly. - `ToOwned::to_owned()` on miniobjects has to create copies instead of only increasing the reference count. Otherwise it was possible to create multiple mutable and immutable references to the same object at the same time. - Various functions take references to owned miniobjects instead of borrowed references as it was otherwise possible to create multiple mutable or immutable references to the same object at the same time. - `URIHandler::set_uri` does not accept `None` anymore as this is not allowed by the C function. - Comparisons and addition of `TypeFindProbability` and `Rank` work correctly now - Various `Display` implementations were fixed to not cause a stack overflow due to infinite recursion anymore - Various `::to_string()` functions don't take ownership of C strings anymore that they do not own, which caused double frees before ### Removed - MIKEY related bindings from the SDP library. The bindings were broken and until someone needs them these are not available anymore. ## [0.13.0] - 2019-02-22 ### Added - Subclassing infrastructure was moved directly into the bindings, making the `gst-plugin` crate deprecated. This involves many API changes but generally cleans up code and makes it more flexible. Take a look at the `gst-plugins-rs` crate for various examples. - Bindings for GStreamer GL library - Bindings for `CapsFeatures` and `Meta` - Bindings for `ParentBufferMeta, `VideoMeta` and `VideoOverlayCompositionMeta` - Bindings for `VideoOverlayComposition` and `VideoOverlayRectangle` - Bindings for `VideoTimeCode` - Bindings for `NetAddressMeta` - Bindings for registering custom tags - `UniqueFlowCombiner` and `UniqueAdapter` wrappers that make use of the Rust compile-time mutability checks and expose more API in a safe way, and as a side-effect implement `Sync` and `Send` now - `Bus::add_watch_local()` and `gst_video::convert_frame_async_local()` that allows to use a closure that does not implement `Send` but can only be called from the thread owning the main context. - More complete bindings for `Allocation` `Query` - `pbutils` functions for codec descriptions - `TagList::iter()` for iterating over all tags while getting a single value per tag. The old `::iter_tag_list()` function was renamed to `::iter_generic()` and still provides access to each value for a tag - `Bus::iter()` and `Bus::iter_timed()` iterators around the corresponding `::pop*()` functions - Getters for `VideoColorimetry` to access its fields - `Debug` impls for various missing types. - serde serialization of `Value` can also handle `Buffer` now - Extensive comments to all examples with explanations - Transmuxing example showing how to use `typefind`, `multiqueue` and dynamic pads - basic-tutorial-12 was ported and added ### Changed - Rust 1.31 is the minimum supported Rust version now - Update to latest gir code generator and glib bindings - Functions returning e.g. `gst::FlowReturn` or other "combined" enums were changed to return split enums like `Result` to allow usage of the standard Rust error handling. - Various functions and callbacks returning `bool` or `Option<_>` were changed to return a `Result<_, glib::BoolError>` or `Result<_, gst::LoggableError>` or `Result<_, gst::ErrorMessage>` for better integration with Rust's error handling infrastructure. - Some infallible functions returning `bool` were changed to return `()`. - `MiniObject` subclasses are now newtype wrappers around the underlying `GstRc` wrapper. This does not change the API in any breaking way for the current usages, but allows `MiniObject`s to also be implemented in other crates and makes sure `rustdoc` places the documentation in the right places. - `BinExt` extension trait was renamed to `GstBinExt` to prevent conflicts with `gtk::Bin` if both are imported - `Buffer::from_slice()` can't possible return `None` ### Fixed - `gst::tag::Album` is the album tag now instead of artist sortname - Return `0` for the channel mask corresponding to negative `AudioChannelPosition`s. - `PartialOrd` and related traits are implemented via pointer equality on `ClockId` instead of using the compare function. Two clock ids with the same timestamp are not necessarily the same. - Various functions that are actually fallible are now returning an `Option<_>`. - Various `clippy` warnings ## [0.12.2] - 2018-11-26 ### Fixed - PTP clock constructor actually creates a PTP instead of NTP clock ### Added - Bindings for GStreamer Editing Services - Bindings for GStreamer Check testing library - Bindings for the encoding profile API (encodebin) - VideoFrame, VideoInfo, AudioInfo, StructureRef implements Send and Sync now - VideoFrame has a function to get the raw FFI pointer - From impls from the Error/Success enums to the combined enums like FlowReturn - Bin-to-dot file functions were added to the Bin trait - gst_base::Adapter implements SendUnique now ### Changed - All references were updated from GitHub to freedesktop.org GitLab - Fix various links in the README.md - Link to the correct location for the documentation - Remove GitLab badge as that only works with gitlab.com currently ## [0.12.1] - 2018-09-21 ### Added - More complete bindings for the gst_video::VideoOverlay interface, especially gst_video::is_video_overlay_prepare_window_handle_message() ## [0.12.0] - 2018-09-08 ### Added - Bindings for the GStreamer SDP and WebRTC libraries - Generic API for working with tags that is based on string tag names and glib::Value for the tag values - Bindings for Aggregator and AggregatorPad - Bindings for BaseTransform/BaseSrc::get_buffer_pool() - Optional serde implementations for the basic GStreamer data flow and metadata types ### Changed - Use ptr::NonNull in various places - Updated to muldiv 0.2, num-rational 0.2 - Bus::create_watch() can't return None - Remove CallbackGuard as unwinding across FFI boundaries is not undefined behaviour anymore but will directly cause a panic - Changed from the futures to the futures-preview crate as an optional dependency - Various Caps operations take a &CapsRef instead of &Caps - "deep-notify" signal takes the whole ParamSpec as parameter instead of only the signal name - Some structs were changed from empty struct to empty enums - Pad probe code does not take an additional reference to the data anymore, potentially passing writable events/buffers into the probe - ValueExt::compare() is implemented around std::cmp::Ordering now instead of a custom enum that was basically the same ### Fixed - Pad::add_probe() can return None if an IDLE probe was already called and removed in the meantime - Various compiler and clippy warnings ### Removed - std::Iterator impl for gst::Iterator. It was awkward to use because the gst::Iterator could fail at each iteration ## [0.11.6] - 2018-08-27 ### Fixed - Build with NLL/two-phase borrows - Explicitly define [bin] section for discoverer example to fix a cargo warning ### Added - Add unsafe gst::deinit() function - Ord/PartialOrd impls on gst::Seqnum - Getter for current pad mode - gst::Pad::sticky_events_foreach() for iterating over all sticky events in a thread-safe way ## [0.11.5] - 2018-07-24 ### Fixed - `gst::Bus`'s sync handler must unref every message if `gst::BusSyncReply::Drop` is returned, otherwise they are all leaked ## [0.11.4] - 2018-07-19 ### Fixed - `gst::Caps::subtract()` does not leak its arguments anymore - `gst::Caps::get_structure()` gracefully returns `None` if the index is out of bounds instead of a `g_return_val_if_fail()` - `gst::Structure::new()` has to give away ownership of the info structure but didn't. For 0.11 we internally copy, in 0.12 it will take the info structure by value - Typefind tests don't fail anymore if the system has typefind factories without caps ### Added - An additional assertion that ensures that miniobjects are actually writable before creating a mutable reference ## [0.11.3] - 2018-06-08 ### Added - `gst::Bus::remove_watch()` is now available to remove a bus watch again - `fmt::Debug` impls for `AudioInfo` and `VideoInfo` were added - `fmt::Debug` impls for mini objects also print the pointer value now to make it easier to track them in debug logs - `PlayerVisualization` has accessors for the name and description fields now, without which there is no sensible way to use them or to set a player visualization ## [0.11.2] - 2018-05-09 ### Fixed - Work-around various floating reference handling changes between 1.12 and 1.14 to be able to run with both versions without memory leaks or other reference count problems. This affects NetTimeProvider, BufferPool, DeviceMonitor, Stream, StreamCollection, and Player, NetClientClock, NetClock, PtpClock which were already previously fixed. ### Changed - Change the appsrc need-data and all appsink callbacks to not require the Sync bound anymore and change from Fn to FnMut. They can only be called from a single thread at a time. This change is only done for the corresponding callbacks, not the signals. ## [0.11.1] - 2018-04-07 ### Fixed - Fix Structure::to_string() to not run into an infinite recursion but call the method on the contained StructureRef instead of on itself ## [0.11.0] - 2018-03-20 ### Changed - Updated everything to GStreamer 1.14.0 - Event, Message and Query types were refactored to improve usability. Especially newly constructed queries allow to directly use the type-specific functions to be used without first creating a view - VideoFrameRef::copy_to_ref() and ::copy_plane_to_ref() are gone now and the original functions work with refs instead of full frames - PadProbeId and NotifyIds are not Copy/Clone anymore and are taken by value - GstPlayer has GstObject as parent class now ### Added - GstPbutils, GstSdp, GstRtsp and GstRtspServer bindings - GstPromise, GstAudioStreamAlign and various other 1.14 API - GstVideoFilter and GstBufferPool bindings - Element::call_async() - Debug impl For Toc and TocEntry - Various new examples (RTP FEC, RTSP server, tag usage, ...) ### Fixed - Memory leak in gst_video::convert_sample_async() ## [0.10.2] - 2018-02-18 ### Fixed - Fix building of messages with custom fields for types that don't have a GstStructure ### Added - VideoFrameRef::copy_to_ref() and ::copy_plane_to_ref(), which work with VideoFrameRefs instead of full VideoFrames - Getters for the BaseSrc/Sink/Transform configured segment - Document the gstreamer-player-1.0 dependency in the README.md ## [0.10.1] - 2018-01-03 ### Fixed - Don't require &mut self for TagSetterExtManual::add() ### Added - A TagSetter example application - Bindings for gst_video::convert_sample() and ::convert_sample_async() - Bindings for gst_video::VideoRectangle - Debug impl for Sample and ::with_buffer_list() constructor - A borrowing version of VideoFrame: VideoFrameRef - Bindings for GstVideoFilter ### Changed - Deprecated Sample::get_info() in favour of ::get_structure() - Player has gst::Object as another parent class now ## [0.10.0] - 2017-12-22 ### Fixed - Various clippy warnings - Memory leak of the tag list in Toc::merge_tags() - Property getters use Values of the correct type - Event::get_structure(), Message::get_structure() and Query::get_structure() can return None for the structure - Various other nullability fixes all over the API, changing functions to accept Option<> or returning Option<>, or only plain types - Functions taking paths/filenames now actually take Paths instead of &strs - Element::remove_pad() is not giving away a new reference to the pad anymore, which caused a memory leak of all pads ever removed - Precision handling in ClockTime's Display impl - Video/AudioInfo are only Send, not Sync ### Added - Various enums now also derive useful traits like Copy, Clone and Hash in addition to PartialEq, Eq and Debug - TagList::merge() and insert() for combining tag lists - EventType gained many useful functions to work with event types and a PartialOrd impl to check expected event order of event types where it matters - MessageRef/EventRef/QueryRef implement ToOwned - Bindings for Registry and PluginFeature - Event::set_running_time_offset() for adjusting the offset while events pass through the pipeline - Event/Message GroupIds and Seqnums now have a newtype wrapper around u32 instead of the plain value, making usage of them slightly more typesafe. Also add an "invalid" value for both, as exists in latest GStreamer now. - FormattedValue, GenericFormattedValue and related types were implemented now, which allows more convenient and type-safe usage of formatted values (time, bytes, etc) - Bindings for force-keyunit and still-frame events were added - MappedBuffer/BufferMap now implement various other useful traits, including AsRef<[u8]>, AsMut, Deref, DerefMut, Debug, PartialEq and Eq - Add VideoMultiviewFramePacking enum, and use it in Player - Bindings for the GStreamer Net library, including PTP/NTP/network client clocks and the GStreamer NetClock provider for network synchronization of pipelines - IteratorError implements std::error:Error - Plugin::add_dependency() and ::add_dependency_simple() was added - Rank and TypeFindProbability implement PartialOrd/Ord now - Bindings for TypeFind, TypeFindFactory and the typefind helpers - StreamCollection::iter() for iterating over all contained streams - ErrorMessage type that can be used e.g. in a Result for passing an error message from somewhere to upper layers to then be posted on an element the same way gst_element_error!() would've done ### Changed - Sample::new(), TagList::add(), Structure::set() and similar functions take the values (ToSendValue impls) by reference instead of value. They were not consumed by the function before. - The Debug impls of various types, including Event/Buffer/Message/Query/Structure were improved to print all the fields, similar to what GST_PTR_FORMAT would do in C - Switched to lazy_static 1.0 - Gap event and Duration tag are using ClockTimes now, as well as various Player signals - Segment is now based on a generic type FormattedSegment that can take any format (time, bytes, etc) or a GenericFormattedValue for more type-safety and convenience. Also functions for "casting" between a generic segment and a segment with a specific format exist on this now - AppSrc and AppSink now have a builder for the callbacks, making it unnecessary to always provide all callbacks even if only one is actually needed - Various functions that returned bool for errors, are now returning a Result - Player configuration is now a custom type with more convenient API - Player VideoInfo uses a Fraction instead of (u32,u32) for the framerate and pixel-aspect-ratio - VideoFrame API has more consistent API between writable and read-only variants - Buffer::copy_into() was added, and ::copy_region() now takes a BufferCopyFlags parameter instead of always using the default flags - ChildProxy::set_child_property() takes a &ToValue now to follow the API of Object::set_property() and improve usability - Proxy/GhostPad default pad functions use the correct specific pad type now instead of a generic Pad - Bus::add_signal_watch_full() takes a Priority for the priority instead of u32 - Clock::(un)adjust_with_calibration() takes no clock parameter anymore ### Removed - FormatValue was removed in favour of GenericFormattedValue and the connected traits and specific format impls ## [0.9.1] - 2017-11-26 ### Fixed - Export `FlowError`/`FlowSuccess`, `ClockError`/`ClockSuccess`, `PadLinkError`/`PadLinkSuccess` too ## [0.9.0] - 2017-11-26 ### Added - Bindings for (outputting to) the GStreamer logging system - Bindings for the GStreamer base library - Bindings for all the `Pad` functions to override pad behaviour, and pad task functions - Bindings for `StaticCaps` and `StaticPadTemplate` - Bindings for `deep-notify` signal on `Object` - Support for directly creating `Error`/`Warning`/`Info` `Messages` and posting them from an element with context information (file, line, module, etc.) similar to the C `GST_ELEMENT_ERROR` macro - Support for setting custom fields in `Messages`/`Events` during construction - Support for creating Buffers out of anything that is `AsRef<[u8]>` or `AsMut<[u8]>` - Support for using the `Read` trait on `Adapter` - Functions for getting all sink/src/all pads of an `Element`, and all children of a `Bin` - Builder for `Caps` and `Structures` in addition to the existing functions - `AppSrc`/`AppSink` implement `BaseSrc`/`BaseSink` and `URIHandler` - Rust ports of the basic tutorials 1 to 8 from https://gstreamer.freedesktop.org/documentation/tutorials/ - "Getting started" and "Installation" sections to the README.md - "dox" feature for generating documentation for all available configurations ### Fixed - `StackTraceFlags` are only available since 1.12 - Worked around macOS requiring a `NSRunLoop` running on the main thread in all examples and tutorials, to be able to show a window or anything else ### Changed - `ClockTime` is now a wrapper around `Option` to handle the `CLOCK_TIME_NONE` case better. This wrapper implements all the arithmetic and other traits as needed and ensures that no accidental calculations with `CLOCK_TIME_NONE` can happen - "Values with format", like in `Duration`/`Position`/`Convert` queries or `Seek` events now return a `FormatValue` type. This contains the actual `Format` together with the value and does any required conversions. This also makes it harder to accidentally mix e.g. values in bytes and time - `PadProbeId` does not implement `Clone`/`Copy` anymore - Property notify watches return a custom type instead of ulong - `Error`/`Warning`/`Info` `Messages` can only be created with specific kinds of `glib::Error` now. Using arbitrary ones does not work - `Iterator` bindings were completely rewritten and provide the item type as a generic type parameter now, greatly simplifying its usage - All `glib::Values` are now `glib::SendValue` instead, e.g. in `Caps` and `Structures`, as their content must be possible to send to different threads safely - `Message::get_src()` can return `None` - Allow `None` as `Caps` in `AppSrc`/`AppSink` - Allow everything implementing `Into>` to be used as a pad name - Moved `copy()` from `GstRc` directly to `MiniObject` - Success/Error enums (like `FlowReturn`, `PadLinkReturn`, `StateChangeReturn`) now implement an `into_result()` function that splits them into a `Result` with the good and bad cases. Also mark them as `#[must_use]` to make it harder to accidentally ignore errors. - Error enums implement the `Error` trait - Many examples use the `failure` crate for error handling now, cleaning up the error handling code quite a bit - Lots of other code cleanup, compiler/clippy warning cleanup, etc. ## [0.8.2] - 2017-11-11 ### Fixed - Implement StaticType of BufferRef instead of Buffer. Buffer aka GstRc already implements StaticType if BufferRef does, and without this it was not possible to use Buffers in GValues. - Free memory of the appsink/appsrc callbacks with the correct type. It was crashing because of using the wrong type before. - Fix documentation URLs in Cargo.toml. ### Added - Installation instructions and links to documentation for getting started to README.md. ## [0.8.1] - 2017-09-15 ### Added - Implement Send+Sync for Query, Message and Event, and their corresponding Ref types. ### Fixed - Constructor for gst_player::Player now works properly with GStreamer 1.12 when passing a video renderer or signal dispatcher. There was a reference counting bug. - Instead of returning &'static references from functions, return references with a generic, unbound lifetime instead. See https://github.com/rust-lang/rust/pull/42417#issue-233404573 - Various "unused external crate" warnings and clippy warnings everywhere. ### Changed - Remove Cargo.lock from GIT, it's not very useful for library crates. - Run everything through latest rustfmt-nightly. - Use while-let (instead of loop and if-let) and CLOCK_TIME_NONE (instead of u64::MAX) in the examples. ## 0.8.0 - 2017-08-31 - Initial release of the autogenerated GStreamer bindings. Older versions (< 0.8.0) of the bindings can be found [here](https://github.com/arturoc/gstreamer1.0-rs). The API of the two is incompatible. [Unreleased]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.23.5...HEAD [0.23.5]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.23.4...0.23.5 [0.23.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.23.3...0.23.4 [0.23.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.23.2...0.23.3 [0.23.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.23.1...0.23.2 [0.23.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.23.0...0.23.1 [0.23.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.22.6...0.23.0 [0.22.6]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.22.5...0.22.6 [0.22.5]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.22.4...0.22.5 [0.22.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.22.3...0.22.4 [0.22.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.22.2...0.22.3 [0.22.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.22.1...0.22.2 [0.22.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.22.0...0.22.1 [0.22.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.21.3...0.22.0 [0.21.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.21.2...0.21.3 [0.21.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.21.1...0.21.2 [0.21.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.21.0...0.21.1 [0.21.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.20.7...0.21.0 [0.20.7]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.20.6...0.20.7 [0.20.6]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.20.5...0.20.6 [0.20.5]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.20.4...0.20.5 [0.20.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.20.3...0.20.4 [0.20.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.20.2...0.20.3 [0.20.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.20.1...0.20.2 [0.20.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.20.0...0.20.1 [0.20.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.19.8...0.20.0 [0.19.8]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.19.7...0.19.8 [0.19.7]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.19.6...0.19.7 [0.19.6]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.19.5...0.19.6 [0.19.5]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.19.4...0.19.5 [0.19.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.19.3...0.19.4 [0.19.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.19.2...0.19.3 [0.19.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.19.1...0.19.2 [0.19.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.19.0...0.19.1 [0.19.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.18.8...0.19.0 [0.18.8]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.18.7...0.18.8 [0.18.7]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.18.6...0.18.7 [0.18.6]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.18.5...0.18.6 [0.18.5]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.18.4...0.18.5 [0.18.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.18.3...0.18.4 [0.18.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.18.2...0.18.3 [0.18.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.18.1...0.18.2 [0.18.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.18.0...0.18.1 [0.18.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.17.4...0.18.0 [0.17.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.17.3...0.17.4 [0.17.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.17.2...0.17.3 [0.17.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.17.1...0.17.2 [0.17.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.17.0...0.17.1 [0.17.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.16.7...0.17.0 [0.16.7]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.16.6...0.16.7 [0.16.6]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.16.5...0.16.6 [0.16.5]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.16.4...0.16.5 [0.16.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.16.3...0.16.4 [0.16.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.16.2...0.16.3 [0.16.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.16.1...0.16.2 [0.16.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.16.0...0.16.1 [0.16.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.7...0.16.0 [0.15.7]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.6...0.15.7 [0.15.6]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.5...0.15.6 [0.15.5]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.4...0.15.5 [0.15.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.3...0.15.4 [0.15.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.2...0.15.3 [0.15.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.1...0.15.2 [0.15.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.15.0...0.15.1 [0.15.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.2...0.15.0 [0.14.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.1...0.14.2 [0.14.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.14.0...0.14.1 [0.14.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.13.0...0.14.0 [0.13.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.12.2...0.13.0 [0.12.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.12.1...0.12.2 [0.12.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.12.0...0.12.1 [0.12.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.11.6...0.12.0 [0.11.6]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.11.5...0.11.6 [0.11.5]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.11.4...0.11.5 [0.11.4]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.11.3...0.11.4 [0.11.3]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.11.2...0.11.3 [0.11.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.11.1...0.11.2 [0.11.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.11.0...0.11.1 [0.11.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.10.2...0.11.0 [0.10.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.10.1...0.10.2 [0.10.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.10.0...0.10.1 [0.10.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.9.1...0.10.0 [0.9.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.9.0...0.9.1 [0.9.0]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.8.1...0.9.0 [0.8.2]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.8.1...0.8.2 [0.8.1]: https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/compare/0.8.0...0.8.1 gstreamer-0.23.5/COPYRIGHT000064400000000000000000000022331046102023000131770ustar 00000000000000The gstreamer-rs project is dual-licensed under Apache 2.0 and MIT terms, with the exception of the sys crates which are licensed only under the terms of the MIT license. Copyrights in the gstreamer-rs project are retained by their contributors. No copyright assignment is required to contribute to the gstreamer-rs project. Some files include explicit copyright notices and/or license notices. For full authorship information, see the version control history. Except as otherwise noted (below and/or in individual files), gstreamer-rs is licensed under the Apache License, Version 2.0 or or the MIT license or , at your option. All the sys crates (e.g. gstreamer/sys and gstreamer-base/sys) are licensed only under the terms of the MIT license. This project provides interoperability with various GStreamer libraries but doesn't distribute any parts of them. Distributing compiled libraries and executables that link to those libraries may be subject to terms of the GNU LGPL or other licenses. For more information check the license of each GStreamer library. gstreamer-0.23.5/Cargo.lock0000644000000404330000000000100110730ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "autocfg" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "base64" version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] [[package]] name = "cfg-expr" version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789" dependencies = [ "smallvec", "target-lexicon", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "futures-channel" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", ] [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-macro" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "futures-task" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-macro", "futures-task", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "gio-sys" version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "160eb5250a26998c3e1b54e6a3d4ea15c6c7762a6062a19a7b63eff6e2b33f9e" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", "windows-sys", ] [[package]] name = "gir-format-check" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a5da913a8586ce748f1164c890e1ebe75a7bbc472668f57b7f9fb893d7ac416" [[package]] name = "glib" version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707b819af8059ee5395a2de9f2317d87a53dbad8846a2f089f0bb44703f37686" dependencies = [ "bitflags", "futures-channel", "futures-core", "futures-executor", "futures-task", "futures-util", "gio-sys", "glib-macros", "glib-sys", "gobject-sys", "libc", "memchr", "smallvec", ] [[package]] name = "glib-macros" version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68" dependencies = [ "heck", "proc-macro-crate", "proc-macro2", "quote", "syn", ] [[package]] name = "glib-sys" version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8928869a44cfdd1fccb17d6746e4ff82c8f82e41ce705aa026a52ca8dc3aefb" dependencies = [ "libc", "system-deps", ] [[package]] name = "gobject-sys" version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c773a3cb38a419ad9c26c81d177d96b4b08980e8bdbbf32dace883e96e96e7e3" dependencies = [ "glib-sys", "libc", "system-deps", ] [[package]] name = "gstreamer" version = "0.23.5" dependencies = [ "cfg-if", "futures-channel", "futures-core", "futures-executor", "futures-util", "gir-format-check", "glib", "gstreamer-sys", "itertools", "libc", "log", "muldiv", "num-integer", "num-rational", "once_cell", "option-operations", "paste", "pin-project-lite", "ron", "serde", "serde_bytes", "serde_json", "smallvec", "thiserror", ] [[package]] name = "gstreamer-sys" version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16cf1ae0a869aa7066ce3c685b76053b4b4f48f364a5b18c4b1f36ef57469719" dependencies = [ "glib-sys", "gobject-sys", "libc", "system-deps", ] [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "libc" version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "muldiv" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "956787520e75e9bd233246045d19f42fb73242759cc57fba9611d940ae96d4b0" [[package]] name = "num-integer" version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ "num-traits", ] [[package]] name = "num-rational" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ "num-integer", "num-traits", "serde", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "option-operations" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c26d27bb1aeab65138e4bf7666045169d1717febcc9ff870166be8348b223d0" dependencies = [ "paste", ] [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pin-project-lite" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "proc-macro-crate" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] [[package]] name = "proc-macro2" version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "ron" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64", "bitflags", "serde", "serde_derive", ] [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] [[package]] name = "serde_derive" version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "system-deps" version = "7.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005" dependencies = [ "cfg-expr", "heck", "pkg-config", "toml", "version-compare", ] [[package]] name = "target-lexicon" version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "thiserror" version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f5383f3e0071702bf93ab5ee99b52d26936be9dedd9413067cbdcddcb6141a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f357fcec90b3caef6623a099691be676d033b40a058ac95d2a6ade6fa0c943" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "toml" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit", ] [[package]] name = "toml_datetime" version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow", ] [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "version-compare" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] gstreamer-0.23.5/Cargo.toml0000644000000060560000000000100111210ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.71.1" name = "gstreamer" version = "0.23.5" authors = ["Sebastian Dröge "] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Rust bindings for GStreamer" homepage = "https://gstreamer.freedesktop.org" documentation = "https://gstreamer.freedesktop.org/documentation/rust/stable/latest/docs/gstreamer/" readme = "README.md" keywords = [ "gstreamer", "multimedia", "audio", "video", "gnome", ] categories = [ "api-bindings", "multimedia", ] license = "MIT OR Apache-2.0" repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" [package.metadata.docs.rs] all-features = true rustc-args = [ "--cfg", "docsrs", ] rustdoc-args = [ "--cfg", "docsrs", "--generate-link-to-definition", ] [lib] name = "gstreamer" path = "src/lib.rs" [[test]] name = "check_gir" path = "tests/check_gir.rs" [dependencies.cfg-if] version = "1.0" [dependencies.futures-channel] version = "0.3" [dependencies.futures-core] version = "0.3" [dependencies.futures-util] version = "0.3" default-features = false [dependencies.glib] version = "0.20" [dependencies.gstreamer-sys] version = "0.23" [dependencies.itertools] version = "0.13" [dependencies.libc] version = "0.2" [dependencies.log] version = "0.4" optional = true [dependencies.muldiv] version = "1" [dependencies.num-integer] version = "0.1" features = [] default-features = false [dependencies.num-rational] version = "0.4" features = [] default-features = false [dependencies.once_cell] version = "1" [dependencies.opt-ops] version = "0.5" package = "option-operations" [dependencies.paste] version = "1.0" [dependencies.pin-project-lite] version = "0.2" [dependencies.serde] version = "1.0" features = ["derive"] optional = true [dependencies.serde_bytes] version = "0.11" optional = true [dependencies.smallvec] version = "1.0" features = ["write"] [dependencies.thiserror] version = "2" [dev-dependencies.futures-executor] version = "0.3.1" [dev-dependencies.gir-format-check] version = "0.1" [dev-dependencies.ron] version = "0.8" [dev-dependencies.serde_json] version = "1.0" [features] default = [] log = ["dep:log"] serde = [ "num-rational/serde", "dep:serde", "serde_bytes", ] v1_16 = ["gstreamer-sys/v1_16"] v1_18 = [ "gstreamer-sys/v1_18", "v1_16", ] v1_20 = [ "gstreamer-sys/v1_20", "v1_18", ] v1_22 = [ "gstreamer-sys/v1_22", "v1_20", ] v1_24 = [ "gstreamer-sys/v1_24", "v1_22", ] v1_26 = [ "gstreamer-sys/v1_26", "v1_24", ] gstreamer-0.23.5/Cargo.toml.orig000064400000000000000000000034611046102023000145770ustar 00000000000000[package] name = "gstreamer" authors = ["Sebastian Dröge "] description = "Rust bindings for GStreamer" license = "MIT OR Apache-2.0" readme = "README.md" keywords = ["gstreamer", "multimedia", "audio", "video", "gnome"] documentation = "https://gstreamer.freedesktop.org/documentation/rust/stable/latest/docs/gstreamer/" version.workspace = true categories.workspace = true repository.workspace = true homepage.workspace = true edition.workspace = true rust-version.workspace = true [dependencies] cfg-if = "1.0" libc = "0.2" gstreamer-sys.workspace = true glib.workspace = true num-integer = { version = "0.1", default-features = false, features = [] } num-rational = { version = "0.4", default-features = false, features = [] } futures-core = "0.3" futures-channel = "0.3" futures-util = { version = "0.3", default-features = false } log = { version = "0.4", optional = true } muldiv = "1" opt-ops = { package = "option-operations", version = "0.5" } serde = { version = "1.0", optional = true, features = ["derive"] } serde_bytes = { version = "0.11", optional = true } paste = "1.0" thiserror = "2" smallvec = { version = "1.0", features = ["write"] } itertools = "0.13" pin-project-lite = "0.2" once_cell = "1" [dev-dependencies] ron = "0.8" serde_json = "1.0" futures-executor = "0.3.1" gir-format-check = "0.1" [features] default = [] v1_16 = ["gstreamer-sys/v1_16"] v1_18 = ["gstreamer-sys/v1_18", "v1_16"] v1_20 = ["gstreamer-sys/v1_20", "v1_18"] v1_22 = ["gstreamer-sys/v1_22", "v1_20"] v1_24 = ["gstreamer-sys/v1_24", "v1_22"] v1_26 = ["gstreamer-sys/v1_26", "v1_24"] serde = ["num-rational/serde", "dep:serde", "serde_bytes"] log = ["dep:log"] [package.metadata.docs.rs] all-features = true rustc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] gstreamer-0.23.5/Gir.toml000064400000000000000000001545051046102023000133340ustar 00000000000000[options] girs_directories = ["../gir-files", "../gst-gir-files"] library = "Gst" version = "1.0" min_cfg_version = "1.14" work_mode = "normal" concurrency = "send+sync" generate_safety_asserts = true single_version_file = true generate_display_trait = false trust_return_value_nullability = true external_libraries = [ "GLib", "GObject", ] generate = [ "Gst.BufferingMode", "Gst.CapsIntersectMode", "Gst.ClockEntryType", "Gst.ClockTimeDiff", "Gst.DebugColorFlags", "Gst.DebugGraphDetails", "Gst.EventTypeFlags", "Gst.GapFlags", "Gst.ParseError", "Gst.PluginAPIFlags", "Gst.PluginError", "Gst.PluginFlags", "Gst.ProgressType", "Gst.PromiseResult", "Gst.QOSType", "Gst.SchedulingFlags", "Gst.StreamStatusType", "Gst.StreamType", "Gst.StructureChangeType", "Gst.SystemClock", "Gst.TaskState", "Gst.TocSetter", "Gst.URIError", "Gst.URIHandler", ] manual = [ "GLib.DateTime", "GLib.Error", "GLib.MainContext", "GLib.Quark", "GLib.Source", "GLib.Type", "GObject.Object", "GObject.Value", "Gst.AllocationParams", "Gst.CapsFeatures", "Gst.DebugCategory", "Gst.DebugMessage", "Gst.DeviceProviderClass", # for docs only "Gst.ElementClass", # for docs only "Gst.Rank", "Gst.Segment", "Gst.StaticCaps", "Gst.StaticPadTemplate", "Gst.TypeFind", ] [[object]] name = "Gst.*" status = "generate" # We'll opt-in for constants at a later time [[object.constant]] pattern = ".+" ignore = true [[object.function]] name = "util_dump_mem" ignore = true [[object.function]] name = "util_dump_buffer" # We have our Debug impl on buffers ignore = true [[object.function]] name = "protection_select_system" # unsupported array type ignore = true [[object.function]] name = "calculate_linear_regression" ignore = true [[object.function]] pattern = "value_.*" ignore = true [[object.function]] pattern = ".*_get_type" ignore = true [[object.function]] pattern = "tag_.*" ignore = true [[object.function]] pattern = "segtrap_.*" ignore = true [[object.function]] pattern = "util_[g]?double_.*" ignore = true [[object.function]] pattern = "util_fraction_.*" ignore = true [[object.function]] name = "util_simplify_fraction" ignore = true [[object.function]] pattern = "util_greatest_.*" ignore = true [[object.function]] pattern = "util_[g]?uint64.*" ignore = true [[object.function]] pattern = "util_(floor|ceil)_log2" ignore = true [[object.function]] name = "deinit" ignore = true [[object.function]] name = "util_set_object_arg" ignore = true [[object.function]] name = "util_seqnum_compare" ignore = true [[object.function]] name = "dynamic_type_register" ignore = true [[object.function]] name = "flow_get_name" ignore = true [[object.function]] name = "filename_to_uri" ignore = true [[object.function]] name = "is_initialized" ignore = true [[object.function]] name = "debug_add_log_function" ignore = true [[object.function]] name = "debug_remove_log_function" ignore = true [[object.function]] name = "debug_remove_log_function_by_data" ignore = true [[object.function]] name = "debug_construct_term_color" ignore = true [[object.function]] name = "debug_construct_win_color" ignore = true [[object.function]] name = "debug_get_all_categories" ignore = true [[object.function]] name = "debug_get_color_mode" ignore = true [[object.function]] pattern = "debug_log.*" ignore = true [[object.function]] name = "debug_set_color_mode" ignore = true [[object.function]] name = "debug_set_color_mode_from_string" ignore = true [[object.function]] name = "error_get_message" ignore = true [[object.function]] name = "flow_to_quark" ignore = true [[object.function]] name = "formats_contains" ignore = true [[object.function]] pattern = "info_.*" ignore = true [[object.function]] pattern = "print.*" ignore = true [[object.function]] pattern = "init.*" ignore = true [[object.function]] pattern = "param_spec_.*" ignore = true [[object.function]] name = "is_caps_features" ignore = true [[object.function]] name = "make_element_message_details" ignore = true [[object.function]] name = "util_array_binary_search" ignore = true [[object.function]] name = "util_get_object_array" ignore = true [[object.function]] name = "util_set_object_array" ignore = true [[object.function]] name = "util_set_value_from_string" ignore = true [[object.function]] pattern = "parse.*full" # wrong mutable for context parameter ignore = true [[object.function]] name = "update_registry" [object.function.return] bool_return_is_error = "Failed to update the registry" [[object.function]] name = "util_group_id_next" # newtype wrapper ignore = true [[object.function]] name = "util_seqnum_next" # newtype wrapper ignore = true [[object.function]] name = "protection_filter_systems_by_available_decryptors" # wrong array annotations ignore = true [[object.function]] pattern = "clear_.*" # C memory management ignore = true [[object.function]] name = "debug_print_object" # Can directly use the Debug impl ignore = true [[object.function]] name = "debug_print_segment" # Can directly use the Debug impl ignore = true [[object.function]] name = "debug_get_stack_trace" # can be called before gst_init() assertion = "skip" [object.function.return] nullable_return_is_error = "Failed to get stack trace" [[object.function]] name = "get_main_executable_path" [object.function.return] nullable_return_is_error = "Failed to get main executable path" [[object.function]] name = "debug_set_default_threshold" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_get_default_threshold" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_set_threshold_for_name" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_set_threshold_from_string" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_unset_threshold_for_name" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_print_stack_trace" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_is_active" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_is_colored" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_set_active" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_set_colored" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_add_ring_buffer_logger" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_remove_ring_buffer_logger" # can be called before gst_init() assertion = "skip" [[object.function]] name = "debug_ring_buffer_logger_get_logs" # can be called before gst_init() assertion = "skip" [[object.function]] name = "util_get_timestamp" # can be called before gst_init() assertion = "skip" [object.function.return] # always returns a value mandatory = true [[object.function]] name = "version" # can be called before gst_init() assertion = "skip" [[object.function]] name = "version_string" # can be called before gst_init() assertion = "skip" [[object.function]] name = "type_is_plugin_api" # We implement it in an extension Trait ignore = true [[object.function]] name = "tracing_register_hook" # implemented as part of Tracer subclassing manual = true [[object.function]] name = "tracing_get_active_tracers" rename = "active_tracers" # Use glib::List as return type manual = true [[object.function]] name = "type_mark_as_plugin_api" # Needs integration into subclassing infrastructure ignore = true [[object.function]] name = "util_filename_compare" # Convert return type to `Ordering` manual = true [[object.function]] name = "util_ceil_log2" # can be called before gst_init() assertion = "skip" [[object]] name = "Gst.Allocator" status = "generate" [[object.function]] name = "register" # Steals the string name in < 1.20.5 manual = true [[object.function]] name = "alloc" [object.function.return] nullable_return_is_error = "Failed to allocate memory" [[object.function.parameter]] name = "params" const = true [[object]] name = "Gst.Bin" status = "generate" trait_name = "GstBinExt" [[object.function]] name = "new" # Remove the optional `name` argument in favor of using the builder manual = true [[object.signal]] name = "do-latency" # Use Result<(), glib::BoolError> manual = true [[object.function]] name = "add_many" # Implemented by repeatedly calling add() manual = true [[object.function]] name = "remove_many" # Implemented by repeatedly calling remove() manual = true [[object.function]] name = "iterate_all_by_element_factory_name" manual = true [[object.function]] name = "iterate_all_by_interface" manual = true [[object.function]] name = "iterate_elements" manual = true [[object.function]] name = "iterate_recurse" manual = true [[object.function]] name = "iterate_sinks" manual = true [[object.function]] name = "iterate_sorted" manual = true [[object.function]] name = "iterate_sources" manual = true [[object.function]] name = "add" [object.function.return] bool_return_is_error = "Failed to add element" [[object.function]] name = "remove" [object.function.return] bool_return_is_error = "Failed to remove element" [[object.function]] name = "recalculate_latency" [object.function.return] bool_return_is_error = "Failed to recalculate latency" [[object.function]] name = "sync_children_states" [object.function.return] bool_return_is_error = "Failed to sync children states" [[object]] name = "Gst.BinFlags" status = "generate" [[object.member]] name = "last" ignore = true [[object]] name = "Gst.Buffer" status = "manual" ref_mode = "ref" [[object.function]] name = "map" # Readable and writable variant dealing with mutability # Non-into variants available under BufferRef rename = "into_mapped_buffer_readable" [[object.function]] name = "unmap" ignore = true [[object]] name = "Gst.BufferCopyFlags" status = "generate" [[object.member]] name = "none" ignore = true [[object]] name = "Gst.BufferFlags" status = "generate" [[object.member]] name = "last" ignore = true [[object]] name = "Gst.BufferList" status = "manual" ref_mode = "ref" [[object]] name = "Gst.BufferPool" status = "generate" manual_traits = ["BufferPoolExtManual"] [[object.function]] pattern = "config_.*" # A different type ignore = true [[object.function]] name = "get_config" # A different type manual = true [[object.function]] name = "set_config" # Takes ownership manual = true [[object.function]] name = "acquire_buffer" # Params and return value manual = true [[object.function]] name = "set_active" [object.function.return] bool_return_is_error = "Failed to activate buffer pool" [[object]] name = "Gst.BufferPoolAcquireFlags" status = "generate" [[object.member]] name = "none" ignore = true [[object.member]] name = "last" ignore = true [[object]] name = "Gst.Bus" status = "generate" final_type = true [[object.function]] name = "set_sync_handler" # Into> makes this hard to use manual = true [[object.function]] name = "add_signal_watch_full" # Priority manual = true [[object.function]] name = "timed_pop_filtered" # Uses enum as flags manual = true [[object.function]] name = "pop_filtered" # Uses enum as flags manual = true [[object.function]] name = "poll" # Uses enum as flags manual = true [[object.function]] name = "create_watch" # More convenient manual implementation manual = true [[object.function]] name = "add_watch" # More specific trait bounds possible for the closure manual = true [[object.function]] name = "add_watch_full" # More specific trait bounds possible for the closure manual = true [[object.function]] name = "remove_watch" visibility = "crate" [object.function.return] bool_return_is_error = "Bus has no event source" [[object.signal]] name = "message" concurrency = "send" [[object.function]] name = "post" [object.function.return] bool_return_is_error = "Failed to post message" [[object]] name = "Gst.BusSyncReply" status = "generate" exhaustive = true [[object]] name = "Gst.Caps" status = "manual" ref_mode = "ref" [[object]] name = "Gst.ChildProxy" status = "generate" manual_traits = ["ChildProxyExtManual"] [[object.function]] name = "get_property" rename = "child_property" manual = true [[object.function]] name = "set_property" rename = "set_child_property" manual = true [[object.function]] name = "lookup" manual = true [[object]] name = "Gst.Clock" status = "generate" manual_traits = ["ClockExtManual"] [[object.function]] name = "adjust_with_calibration" # Associated function manual = true [[object.function]] name = "unadjust_with_calibration" # Associated function manual = true [[object.function]] name = "get_calibration" # Wrong types for the rate manual = true [[object.function]] name = "set_calibration" # Wrong types for the rate manual = true [[object.function]] name = "new_periodic_id" manual = true [[object.function]] name = "periodic_id_reinit" manual = true [[object.function]] name = "new_single_shot_id" manual = true [[object.function]] name = "single_shot_id_reinit" manual = true [[object.function]] name = "add_observation" [[object.function.parameter]] name = "observation_internal" mandatory = true [[object.function.parameter]] name = "observation_external" mandatory = true [[object.function]] name = "add_observation_unapplied" [[object.function.parameter]] name = "observation_internal" mandatory = true [[object.function.parameter]] name = "observation_external" mandatory = true [[object.function.parameter]] name = "internal" mandatory = true [[object.function.parameter]] name = "external" mandatory = true [[object.function.parameter]] name = "rate_num" mandatory = true [[object.function.parameter]] name = "rate_denom" mandatory = true [[object.function]] name = "adjust_unlocked" [[object.function.parameter]] name = "internal" mandatory = true [[object.function]] name = "get_internal_time" [object.function.return] mandatory = true [[object.function]] name = "get_resolution" [object.function.return] mandatory = true [[object.function]] name = "set_master" [object.function.return] bool_return_is_error = "Failed to set master clock" [[object.function]] name = "set_resolution" [[object.function.parameter]] name = "resolution" mandatory = true [object.function.return] mandatory = true [[object.function]] name = "unadjust_unlocked" [[object.function.parameter]] name = "external" mandatory = true [[object.function]] name = "wait_for_sync" [object.function.return] bool_return_is_error = "Timed out waiting for sync" [[object]] name = "Gst.ClockFlags" status = "generate" [[object.member]] name = "last" ignore = true [[object]] name = "Gst.ClockID" status = "manual" [[object.function]] name = "compare_func" rename = "compare_by_time" [[object]] name = "Gst.ClockReturn" status = "generate" must_use = true exhaustive = true [object.conversion_type] variant = "Result" ok_type = "ClockSuccess" err_type = "ClockError" [[object]] name = "Gst.ClockTime" status = "manual" conversion_type = "Option" [[object]] name = "Gst.ClockType" status = "generate" [[object.member]] name = "tai" version = "1.18" [[object]] name = "Gst.Context" status = "manual" ref_mode = "ref" [[object]] name = "Gst.ControlBinding" status = "generate" manual_traits = ["ControlBindingExtManual"] generate_builder = true [[object.function]] name = "get_g_value_array" manual = true [[object.function]] name = "get_value" [[object.function.parameter]] name = "timestamp" mandatory = true [[object.function]] name = "sync_values" [[object.function.parameter]] name = "timestamp" mandatory = true [[object]] name = "Gst.ControlSource" status = "generate" manual_traits = ["ControlSourceExtManual"] generate_builder = true [[object.function]] name = "control_source_get_value" rename = "value" [[object.function.parameter]] name = "timestamp" mandatory = true [[object.function]] name = "control_source_get_value_array" manual = true [[object]] name = "Gst.CoreError" status = "generate" [[object.member]] name = "num_errors" ignore = true [[object]] name = "Gst.DateTime" status = "generate" [[object.derive]] # Don't auto-implement traits name = "" [[object.function]] name = "new" # Needs manual checking of invariants manual = true [[object.function]] name = "new_local_time" # Needs manual checking of invariants manual = true [[object.function]] name = "new_y" # Needs manual checking of invariants manual = true [[object.function]] name = "new_ym" # Needs manual checking of invariants manual = true [[object.function]] name = "new_ymd" # Needs manual checking of invariants manual = true [[object.function]] name = "get_month" # Needs manual checking of invariants manual = true [[object.function]] name = "get_day" # Needs manual checking of invariants manual = true [[object.function]] name = "get_hour" # Needs manual checking of invariants manual = true [[object.function]] name = "get_minute" # Needs manual checking of invariants manual = true [[object.function]] name = "get_second" # Needs manual checking of invariants manual = true [[object.function]] name = "get_microsecond" # Needs manual checking of invariants manual = true [[object.function]] name = "get_time_zone_offset" # Needs manual checking of invariants manual = true [[object.function]] name = "new_from_g_date_time" # Function only ever returns NULL if the argument is NULL [[object.function.parameter]] name = "dt" nullable = false [object.function.return] nullable = false [[object.function]] name = "to_g_date_time" [object.function.return] nullable_return_is_error = "Can't create glib::DateTime from DateTime" [[object.function]] name = "new_from_iso8601_string" [object.function.return] nullable_return_is_error = "Failed to create DateTime from ISO-8601 string" [[object.function]] name = "to_iso8601_string" [object.function.return] nullable_return_is_error = "Failed to create ISO-8601 string from DateTime" [[object.function]] name = "new_from_unix_epoch_local_time" [object.function.return] nullable_return_is_error = "Can't create DateTime from UNIX epoch" [[object.function]] name = "new_from_unix_epoch_local_time_usecs" [object.function.return] nullable_return_is_error = "Can't create DateTime from UNIX epoch" [[object.function]] name = "new_from_unix_epoch_utc" [object.function.return] nullable_return_is_error = "Can't create DateTime from UNIX epoch" [[object.function]] name = "new_from_unix_epoch_utc_usecs" [object.function.return] nullable_return_is_error = "Can't create DateTime from UNIX epoch" [[object]] name = "Gst.DebugLevel" status = "generate" [[object.member]] name = "count" ignore = true [[object]] name = "Gst.Device" status = "generate" [[object.function]] name = "reconfigure_element" [object.function.return] bool_return_is_error = "Failed to reconfigure the element to use this device" [[object.function]] name = "create_element" [object.function.return] nullable_return_is_error = "Failed to create element for device" [[object]] name = "Gst.DeviceMonitor" status = "generate" manual_traits = ["DeviceMonitorExtManual"] [[object.function]] name = "add_filter" # Return Option manual = true [[object.function]] name = "start" [object.function.return] bool_return_is_error = "Failed to start" [[object.function]] name = "remove_filter" # Use DeviceMonitorFilterId and return Result<(), glib::BoolError> manual = true [[object.function]] name = "get_devices" # Use glib::List as return type manual = true [[object]] name = "Gst.DeviceProvider" status = "generate" manual_traits = ["DeviceProviderExtManual"] [[object.function]] name = "start" [object.function.return] bool_return_is_error = "Failed to start" [[object.function]] name = "register" manual = true [[object.function]] name = "get_metadata" # better manual function manual = true [[object.function]] name = "get_devices" # Use glib::List as return type manual = true [[object]] name = "Gst.DeviceProviderFactory" status = "generate" final_type = true [[object.function]] name = "list_get_device_providers" rename = "factories" # Use glib::List as return type manual = true [[object.function]] name = "get_metadata" # Use str as return type manual = true [[object]] name = "Gst.Element" status = "generate" manual_traits = ["ElementExtManual"] # Manual implementation provides associated functions on `Element`, # but gir considers these methods on `ElementExtManual` in the docs. [[object.function]] name = "link_many" manual = true [[object.function]] name = "unlink_many" manual = true [[object.function]] name = "register" manual = true [[object.function]] name = "call_async" # more specific closure type possible manual = true [[object.function]] name = "set_base_time" [[object.function.parameter]] name = "time" mandatory = true [[object.function]] name = "get_current_running_time" # manual implementation also works for earlier versions manual = true [[object.function]] name = "get_current_clock_time" # manual implementation also works for earlier versions manual = true [[object.function]] name = "get_request_pad" # rename to more explicit name and avoid conflict with `request_pad` rename = "request_pad_simple" # Renamed version is not deprecated manual = true [[object.function]] name = "request_pad_simple" # see above manual = true [[object.function]] name = "post_message" [object.function.return] bool_return_is_error = "Failed to post message" [[object.function]] name = "add_pad" [object.function.return] bool_return_is_error = "Failed to add pad" [[object.function]] name = "remove_pad" [object.function.return] bool_return_is_error = "Failed to remove pad" # Manual implementations with better error reporting [[object.function]] name = "link" manual = true [[object.function]] name = "link_filtered" manual = true [[object.function.parameter]] name = "filter" # Can use `link` instead nullable = false [[object.function]] name = "link_pads" manual = true [[object.function]] name = "link_pads_filtered" manual = true [[object.function.parameter]] name = "filter" # Can use `link` instead nullable = false [[object.function]] name = "link_pads_full" manual = true [[object.function]] name = "set_clock" [object.function.return] bool_return_is_error = "Failed to set clock" [[object.function]] name = "sync_state_with_parent" [object.function.return] bool_return_is_error = "Failed to sync state with parent" [[object.function]] name = "query" # correct mutability manual = true [[object.function]] name = "send_event" # Pass by value manual = true [[object.function]] name = "get_context_unlocked" # Unsafe ignore = true [[object.function]] name = "add_property_deep_notify_watch" # ulong manual = true [[object.function]] name = "add_property_notify_watch" # ulong manual = true [[object.function]] name = "remove_property_notify_watch" # ulong manual = true [[object.function]] name = "query_duration" # formatted value manual = true [[object.function]] name = "query_position" # formatted value manual = true [[object.function]] name = "query_convert" # formatted value manual = true [[object.function]] name = "seek" # formatted value manual = true [[object.function]] name = "seek_simple" # formatted value manual = true [[object.function]] name = "state_change_return_get_name" # Wrong place ignore = true [[object.function]] name = "state_get_name" # Wrong place ignore = true [[object.function]] name = "get_metadata" # better manual function manual = true [[object.function]] name = "get_pad_template" # better manual function manual = true [[object.function]] name = "get_pad_template_list" # better manual function manual = true # Limited subset of `MessageType`, # see `ElementMessageType`. [[object.function]] name = "message_full" manual = true [[object.function]] name = "message_full_with_details" manual = true # Return iterators [[object.function]] name = "iterate_pads" manual = true [[object.function]] name = "iterate_sink_pads" manual = true [[object.function]] name = "iterate_src_pads" manual = true [[object.function]] name = "type_set_skip_documentation" # Needs integration into subclassing infrastructure ignore = true [[object.function]] name = "decorate_stream_id_printf" # Varargs ignore = true [[object.function]] name = "decorate_stream_id_printf_valist" # Varargs ignore = true [[object]] name = "Gst.ElementFactory" status = "generate" final_type = true [[object.function]] name = "create" rename = "create_with_name" manual = true [[object.function]] name = "make" rename = "make_with_name" manual = true [[object.function]] name = "create_full" # varargs ignore = true [[object.function]] name = "create_valist" # varargs ignore = true [[object.function]] name = "create_with_properties" # separate name/value arrays need to be merged manual = true [[object.function]] name = "make_full" # varargs ignore = true [[object.function]] name = "make_valist" # varargs ignore = true [[object.function]] name = "make_with_properties" # separate name/value arrays need to be merged manual = true [[object.function]] name = "get_static_pad_templates" # Use glib::List as return type manual = true [[object.function]] name = "list_is_type" rename = "has_type" # Renamed flags type manual = true [[object.function]] name = "list_filter" # can_{sink,src}_{all,any}_caps() around an iterator is the same ignore = true [[object.function]] name = "list_get_elements" rename = "factories_with_type" # Use glib::List as return type manual = true [[object.function]] name = "get_metadata" # Use str as return type manual = true [[object.function]] name = "can_sink_all_caps" # Use &CapsRef manual = true [[object.function]] name = "can_src_all_caps" # Use &CapsRef manual = true [[object.function]] name = "can_sink_any_caps" # Use &CapsRef manual = true [[object.function]] name = "can_src_any_caps" # Use &CapsRef manual = true [[object]] name = "Gst.ElementFactoryListType" status = "manual" conversion_type = "scalar" [[object]] name = "Gst.ElementFlags" status = "generate" [[object.member]] name = "last" ignore = true [[object]] name = "Gst.Event" status = "manual" ref_mode = "ref" [[object.function]] name = "new_caps" # Moved to CapsBuilder::new() ignore = true [[object.function]] name = "new_qos" # Moved to QosBuilder::new() ignore = true [[object.function]] name = "new_seek" # Moved to SeekBuilder::new() ignore = true [[object.function]] name = "parse_stream" # Moved to StreamStart::stream() ignore = true [[object.function]] name = "parse_stream_start" # Moved to StreamStart::stream_id() ignore = true [[object]] name = "Gst.EventType" status = "generate" [[object.function]] name = "to_sticky_ordering" # handle this manually via the `PartialOrd` function ignore = true [[object.derive]] name = "Debug, PartialEq, Eq, Hash" [[object.member]] name = "instant_rate_change" version = "1.18" [[object.member]] name = "instant_rate_sync_time" version = "1.18" [[object]] name = "Gst.FlowReturn" # mapping unknown values to defaults status = "manual" must_use = true exhaustive = true [object.conversion_type] variant = "Result" ok_type = "FlowSuccess" err_type = "FlowError" [[object]] name = "Gst.Format" status = "generate" [[object.derive]] name = "serde::Serialize, serde::Deserialize" cfg_condition = "feature = \"serde\"" [[object.derive]] name = "Debug, PartialEq, Eq, PartialOrd, Ord, Hash" [[object.function]] name = "register" # Needs manual work ignore = true [[object]] name = "Gst.GhostPad" status = "generate" [[object.function]] name = "set_target" [object.function.return] bool_return_is_error = "Failed to set target" [[object.function]] name = "new" rename = "with_target" manual = true [[object.function]] name = "new_no_target" rename = "new" manual = true [[object.function]] name = "new_from_template" rename = "from_template_with_target" manual = true [[object.function]] name = "new_no_target_from_template" rename = "from_template" manual = true [[object.function]] name = "construct" ignore = true [[object.function]] name = "activate_mode_default" # wrong instance type manual = true [[object.function]] name = "internal_activate_mode_default" # wrong instance type manual = true [[object]] name = "Gst.LibraryError" status = "generate" [[object.member]] name = "num_errors" ignore = true [[object]] name = "Gst.Memory" status = "manual" [[object.function]] name = "map" # Readable and writable variant dealing with mutability # Non-into variants available under MemoryRef rename = "into_mapped_memory_readable" [[object.function]] name = "unmap" ignore = true [[object]] name = "Gst.MemoryFlags" status = "generate" [[object.member]] name = "last" ignore = true [[object]] name = "Gst.Message" status = "manual" ref_mode = "ref" [[object]] name = "Gst.MetaFlags" status = "generate" [[object.member]] name = "none" ignore = true [[object.member]] name = "last" ignore = true [[object]] name = "Gst.Object" # For renaming the trait... status = "generate" trait_name = "GstObjectExt" [[object.function]] name = "set_name" # Don't allow changing the name at random times ignore = true [[object.property]] name = "name" # There are accessor functions for this ignore = true [[object.function]] name = "ref_sink" # Takes a raw pointer ignore = true [[object.function]] name = "get_name" [object.function.return] # Nullable state only occurs during instance init and finalize # which cannot be observed from Rust nullable = false [[object.function]] name = "set_parent" [object.function.return] bool_return_is_error = "Failed to set parent object" [[object.function]] name = "sync_values" [[object.function.parameter]] name = "timestamp" mandatory = true [object.function.return] bool_return_is_error = "Failed to sync values" [[object.function]] name = "value" [[object.function.parameter]] name = "timestamp" mandatory = true [[object.function]] name = "get_g_value_array" ignore = true [[object.function]] name = "add_control_binding" [object.function.return] bool_return_is_error = "Failed to add control binding" [[object]] name = "Gst.ObjectFlags" status = "generate" [[object.member]] name = "last" ignore = true [[object]] name = "Gst.Pad" status = "generate" manual_traits = ["PadExtManual"] [[object.function]] name = "link_maybe_ghosting" [object.function.return] bool_return_is_error = "Failed to link pads, possibly ghosting" [[object.function]] name = "link_maybe_ghosting_full" [object.function.return] bool_return_is_error = "Failed to link pads, possibly ghosting" [[object.function]] name = "unlink" [object.function.return] bool_return_is_error = "Failed to unlink pad" [[object.function]] name = "pause_task" [object.function.return] bool_return_is_error = "Failed to pause pad task" [[object.function]] name = "stop_task" [object.function.return] bool_return_is_error = "Failed to stop pad task" [[object.function]] name = "set_active" [object.function.return] bool_return_is_error = "Failed to activate pad" [[object.function]] name = "activate_mode" [object.function.return] bool_return_is_error = "Failed to activate mode pad" [[object.function]] name = "remove_probe" # Don't use a ulong manual = true [[object.function]] name = "pull_range" # Buffer can be NULL manual = true [[object.function]] name = "get_range" # Buffer can be NULL manual = true [[object.function]] name = "get_last_flow_return" # Use Result rename = "last_flow_result" [[object.function]] name = "query" # Correct mutability manual = true [[object.function]] name = "peer_query" # Correct mutability manual = true [[object.function]] name = "query_default" # Correct mutability manual = true [[object.function]] name = "proxy_query_caps" # Correct mutability manual = true [[object.function]] name = "proxy_query_accept_caps" # Correct mutability manual = true [[object.function]] name = "event_default" # Pass by value manual = true [[object.function]] name = "push_event" # Pass by value manual = true [[object.function]] name = "send_event" # Pass by value manual = true [[object.function]] name = "new" # Also has builder() manual = true [[object.function]] name = "new_from_template" # Also has builder_from_template() rename = "from_template" manual = true [[object.function]] name = "new_from_static_template" # Also has builder_from_static_template() rename = "from_static_template" manual = true [[object.function]] name = "query_duration" # formatted value manual = true [[object.function]] name = "query_position" # formatted value manual = true [[object.function]] name = "query_convert" # formatted value manual = true [[object.function]] name = "peer_query_duration" # formatted value manual = true [[object.function]] name = "peer_query_position" # formatted value manual = true [[object.function]] name = "peer_query_convert" # formatted value manual = true [[object.function]] name = "link_get_name" # Wrong place manual = true [[object.function]] pattern = "set_.*_function_full" # More specific closure trait bounds possible manual = true [[object.function]] name = "start_task" # More specific closure trait bounds possible manual = true [[object.function]] name = "sticky_events_foreach" # Complex closure argument handling manual = true [[object.function]] name = "get_sticky_event" # More convenient API manual = true [[object.function]] name = "add_probe" # Complex closure argument handling manual = true [[object.property]] name = "template" # Has a proper getter ignore = true [[object.property]] name = "caps" # Same as `current_caps()` generate = ["notify"] [[object]] name = "Gst.PadDirection" status = "generate" exhaustive = true [[object.derive]] name = "serde::Serialize, serde::Deserialize" cfg_condition = "feature = \"serde\"" [[object.derive]] name = "Debug, PartialEq, Eq, PartialOrd, Ord, Hash" [[object]] name = "Gst.PadFlags" status = "generate" [[object.member]] name = "last" ignore = true [[object]] name = "Gst.PadLinkCheck" status = "generate" [[object.member]] name = "nothing" ignore = true [[object]] # mapping unknown values to default name = "Gst.PadLinkReturn" status = "manual" must_use = true exhaustive = true [object.conversion_type] variant = "Result" ok_type = "PadLinkSuccess" err_type = "PadLinkError" [[object]] name = "Gst.PadMode" status = "generate" exhaustive = true [[object]] name = "Gst.PadPresence" status = "generate" exhaustive = true [[object.derive]] name = "serde::Serialize, serde::Deserialize" cfg_condition = "feature = \"serde\"" [[object.derive]] name = "Debug, PartialEq, Eq, PartialOrd, Ord, Hash" [[object]] name = "Gst.PadProbeReturn" status = "generate" exhaustive = true [[object]] name = "Gst.PadProbeType" status = "generate" [[object.member]] name = "invalid" ignore = true [[object]] name = "Gst.PadTemplate" status = "generate" final_type = true [[object.function]] name = "new" [object.function.return] nullable_return_is_error = "Failed to create pad template" [[object.function]] name = "new_with_gtype" [object.function.return] nullable_return_is_error = "Failed to create pad template" [[object.function]] name = "new_from_static_pad_template_with_gtype" # static pad template manual manual = true [[object.function]] name = "get_caps" # directly access the field manual = true [[object.function]] name = "set_documentation_caps" # builder manual = true [[object.function]] name = "get_documentation_caps" # directly access the field manual = true [[object.property]] name = "name-template" # directly access the field and borrow the string manual = true [[object.property]] name = "direction" # directly access the field manual = true [[object.property]] name = "presence" # directly access the field manual = true [[object.property]] name = "gtype" # directly access the field manual = true [[object]] name = "Gst.ParseContext" status = "manual" ref_mode = "ref-mut" [[object]] name = "Gst.ParseFlags" status = "generate" [[object.member]] name = "none" ignore = true [[object]] name = "Gst.Pipeline" status = "generate" [[object.function]] name = "new" # Remove the optional `name` argument in favor of using the builder manual = true [[object.function]] name = "get_delay" [object.function.return] mandatory = true [[object.function]] name = "set_delay" [[object.function.parameter]] name = "delay" mandatory = true [[object.function]] name = "get_clock" # useless function that is equal to the GstElement one ignore = true [[object.function]] name = "set_clock" # useless function that is equal to the GstElement one ignore = true [[object.function]] name = "get_bus" # useless function that is equal to the GstElement one ignore = true [[object]] name = "Gst.PipelineFlags" status = "generate" [[object.member]] name = "last" ignore = true [[object]] name = "Gst.Plugin" status = "generate" final_type = true [[object.function]] pattern = "register_static.*" # Needs manual implementation ignore = true [[object.function]] name = "list_free" # useless and unsafe ignore = true [[object.function]] name = "get_cache_data" # structure ref manual = true [[object.function]] name = "load" [object.function.return] nullable_return_is_error = "Failed to load plugin" [[object.function]] name = "load_by_name" [object.function.return] nullable_return_is_error = "Failed to load plugin" [[object.function]] name = "get_name" rename = "plugin_name" [[object]] name = "Gst.PluginDependencyFlags" status = "generate" [[object.member]] name = "none" ignore = true [[object]] name = "Gst.PluginFeature" status = "generate" manual_traits = ["PluginFeatureExtManual"] [[object.function]] pattern = "list_.*" ignore = true [[object.function]] name = "rank_compare_func" ignore = true [[object.function]] name = "get_rank" manual = true [[object.function]] name = "set_rank" manual = true [[object.function]] name = "load" manual = true [[object]] name = "Gst.Preset" status = "generate" [[object.function]] name = "set_app_dir" [object.function.return] bool_return_is_error = "Failed to set app preset directory" [[object.function]] name = "delete_preset" [object.function.return] bool_return_is_error = "Failed to delete preset" [[object.function]] name = "load_preset" [object.function.return] bool_return_is_error = "Failed to load preset" [[object.function]] name = "save_preset" [object.function.return] bool_return_is_error = "Failed to save preset" [[object.function]] name = "rename_preset" [object.function.return] bool_return_is_error = "Failed to rename preset" [[object.function]] name = "set_meta" [object.function.return] bool_return_is_error = "Failed to set preset meta" [[object]] name = "Gst.Promise" status = "manual" ref_mode = "ref" [[object]] name = "Gst.ProxyPad" status = "generate" manual_traits = ["ProxyPadExtManual"] [[object.function]] name = "chain_default" # Buffer move manual = true [[object.function]] name = "chain_list_default" # Buffer move manual = true [[object.function]] name = "getrange_default" # Buffer move manual = true [[object]] name = "Gst.Query" status = "manual" ref_mode = "ref" [[object]] name = "Gst.Registry" status = "generate" final_type = true [[object.function]] pattern = "fork_.*" ignore = true [[object.function]] name = "add_feature" [object.function.return] bool_return_is_error = "Failed to add feature" [[object.function]] name = "add_plugin" [object.function.return] bool_return_is_error = "Failed to add plugin" [[object.function]] name = "feature_filter" rename = "features_filtered" # Use glib::List as return type manual = true [[object.function]] name = "get_feature_list" rename = "features" # Use glib::List as return type manual = true [[object.function]] name = "get_feature_list_by_plugin" rename = "features_by_plugin" # Use glib::List as return type manual = true [[object.function]] name = "get_plugin_list" rename = "plugins" # Use glib::List as return type manual = true [[object.function]] name = "plugin_filter" rename = "plugins_filtered" # Use glib::List as return type manual = true [[object]] name = "Gst.ResourceError" status = "generate" [[object.member]] name = "num_errors" ignore = true [[object]] name = "Gst.Sample" status = "manual" ref_mode = "ref" [[object]] name = "Gst.SeekFlags" status = "generate" [[object.member]] name = "trickmode_forward_predicted" version = "1.18" [[object.member]] name = "instant_rate_change" version = "1.18" [[object.member]] name = "none" ignore = true [[object]] name = "Gst.SeekType" status = "generate" exhaustive = true [[object]] name = "Gst.SegmentFlags" status = "generate" [[object.member]] name = "trickmode_forward_predicted" version = "1.18" [[object.member]] name = "none" ignore = true [[object]] name = "Gst.SerializeFlags" status = "generate" [[object.member]] name = "strict" # Changes nullability of gst_structure_serialize() so moved to a # separate function instead ignore = true [[object]] name = "Gst.StackTraceFlags" status = "generate" [[object.member]] name = "none" ignore = true [[object]] name = "Gst.State" status = "generate" exhaustive = true [[object.derive]] name = "serde::Serialize, serde::Deserialize" cfg_condition = "feature = \"serde\"" [[object.derive]] name = "Debug, PartialEq, Eq, PartialOrd, Ord, Hash" [[object]] name = "Gst.StateChange" status = "generate" exhaustive = true [[object]] name = "Gst.StateChangeReturn" status = "generate" must_use = true exhaustive = true [object.conversion_type] variant = "Result" ok_type = "StateChangeSuccess" err_type = "StateChangeError" [[object]] name = "Gst.Stream" status = "generate" final_type = true [[object]] name = "Gst.StreamCollection" status = "generate" final_type = true [[object.function]] name = "new" # Manual builder pattern manual = true [[object.function]] name = "add_stream" # Ignore return value which is always `true` manual = true [[object.property]] name = "upstream-id" generate = ["get"] [[object]] name = "Gst.StreamError" status = "generate" [[object.member]] name = "num_errors" ignore = true [[object]] name = "Gst.StreamFlags" status = "generate" [[object.member]] name = "none" ignore = true [[object]] name = "Gst.Structure" status = "manual" ref_mode = "ref" # Functions moved to `StructureRef` [[object.function]] name = "set" ignore = true [[object.function]] name = "set_value" ignore = true [[object.function]] name = "get_value" ignore = true [[object.function]] name = "id_get_value" rename = "value_by_quark" ignore = true [[object.function]] name = "take_value" rename = "set_value" ignore = true [[object.function]] name = "id_take_value" rename = "set_value_by_quark" ignore = true [[object.function]] name = "get_name" rename = "name" ignore = true [[object.function]] name = "get_name_id" rename = "name_quark" ignore = true [[object.function]] name = "set_name" ignore = true [[object.function]] name = "has_field" ignore = true [[object.function]] name = "has_field_with_typed" rename = "has_field_with_type" ignore = true [[object.function]] name = "id_has_field" rename = "has_field_by_quark" ignore = true [[object.function]] name = "id_has_field_typed" rename = "has_field_with_type_by_quark" ignore = true [[object.function]] name = "remove_field" ignore = true [[object.function]] name = "remove_fields" # Repeatedly call remove_field() ignore = true [[object.function]] name = "remove_all_fields" ignore = true [[object.function]] name = "get_nth_field_name" ignore = true [[object.function]] name = "n_fields" ignore = true [[object.function]] name = "can_intersect" ignore = true [[object.function]] name = "intersect" ignore = true [[object.function]] name = "is_subset" ignore = true [[object.function]] name = "fixate" ignore=true [[object.function]] name = "fixate_field" ignore=true [[object.function]] name = "fixate_field_boolean" ignore=true [[object.function]] name = "fixate_field_string" ignore=true [[object.function]] name = "fixate_field_nearest_double" ignore=true [[object.function]] name = "fixate_field_nearest_fraction" ignore=true [[object.function]] name = "fixate_field_nearest_int" ignore=true # Not implemented [[object.function]] name = "set_parent_refcount" ignore = true [[object]] name = "Gst.TagFlag" status = "generate" [[object.member]] name = "count" ignore = true [[object]] name = "Gst.TagList" status = "manual" ref_mode = "ref" [[object]] name = "Gst.TagMergeMode" status = "generate" [[object.member]] name = "count" ignore = true [[object]] name = "Gst.TagScope" status = "generate" [[object.derive]] name = "serde::Serialize, serde::Deserialize" cfg_condition = "feature = \"serde\"" [[object.derive]] name = "Debug, PartialEq, Eq, PartialOrd, Ord, Hash" [[object]] name = "Gst.TagSetter" status = "generate" manual_traits = ["TagSetterExtManual"] [[object.function]] name = "add_tag_value" manual = true [[object.function]] name = "add_tags" # Takes a raw pointer ignore = true [[object]] name = "Gst.Task" status = "generate" # Need work [[object.function]] name = "new" manual = true [[object.function]] name = "set_enter_callback" manual = true [[object.function]] name = "set_leave_callback" manual = true [[object.function]] name = "set_lock" manual = true [[object.function]] name = "start" [object.function.return] bool_return_is_error = "Failed to start task" [[object.function]] name = "stop" [object.function.return] bool_return_is_error = "Failed to stop task" [[object.function]] name = "pause" [object.function.return] bool_return_is_error = "Failed to pause task" [[object.function]] name = "resume" [object.function.return] bool_return_is_error = "Failed to resume task" [[object.function]] name = "join" [object.function.return] bool_return_is_error = "Failed to join task" [[object.function]] name = "set_state" [object.function.return] bool_return_is_error = "Failed to set task state" [[object]] name = "Gst.TaskPool" status = "generate" manual_traits = ["TaskPoolExtManual"] [[object.function]] name = "push" manual = true # Moved to TaskHandle [[object.function]] name = "join" ignore = true [[object.function]] name = "dispose_handle" ignore = true [[object]] name = "Gst.Toc" status = "manual" ref_mode = "ref" [[object]] name = "Gst.TocEntry" status = "manual" ref_mode = "ref" [[object]] name = "Gst.TocEntryType" status = "generate" [[object.derive]] name = "serde::Serialize, serde::Deserialize" cfg_condition = "feature = \"serde\"" [[object.derive]] name = "Debug, PartialEq, Eq, PartialOrd, Ord, Hash" [[object]] name = "Gst.TocLoopType" status = "generate" [[object.derive]] name = "serde::Serialize, serde::Deserialize" cfg_condition = "feature = \"serde\"" [[object.derive]] name = "Debug, PartialEq, Eq, PartialOrd, Ord, Hash" [[object]] name = "Gst.TocScope" status = "generate" [[object.derive]] name = "serde::Serialize, serde::Deserialize" cfg_condition = "feature = \"serde\"" [[object.derive]] name = "Debug, PartialEq, Eq, PartialOrd, Ord, Hash" [[object]] name = "Gst.Tracer" status = "generate" [[object.function]] name = "register" # Manual implementation as inherent to the type. ignore = true [[object]] name = "Gst.TracerFactory" status = "generate" [[object.function]] name = "get_list" rename = "factories" # Use glib::List as return type manual = true [[object]] name = "Gst.TypeFindFactory" status = "generate" final_type = true [[object.function]] name = "call_function" # Set up native functions in `TypeFind`, calling into trait argument manual = true [[object.function]] name = "get_list" rename = "factories" # Use glib::List as return type manual = true [[object]] name = "Gst.TypeFindProbability" status = "generate" [[object.derive]] name = "Debug" [[object]] name = "Gst.URIType" status = "generate" exhaustive = true [[object.derive]] name = "serde::Serialize, serde::Deserialize" cfg_condition = "feature = \"serde\"" [[object.derive]] name = "Debug, PartialEq, Eq, PartialOrd, Ord, Hash" gstreamer-0.23.5/LICENSE-APACHE000064400000000000000000000251371046102023000136400ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. gstreamer-0.23.5/LICENSE-MIT000064400000000000000000000017771046102023000133540ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. gstreamer-0.23.5/README.md000064400000000000000000000176301046102023000131720ustar 00000000000000# gstreamer-rs [![crates.io](https://img.shields.io/crates/v/gstreamer.svg)](https://crates.io/crates/gstreamer) [![pipeline status](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/badges/main/pipeline.svg)](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/commits/main) [GStreamer](https://gstreamer.freedesktop.org/) bindings for Rust. Documentation can be found [here](https://gstreamer.freedesktop.org/documentation/rust/stable/latest/docs/gstreamer/). These bindings are providing a safe API that can be used to interface with GStreamer, e.g. for writing GStreamer-based applications and GStreamer plugins. The bindings are mostly autogenerated with [gir](https://github.com/gtk-rs/gir/) based on the [GObject-Introspection](https://wiki.gnome.org/Projects/GObjectIntrospection/) API metadata provided by the GStreamer project. ## Table of Contents 1. [Installation](#installation) 1. [Linux/BSDs](#installation-linux) 1. [macOS](#installation-macos) 1. [Windows](#installation-windows) 1. [Getting Started](#getting-started) 1. [License](#license) 1. [Contribution](#contribution) ## Installation To build the GStreamer bindings or anything depending on them, you need to have at least GStreamer 1.14 and gst-plugins-base 1.14 installed. In addition, some of the examples/tutorials require various GStreamer plugins to be available, which can be found in gst-plugins-base, gst-plugins-good, gst-plugins-bad, gst-plugins-ugly and/or gst-libav. ### Linux/BSDs You need to install the above mentioned packages with your distributions package manager, or build them from source. On Debian/Ubuntu they can be installed with ```console $ apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ gstreamer1.0-plugins-base gstreamer1.0-plugins-good \ gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \ gstreamer1.0-libav libgstrtspserver-1.0-dev libges-1.0-dev ``` The minimum required version of the above libraries is >= 1.14. If you build the gstreamer-player sub-crate, or any of the examples that depend on gstreamer-player, you must ensure that in addition to the above packages, `libgstreamer-plugins-bad1.0-dev` is installed. See the `Cargo.toml` files for the full details, ```console $ apt-get install libgstreamer-plugins-bad1.0-dev ``` Package names on other distributions should be similar. Please submit a pull request with instructions for yours. ### macOS You can install GStreamer and the plugins via [Homebrew](https://brew.sh/) or by installing the [binaries](https://gstreamer.freedesktop.org/data/pkg/osx/) provided by the GStreamer project. We recommend using the official GStreamer binaries over Homebrew, especially as GStreamer in Homebrew is [currently broken](https://github.com/orgs/Homebrew/discussions/3740#discussioncomment-3804964). #### GStreamer Binaries You need to download the *two* `.pkg` files from the GStreamer website and install them, e.g. `gstreamer-1.0-1.20.4-universal.pkg` and `gstreamer-1.0-devel-1.20.4-universal.pkg`. After installation, you also need to set the `PATH` environment variable as follows ```console $ export PATH="/Library/Frameworks/GStreamer.framework/Versions/1.0/bin${PATH:+:$PATH}" ``` Also note that the `pkg-config` from GStreamer should be the first one in the `PATH` as other versions have all kinds of quirks that will cause problems. #### Homebrew Homebrew only installs various plugins if explicitly enabled, so some extra `--with-*` flags may be required. ```console $ brew install gstreamer gst-plugins-base gst-plugins-good \ gst-plugins-bad gst-plugins-ugly gst-libav gst-rtsp-server \ gst-editing-services --with-orc --with-libogg --with-opus \ --with-pango --with-theora --with-libvorbis --with-libvpx \ --enable-gtk3 ``` Make sure the version of these libraries is >= 1.14. ### Windows You can install GStreamer and the plugins via [MSYS2](http://www.msys2.org/) with `pacman` or by installing the [binaries](https://gstreamer.freedesktop.org/data/pkg/windows/) provided by the GStreamer project. We recommend using the official GStreamer binaries over MSYS2. #### GStreamer Binaries You need to download the *two* `.msi` files for your platform from the GStreamer website and install them, e.g. `gstreamer-1.0-x86_64-1.20.4.msi` and `gstreamer-1.0-devel-x86_64-1.20.4.msi`. Make sure to select the version that matches your Rust toolchain, i.e. MinGW or MSVC. After installation set the ``PATH` environment variable as follows: ```console # For a UNIX-style shell: $ export PATH="c:/gstreamer/1.0/msvc_x86_64/bin${PATH:+:$PATH}" # For cmd.exe: $ set PATH=C:\gstreamer\1.0\msvc_x86_64\bin;%PATH% ``` Make sure to update the path to where you have actually installed GStreamer and for the corresponding toolchain. Also note that the `pkg-config.exe` from GStreamer should be the first one in the `PATH` as other versions have all kinds of quirks that will cause problems. #### MSYS2 / pacman ```console $ pacman -S glib2-devel pkg-config \ mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base \ mingw-w64-x86_64-gst-plugins-good mingw-w64-x86_64-gst-plugins-bad \ mingw-w64-x86_64-gst-plugins-ugly mingw-w64-x86_64-gst-libav \ mingw-w64-x86_64-gst-rtsp-server ``` Make sure the version of these libraries is >= 1.14. Note that the version of `pkg-config` included in `MSYS2` is [known to have problems](https://github.com/rust-lang/pkg-config-rs/issues/51#issuecomment-346300858) compiling GStreamer, so you may need to install another version. One option would be [`pkg-config-lite`](https://sourceforge.net/projects/pkgconfiglite/). ## Getting Started The API reference can be found [here](https://gstreamer.freedesktop.org/documentation/rust/stable/latest/docs/gstreamer/), however it is only the Rust API reference and does not explain any of the concepts. For getting started with GStreamer development, the best would be to follow the [documentation](https://gstreamer.freedesktop.org/documentation/) on the GStreamer website, especially the [Application Development Manual](https://gstreamer.freedesktop.org/documentation/application-development/). While being C-centric, it explains all the fundamental concepts of GStreamer and the code examples should be relatively easily translatable to Rust. The API is basically the same, function/struct names are the same and everything is only more convenient (hopefully) and safer. In addition there are [tutorials](https://gstreamer.freedesktop.org/documentation/tutorials/) on the GStreamer website. Many of them were ported to Rust already and the code can be found in the [tutorials](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/tree/main/tutorials) directory. Some further examples for various aspects of GStreamer and how to use it from Rust can be found in the [examples](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/tree/main/examples) directory. Various GStreamer plugins written in Rust can be found in the [gst-plugins-rs](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs) repository. ## LICENSE gstreamer-rs and all crates contained in here are licensed under either of * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. GStreamer itself is licensed under the Lesser General Public License version 2.1 or (at your option) any later version: https://www.gnu.org/licenses/lgpl-2.1.html ## Contribution Any kinds of contributions are welcome as a pull request. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in gstreamer-rs by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. gstreamer-0.23.5/src/allocation_params.rs000064400000000000000000000045411046102023000165350ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{marker::PhantomData, mem}; use glib::translate::*; use crate::{ffi, MemoryFlags}; #[derive(Debug, Clone)] #[doc(alias = "GstAllocationParams")] #[repr(transparent)] pub struct AllocationParams(ffi::GstAllocationParams); unsafe impl Send for AllocationParams {} unsafe impl Sync for AllocationParams {} impl Default for AllocationParams { fn default() -> Self { unsafe { let mut params = mem::MaybeUninit::uninit(); ffi::gst_allocation_params_init(params.as_mut_ptr()); AllocationParams(params.assume_init()) } } } impl AllocationParams { #[doc(alias = "get_flags")] #[inline] pub fn flags(&self) -> MemoryFlags { unsafe { from_glib(self.0.flags) } } #[doc(alias = "get_align")] #[inline] pub fn align(&self) -> usize { self.0.align } #[doc(alias = "get_prefix")] #[inline] pub fn prefix(&self) -> usize { self.0.prefix } #[doc(alias = "get_padding")] #[inline] pub fn padding(&self) -> usize { self.0.padding } pub fn new(flags: MemoryFlags, align: usize, prefix: usize, padding: usize) -> Self { assert_initialized_main_thread!(); let params = unsafe { ffi::GstAllocationParams { flags: flags.into_glib(), align, prefix, padding, ..mem::zeroed() } }; params.into() } #[inline] pub fn as_ptr(&self) -> *const ffi::GstAllocationParams { &self.0 } } impl From for AllocationParams { #[inline] fn from(params: ffi::GstAllocationParams) -> Self { skip_assert_initialized!(); AllocationParams(params) } } #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const ffi::GstAllocationParams> for AllocationParams { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GstAllocationParams, Self> { Stash(&self.0, PhantomData) } } impl FromGlib for AllocationParams { #[allow(unused_unsafe)] #[inline] unsafe fn from_glib(value: ffi::GstAllocationParams) -> Self { skip_assert_initialized!(); Self::from(value) } } gstreamer-0.23.5/src/allocator.rs000064400000000000000000000022561046102023000150260ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::{prelude::*, translate::*}; use crate::{ffi, Allocator}; impl Allocator { #[doc(alias = "gst_allocator_register")] pub fn register(name: &str, allocator: impl IsA) { skip_assert_initialized!(); unsafe { #[cfg(not(feature = "v1_22"))] { // See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3364 if crate::version() < (1, 20, 5, 0) { ffi::gst_allocator_register( name.to_glib_full(), allocator.upcast().into_glib_ptr(), ); } else { ffi::gst_allocator_register( name.to_glib_none().0, allocator.upcast().into_glib_ptr(), ); } } #[cfg(feature = "v1_22")] { ffi::gst_allocator_register( name.to_glib_none().0, allocator.upcast().into_glib_ptr(), ); } } } } gstreamer-0.23.5/src/auto/alias.rs000064400000000000000000000005131046102023000151010ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git) // DO NOT EDIT #[allow(unused_imports)] use crate::auto::*; #[doc(alias = "GstClockTimeDiff")] pub type ClockTimeDiff = i64; gstreamer-0.23.5/src/auto/allocator.rs000064400000000000000000000034071046102023000157750ustar 00000000000000// 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::{ffi, AllocationParams, Memory, Object}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstAllocator")] pub struct Allocator(Object) @extends Object; match fn { type_ => || ffi::gst_allocator_get_type(), } } impl Allocator { pub const NONE: Option<&'static Allocator> = None; #[doc(alias = "gst_allocator_find")] pub fn find(name: Option<&str>) -> Option { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_allocator_find(name.to_glib_none().0)) } } } unsafe impl Send for Allocator {} unsafe impl Sync for Allocator {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait AllocatorExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_allocator_alloc")] fn alloc( &self, size: usize, params: Option<&AllocationParams>, ) -> Result { unsafe { Option::<_>::from_glib_full(ffi::gst_allocator_alloc( self.as_ref().to_glib_none().0, size, mut_override(params.to_glib_none().0), )) .ok_or_else(|| glib::bool_error!("Failed to allocate memory")) } } #[doc(alias = "gst_allocator_set_default")] fn set_default(self) { unsafe { ffi::gst_allocator_set_default(self.upcast().into_glib_ptr()); } } } impl> AllocatorExt for O {} gstreamer-0.23.5/src/auto/bin.rs000064400000000000000000000264021046102023000145650ustar 00000000000000// 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::{ffi, ChildProxy, Element, ElementFlags, Object, Pad, PadDirection}; use glib::{ object::ObjectType as _, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstBin")] pub struct Bin(Object) @extends Element, Object, @implements ChildProxy; match fn { type_ => || ffi::gst_bin_get_type(), } } impl Bin { pub const NONE: Option<&'static Bin> = None; } unsafe impl Send for Bin {} unsafe impl Sync for Bin {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait GstBinExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_bin_add")] fn add(&self, element: &impl IsA) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_bin_add( self.as_ref().to_glib_none().0, element.as_ref().to_glib_none().0 ), "Failed to add element" ) } } #[doc(alias = "gst_bin_find_unlinked_pad")] fn find_unlinked_pad(&self, direction: PadDirection) -> Option { unsafe { from_glib_full(ffi::gst_bin_find_unlinked_pad( self.as_ref().to_glib_none().0, direction.into_glib(), )) } } #[doc(alias = "gst_bin_get_by_interface")] #[doc(alias = "get_by_interface")] fn by_interface(&self, iface: glib::types::Type) -> Option { unsafe { from_glib_full(ffi::gst_bin_get_by_interface( self.as_ref().to_glib_none().0, iface.into_glib(), )) } } #[doc(alias = "gst_bin_get_by_name")] #[doc(alias = "get_by_name")] fn by_name(&self, name: &str) -> Option { unsafe { from_glib_full(ffi::gst_bin_get_by_name( self.as_ref().to_glib_none().0, name.to_glib_none().0, )) } } #[doc(alias = "gst_bin_get_by_name_recurse_up")] #[doc(alias = "get_by_name_recurse_up")] fn by_name_recurse_up(&self, name: &str) -> Option { unsafe { from_glib_full(ffi::gst_bin_get_by_name_recurse_up( self.as_ref().to_glib_none().0, name.to_glib_none().0, )) } } #[doc(alias = "gst_bin_get_suppressed_flags")] #[doc(alias = "get_suppressed_flags")] fn suppressed_flags(&self) -> ElementFlags { unsafe { from_glib(ffi::gst_bin_get_suppressed_flags( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_bin_recalculate_latency")] fn recalculate_latency(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_bin_recalculate_latency(self.as_ref().to_glib_none().0), "Failed to recalculate latency" ) } } #[doc(alias = "gst_bin_remove")] fn remove(&self, element: &impl IsA) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_bin_remove( self.as_ref().to_glib_none().0, element.as_ref().to_glib_none().0 ), "Failed to remove element" ) } } #[doc(alias = "gst_bin_set_suppressed_flags")] fn set_suppressed_flags(&self, flags: ElementFlags) { unsafe { ffi::gst_bin_set_suppressed_flags(self.as_ref().to_glib_none().0, flags.into_glib()); } } #[doc(alias = "gst_bin_sync_children_states")] fn sync_children_states(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_bin_sync_children_states(self.as_ref().to_glib_none().0), "Failed to sync children states" ) } } #[doc(alias = "async-handling")] fn is_async_handling(&self) -> bool { ObjectExt::property(self.as_ref(), "async-handling") } #[doc(alias = "async-handling")] fn set_async_handling(&self, async_handling: bool) { ObjectExt::set_property(self.as_ref(), "async-handling", async_handling) } #[doc(alias = "message-forward")] fn is_message_forward(&self) -> bool { ObjectExt::property(self.as_ref(), "message-forward") } #[doc(alias = "message-forward")] fn set_message_forward(&self, message_forward: bool) { ObjectExt::set_property(self.as_ref(), "message-forward", message_forward) } #[doc(alias = "deep-element-added")] fn connect_deep_element_added( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn deep_element_added_trampoline< P: IsA, F: Fn(&P, &Bin, &Element) + Send + Sync + 'static, >( this: *mut ffi::GstBin, sub_bin: *mut ffi::GstBin, element: *mut ffi::GstElement, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( Bin::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(sub_bin), &from_glib_borrow(element), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"deep-element-added\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( deep_element_added_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "deep-element-removed")] fn connect_deep_element_removed( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn deep_element_removed_trampoline< P: IsA, F: Fn(&P, &Bin, &Element) + Send + Sync + 'static, >( this: *mut ffi::GstBin, sub_bin: *mut ffi::GstBin, element: *mut ffi::GstElement, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( Bin::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(sub_bin), &from_glib_borrow(element), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"deep-element-removed\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( deep_element_removed_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "element-added")] fn connect_element_added( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn element_added_trampoline< P: IsA, F: Fn(&P, &Element) + Send + Sync + 'static, >( this: *mut ffi::GstBin, element: *mut ffi::GstElement, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( Bin::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(element), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"element-added\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( element_added_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "element-removed")] fn connect_element_removed( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn element_removed_trampoline< P: IsA, F: Fn(&P, &Element) + Send + Sync + 'static, >( this: *mut ffi::GstBin, element: *mut ffi::GstElement, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( Bin::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(element), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"element-removed\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( element_removed_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "async-handling")] fn connect_async_handling_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_async_handling_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstBin, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Bin::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::async-handling\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_async_handling_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "message-forward")] fn connect_message_forward_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_message_forward_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstBin, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Bin::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::message-forward\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_message_forward_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> GstBinExt for O {} gstreamer-0.23.5/src/auto/buffer_pool.rs000064400000000000000000000054761046102023000163270ustar 00000000000000// 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::{ffi, Buffer, Object}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstBufferPool")] pub struct BufferPool(Object) @extends Object; match fn { type_ => || ffi::gst_buffer_pool_get_type(), } } impl BufferPool { pub const NONE: Option<&'static BufferPool> = None; #[doc(alias = "gst_buffer_pool_new")] pub fn new() -> BufferPool { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_buffer_pool_new()) } } } impl Default for BufferPool { fn default() -> Self { Self::new() } } unsafe impl Send for BufferPool {} unsafe impl Sync for BufferPool {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait BufferPoolExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_buffer_pool_get_options")] #[doc(alias = "get_options")] fn options(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::gst_buffer_pool_get_options( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_buffer_pool_has_option")] fn has_option(&self, option: &str) -> bool { unsafe { from_glib(ffi::gst_buffer_pool_has_option( self.as_ref().to_glib_none().0, option.to_glib_none().0, )) } } #[doc(alias = "gst_buffer_pool_is_active")] fn is_active(&self) -> bool { unsafe { from_glib(ffi::gst_buffer_pool_is_active( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_buffer_pool_release_buffer")] fn release_buffer(&self, buffer: Buffer) { unsafe { ffi::gst_buffer_pool_release_buffer( self.as_ref().to_glib_none().0, buffer.into_glib_ptr(), ); } } #[doc(alias = "gst_buffer_pool_set_active")] fn set_active(&self, active: bool) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_buffer_pool_set_active(self.as_ref().to_glib_none().0, active.into_glib()), "Failed to activate buffer pool" ) } } #[doc(alias = "gst_buffer_pool_set_flushing")] fn set_flushing(&self, flushing: bool) { unsafe { ffi::gst_buffer_pool_set_flushing(self.as_ref().to_glib_none().0, flushing.into_glib()); } } } impl> BufferPoolExt for O {} gstreamer-0.23.5/src/auto/bus.rs000064400000000000000000000145311046102023000146060ustar 00000000000000// 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::{ffi, ClockTime, Message, Object}; use glib::{ object::ObjectType as _, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstBus")] pub struct Bus(Object) @extends Object; match fn { type_ => || ffi::gst_bus_get_type(), } } impl Bus { #[doc(alias = "gst_bus_new")] pub fn new() -> Bus { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_bus_new()) } } #[doc(alias = "gst_bus_add_signal_watch")] pub fn add_signal_watch(&self) { unsafe { ffi::gst_bus_add_signal_watch(self.to_glib_none().0); } } //#[doc(alias = "gst_bus_async_signal_func")] //pub fn async_signal_func(&self, message: &Message, data: /*Unimplemented*/Option) -> bool { // unsafe { TODO: call ffi:gst_bus_async_signal_func() } //} #[doc(alias = "gst_bus_disable_sync_message_emission")] pub fn disable_sync_message_emission(&self) { unsafe { ffi::gst_bus_disable_sync_message_emission(self.to_glib_none().0); } } #[doc(alias = "gst_bus_enable_sync_message_emission")] pub fn enable_sync_message_emission(&self) { unsafe { ffi::gst_bus_enable_sync_message_emission(self.to_glib_none().0); } } //#[doc(alias = "gst_bus_get_pollfd")] //#[doc(alias = "get_pollfd")] //pub fn pollfd(&self, fd: /*Ignored*/glib::PollFD) { // unsafe { TODO: call ffi:gst_bus_get_pollfd() } //} #[doc(alias = "gst_bus_have_pending")] pub fn have_pending(&self) -> bool { unsafe { from_glib(ffi::gst_bus_have_pending(self.to_glib_none().0)) } } #[doc(alias = "gst_bus_peek")] pub fn peek(&self) -> Option { unsafe { from_glib_full(ffi::gst_bus_peek(self.to_glib_none().0)) } } #[doc(alias = "gst_bus_pop")] pub fn pop(&self) -> Option { unsafe { from_glib_full(ffi::gst_bus_pop(self.to_glib_none().0)) } } #[doc(alias = "gst_bus_post")] pub fn post(&self, message: Message) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_bus_post(self.to_glib_none().0, message.into_glib_ptr()), "Failed to post message" ) } } #[doc(alias = "gst_bus_remove_signal_watch")] pub fn remove_signal_watch(&self) { unsafe { ffi::gst_bus_remove_signal_watch(self.to_glib_none().0); } } #[doc(alias = "gst_bus_remove_watch")] #[allow(dead_code)] pub(crate) fn remove_watch(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_bus_remove_watch(self.to_glib_none().0), "Bus has no event source" ) } } #[doc(alias = "gst_bus_set_flushing")] pub fn set_flushing(&self, flushing: bool) { unsafe { ffi::gst_bus_set_flushing(self.to_glib_none().0, flushing.into_glib()); } } //#[doc(alias = "gst_bus_sync_signal_handler")] //pub fn sync_signal_handler(&self, message: &Message, data: /*Unimplemented*/Option) -> BusSyncReply { // unsafe { TODO: call ffi:gst_bus_sync_signal_handler() } //} #[doc(alias = "gst_bus_timed_pop")] pub fn timed_pop(&self, timeout: impl Into>) -> Option { unsafe { from_glib_full(ffi::gst_bus_timed_pop( self.to_glib_none().0, timeout.into().into_glib(), )) } } #[doc(alias = "message")] pub fn connect_message( &self, detail: Option<&str>, f: F, ) -> SignalHandlerId { unsafe extern "C" fn message_trampoline( this: *mut ffi::GstBus, message: *mut ffi::GstMessage, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this), &from_glib_borrow(message)) } unsafe { let f: Box_ = Box_::new(f); let detailed_signal_name = detail.map(|name| format!("message::{name}\0")); let signal_name: &[u8] = detailed_signal_name .as_ref() .map_or(&b"message\0"[..], |n| n.as_bytes()); connect_raw( self.as_ptr() as *mut _, signal_name.as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( message_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "sync-message")] pub fn connect_sync_message( &self, detail: Option<&str>, f: F, ) -> SignalHandlerId { unsafe extern "C" fn sync_message_trampoline< F: Fn(&Bus, &Message) + Send + Sync + 'static, >( this: *mut ffi::GstBus, message: *mut ffi::GstMessage, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this), &from_glib_borrow(message)) } unsafe { let f: Box_ = Box_::new(f); let detailed_signal_name = detail.map(|name| format!("sync-message::{name}\0")); let signal_name: &[u8] = detailed_signal_name .as_ref() .map_or(&b"sync-message\0"[..], |n| n.as_bytes()); connect_raw( self.as_ptr() as *mut _, signal_name.as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( sync_message_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl Default for Bus { fn default() -> Self { Self::new() } } unsafe impl Send for Bus {} unsafe impl Sync for Bus {} gstreamer-0.23.5/src/auto/child_proxy.rs000064400000000000000000000144741046102023000163470ustar 00000000000000// 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::ffi; use glib::{ object::ObjectType as _, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstChildProxy")] pub struct ChildProxy(Interface); match fn { type_ => || ffi::gst_child_proxy_get_type(), } } impl ChildProxy { pub const NONE: Option<&'static ChildProxy> = None; } unsafe impl Send for ChildProxy {} unsafe impl Sync for ChildProxy {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait ChildProxyExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_child_proxy_child_added")] fn child_added(&self, child: &impl IsA, name: &str) { unsafe { ffi::gst_child_proxy_child_added( self.as_ref().to_glib_none().0, child.as_ref().to_glib_none().0, name.to_glib_none().0, ); } } #[doc(alias = "gst_child_proxy_child_removed")] fn child_removed(&self, child: &impl IsA, name: &str) { unsafe { ffi::gst_child_proxy_child_removed( self.as_ref().to_glib_none().0, child.as_ref().to_glib_none().0, name.to_glib_none().0, ); } } //#[doc(alias = "gst_child_proxy_get")] //fn get(&self, first_property_name: &str, : /*Unknown conversion*//*Unimplemented*/Basic: VarArgs) { // unsafe { TODO: call ffi:gst_child_proxy_get() } //} #[doc(alias = "gst_child_proxy_get_child_by_index")] #[doc(alias = "get_child_by_index")] fn child_by_index(&self, index: u32) -> Option { unsafe { from_glib_full(ffi::gst_child_proxy_get_child_by_index( self.as_ref().to_glib_none().0, index, )) } } #[doc(alias = "gst_child_proxy_get_child_by_name")] #[doc(alias = "get_child_by_name")] fn child_by_name(&self, name: &str) -> Option { unsafe { from_glib_full(ffi::gst_child_proxy_get_child_by_name( self.as_ref().to_glib_none().0, name.to_glib_none().0, )) } } #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] #[doc(alias = "gst_child_proxy_get_child_by_name_recurse")] #[doc(alias = "get_child_by_name_recurse")] fn child_by_name_recurse(&self, name: &str) -> Option { unsafe { from_glib_full(ffi::gst_child_proxy_get_child_by_name_recurse( self.as_ref().to_glib_none().0, name.to_glib_none().0, )) } } #[doc(alias = "gst_child_proxy_get_children_count")] #[doc(alias = "get_children_count")] fn children_count(&self) -> u32 { unsafe { ffi::gst_child_proxy_get_children_count(self.as_ref().to_glib_none().0) } } //#[doc(alias = "gst_child_proxy_get_valist")] //#[doc(alias = "get_valist")] //fn valist(&self, first_property_name: &str, var_args: /*Unknown conversion*//*Unimplemented*/Unsupported) { // unsafe { TODO: call ffi:gst_child_proxy_get_valist() } //} //#[doc(alias = "gst_child_proxy_set")] //fn set(&self, first_property_name: &str, : /*Unknown conversion*//*Unimplemented*/Basic: VarArgs) { // unsafe { TODO: call ffi:gst_child_proxy_set() } //} //#[doc(alias = "gst_child_proxy_set_valist")] //fn set_valist(&self, first_property_name: &str, var_args: /*Unknown conversion*//*Unimplemented*/Unsupported) { // unsafe { TODO: call ffi:gst_child_proxy_set_valist() } //} #[doc(alias = "child-added")] fn connect_child_added( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn child_added_trampoline< P: IsA, F: Fn(&P, &glib::Object, &str) + Send + Sync + 'static, >( this: *mut ffi::GstChildProxy, object: *mut glib::gobject_ffi::GObject, name: *mut std::ffi::c_char, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( ChildProxy::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(object), &glib::GString::from_glib_borrow(name), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"child-added\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( child_added_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "child-removed")] fn connect_child_removed( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn child_removed_trampoline< P: IsA, F: Fn(&P, &glib::Object, &str) + Send + Sync + 'static, >( this: *mut ffi::GstChildProxy, object: *mut glib::gobject_ffi::GObject, name: *mut std::ffi::c_char, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( ChildProxy::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(object), &glib::GString::from_glib_borrow(name), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"child-removed\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( child_removed_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> ChildProxyExt for O {} gstreamer-0.23.5/src/auto/clock.rs000064400000000000000000000330071046102023000151070ustar 00000000000000// 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::{ffi, ClockTime, Object}; use glib::{ object::ObjectType as _, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstClock")] pub struct Clock(Object) @extends Object; match fn { type_ => || ffi::gst_clock_get_type(), } } impl Clock { pub const NONE: Option<&'static Clock> = None; //#[doc(alias = "gst_clock_id_compare_func")] //pub fn id_compare_func(id1: /*Unimplemented*/Option, id2: /*Unimplemented*/Option) -> i32 { // unsafe { TODO: call ffi:gst_clock_id_compare_func() } //} //#[cfg(feature = "v1_16")] //#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] //#[doc(alias = "gst_clock_id_get_clock")] //pub fn id_get_clock(id: /*Unimplemented*/ClockID) -> Option { // unsafe { TODO: call ffi:gst_clock_id_get_clock() } //} //#[doc(alias = "gst_clock_id_get_time")] //pub fn id_get_time(id: /*Unimplemented*/ClockID) -> Option { // unsafe { TODO: call ffi:gst_clock_id_get_time() } //} //#[doc(alias = "gst_clock_id_ref")] //pub fn id_ref(id: /*Unimplemented*/ClockID) -> /*Unimplemented*/ClockID { // unsafe { TODO: call ffi:gst_clock_id_ref() } //} //#[doc(alias = "gst_clock_id_unref")] //pub fn id_unref(id: /*Unimplemented*/ClockID) { // unsafe { TODO: call ffi:gst_clock_id_unref() } //} //#[doc(alias = "gst_clock_id_unschedule")] //pub fn id_unschedule(id: /*Unimplemented*/ClockID) { // unsafe { TODO: call ffi:gst_clock_id_unschedule() } //} //#[cfg(feature = "v1_16")] //#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] //#[doc(alias = "gst_clock_id_uses_clock")] //pub fn id_uses_clock(id: /*Unimplemented*/ClockID, clock: &impl IsA) -> bool { // unsafe { TODO: call ffi:gst_clock_id_uses_clock() } //} //#[doc(alias = "gst_clock_id_wait")] //pub fn id_wait(id: /*Unimplemented*/ClockID) -> (Result, ClockTimeDiff) { // unsafe { TODO: call ffi:gst_clock_id_wait() } //} //#[doc(alias = "gst_clock_id_wait_async")] //pub fn id_wait_async(id: /*Unimplemented*/ClockID, func: /*Unimplemented*/Fn(&Clock, impl Into>, /*Unimplemented*/ClockID) -> bool, user_data: /*Unimplemented*/Option) -> Result { // unsafe { TODO: call ffi:gst_clock_id_wait_async() } //} } unsafe impl Send for Clock {} unsafe impl Sync for Clock {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait ClockExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_clock_add_observation")] fn add_observation( &self, observation_internal: ClockTime, observation_external: ClockTime, ) -> Option { unsafe { let mut r_squared = std::mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_clock_add_observation( self.as_ref().to_glib_none().0, observation_internal.into_glib(), observation_external.into_glib(), r_squared.as_mut_ptr(), )); if ret { Some(r_squared.assume_init()) } else { None } } } #[doc(alias = "gst_clock_add_observation_unapplied")] fn add_observation_unapplied( &self, observation_internal: ClockTime, observation_external: ClockTime, ) -> Option<(f64, ClockTime, ClockTime, ClockTime, ClockTime)> { unsafe { let mut r_squared = std::mem::MaybeUninit::uninit(); let mut internal = std::mem::MaybeUninit::uninit(); let mut external = std::mem::MaybeUninit::uninit(); let mut rate_num = std::mem::MaybeUninit::uninit(); let mut rate_denom = std::mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_clock_add_observation_unapplied( self.as_ref().to_glib_none().0, observation_internal.into_glib(), observation_external.into_glib(), r_squared.as_mut_ptr(), internal.as_mut_ptr(), external.as_mut_ptr(), rate_num.as_mut_ptr(), rate_denom.as_mut_ptr(), )); if ret { Some(( r_squared.assume_init(), try_from_glib(internal.assume_init()).expect("mandatory glib value is None"), try_from_glib(external.assume_init()).expect("mandatory glib value is None"), try_from_glib(rate_num.assume_init()).expect("mandatory glib value is None"), try_from_glib(rate_denom.assume_init()).expect("mandatory glib value is None"), )) } else { None } } } #[doc(alias = "gst_clock_adjust_unlocked")] fn adjust_unlocked(&self, internal: ClockTime) -> Option { unsafe { from_glib(ffi::gst_clock_adjust_unlocked( self.as_ref().to_glib_none().0, internal.into_glib(), )) } } #[doc(alias = "gst_clock_get_internal_time")] #[doc(alias = "get_internal_time")] fn internal_time(&self) -> ClockTime { unsafe { try_from_glib(ffi::gst_clock_get_internal_time( self.as_ref().to_glib_none().0, )) .expect("mandatory glib value is None") } } #[doc(alias = "gst_clock_get_master")] #[doc(alias = "get_master")] #[must_use] fn master(&self) -> Option { unsafe { from_glib_full(ffi::gst_clock_get_master(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_clock_get_resolution")] #[doc(alias = "get_resolution")] fn resolution(&self) -> ClockTime { unsafe { try_from_glib(ffi::gst_clock_get_resolution( self.as_ref().to_glib_none().0, )) .expect("mandatory glib value is None") } } #[doc(alias = "gst_clock_get_time")] #[doc(alias = "get_time")] fn time(&self) -> Option { unsafe { from_glib(ffi::gst_clock_get_time(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_clock_get_timeout")] #[doc(alias = "get_timeout")] fn timeout(&self) -> Option { unsafe { from_glib(ffi::gst_clock_get_timeout(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_clock_is_synced")] fn is_synced(&self) -> bool { unsafe { from_glib(ffi::gst_clock_is_synced(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_clock_set_master")] fn set_master(&self, master: Option<&impl IsA>) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_clock_set_master( self.as_ref().to_glib_none().0, master.map(|p| p.as_ref()).to_glib_none().0 ), "Failed to set master clock" ) } } #[doc(alias = "gst_clock_set_resolution")] fn set_resolution(&self, resolution: ClockTime) -> ClockTime { unsafe { try_from_glib(ffi::gst_clock_set_resolution( self.as_ref().to_glib_none().0, resolution.into_glib(), )) .expect("mandatory glib value is None") } } #[doc(alias = "gst_clock_set_synced")] fn set_synced(&self, synced: bool) { unsafe { ffi::gst_clock_set_synced(self.as_ref().to_glib_none().0, synced.into_glib()); } } #[doc(alias = "gst_clock_set_timeout")] #[doc(alias = "timeout")] fn set_timeout(&self, timeout: impl Into>) { unsafe { ffi::gst_clock_set_timeout(self.as_ref().to_glib_none().0, timeout.into().into_glib()); } } #[doc(alias = "gst_clock_unadjust_unlocked")] fn unadjust_unlocked(&self, external: ClockTime) -> Option { unsafe { from_glib(ffi::gst_clock_unadjust_unlocked( self.as_ref().to_glib_none().0, external.into_glib(), )) } } #[doc(alias = "gst_clock_wait_for_sync")] fn wait_for_sync( &self, timeout: impl Into>, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_clock_wait_for_sync( self.as_ref().to_glib_none().0, timeout.into().into_glib() ), "Timed out waiting for sync" ) } } #[doc(alias = "window-size")] fn window_size(&self) -> i32 { ObjectExt::property(self.as_ref(), "window-size") } #[doc(alias = "window-size")] fn set_window_size(&self, window_size: i32) { ObjectExt::set_property(self.as_ref(), "window-size", window_size) } #[doc(alias = "window-threshold")] fn window_threshold(&self) -> i32 { ObjectExt::property(self.as_ref(), "window-threshold") } #[doc(alias = "window-threshold")] fn set_window_threshold(&self, window_threshold: i32) { ObjectExt::set_property(self.as_ref(), "window-threshold", window_threshold) } #[doc(alias = "synced")] fn connect_synced(&self, f: F) -> SignalHandlerId { unsafe extern "C" fn synced_trampoline< P: IsA, F: Fn(&P, bool) + Send + Sync + 'static, >( this: *mut ffi::GstClock, synced: glib::ffi::gboolean, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( Clock::from_glib_borrow(this).unsafe_cast_ref(), from_glib(synced), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"synced\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( synced_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "timeout")] fn connect_timeout_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_timeout_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstClock, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Clock::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::timeout\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_timeout_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "window-size")] fn connect_window_size_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_window_size_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstClock, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Clock::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::window-size\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_window_size_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "window-threshold")] fn connect_window_threshold_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_window_threshold_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstClock, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Clock::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::window-threshold\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_window_threshold_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> ClockExt for O {} gstreamer-0.23.5/src/auto/control_binding.rs000064400000000000000000000053471046102023000171740ustar 00000000000000// 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::{ffi, ClockTime, Object}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstControlBinding")] pub struct ControlBinding(Object) @extends Object; match fn { type_ => || ffi::gst_control_binding_get_type(), } } impl ControlBinding { pub const NONE: Option<&'static ControlBinding> = None; } unsafe impl Send for ControlBinding {} unsafe impl Sync for ControlBinding {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait ControlBindingExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_control_binding_get_value")] #[doc(alias = "get_value")] fn value(&self, timestamp: ClockTime) -> Option { unsafe { from_glib_full(ffi::gst_control_binding_get_value( self.as_ref().to_glib_none().0, timestamp.into_glib(), )) } } //#[doc(alias = "gst_control_binding_get_value_array")] //#[doc(alias = "get_value_array")] //fn is_value_array(&self, timestamp: impl Into>, interval: impl Into>, values: /*Unimplemented*/&[&Basic: Pointer]) -> bool { // unsafe { TODO: call ffi:gst_control_binding_get_value_array() } //} #[doc(alias = "gst_control_binding_is_disabled")] fn is_disabled(&self) -> bool { unsafe { from_glib(ffi::gst_control_binding_is_disabled( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_control_binding_set_disabled")] fn set_disabled(&self, disabled: bool) { unsafe { ffi::gst_control_binding_set_disabled( self.as_ref().to_glib_none().0, disabled.into_glib(), ); } } #[doc(alias = "gst_control_binding_sync_values")] fn sync_values( &self, object: &impl IsA, timestamp: ClockTime, last_sync: impl Into>, ) -> bool { unsafe { from_glib(ffi::gst_control_binding_sync_values( self.as_ref().to_glib_none().0, object.as_ref().to_glib_none().0, timestamp.into_glib(), last_sync.into().into_glib(), )) } } fn object(&self) -> Option { ObjectExt::property(self.as_ref(), "object") } } impl> ControlBindingExt for O {} gstreamer-0.23.5/src/auto/control_source.rs000064400000000000000000000027451046102023000170610ustar 00000000000000// 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::{ffi, ClockTime, Object}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstControlSource")] pub struct ControlSource(Object) @extends Object; match fn { type_ => || ffi::gst_control_source_get_type(), } } impl ControlSource { pub const NONE: Option<&'static ControlSource> = None; } unsafe impl Send for ControlSource {} unsafe impl Sync for ControlSource {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait ControlSourceExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_control_source_get_value")] #[doc(alias = "control_source_get_value")] fn value(&self, timestamp: ClockTime) -> Option { unsafe { let mut value = std::mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_control_source_get_value( self.as_ref().to_glib_none().0, timestamp.into_glib(), value.as_mut_ptr(), )); if ret { Some(value.assume_init()) } else { None } } } } impl> ControlSourceExt for O {} gstreamer-0.23.5/src/auto/date_time.rs000064400000000000000000000131211046102023000157420ustar 00000000000000// 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::ffi; use glib::translate::*; glib::wrapper! { #[derive()] pub struct DateTime(Shared); match fn { ref => |ptr| ffi::gst_date_time_ref(ptr), unref => |ptr| ffi::gst_date_time_unref(ptr), type_ => || ffi::gst_date_time_get_type(), } } impl DateTime { #[doc(alias = "gst_date_time_new_from_g_date_time")] #[doc(alias = "new_from_g_date_time")] pub fn from_g_date_time(dt: glib::DateTime) -> DateTime { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_date_time_new_from_g_date_time(dt.into_glib_ptr())) } } #[doc(alias = "gst_date_time_new_from_iso8601_string")] #[doc(alias = "new_from_iso8601_string")] pub fn from_iso8601_string(string: &str) -> Result { assert_initialized_main_thread!(); unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_new_from_iso8601_string( string.to_glib_none().0, )) .ok_or_else(|| glib::bool_error!("Failed to create DateTime from ISO-8601 string")) } } #[doc(alias = "gst_date_time_new_from_unix_epoch_local_time")] #[doc(alias = "new_from_unix_epoch_local_time")] pub fn from_unix_epoch_local_time(secs: i64) -> Result { assert_initialized_main_thread!(); unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_new_from_unix_epoch_local_time(secs)) .ok_or_else(|| glib::bool_error!("Can't create DateTime from UNIX epoch")) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "gst_date_time_new_from_unix_epoch_local_time_usecs")] #[doc(alias = "new_from_unix_epoch_local_time_usecs")] pub fn from_unix_epoch_local_time_usecs(usecs: i64) -> Result { assert_initialized_main_thread!(); unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_new_from_unix_epoch_local_time_usecs( usecs, )) .ok_or_else(|| glib::bool_error!("Can't create DateTime from UNIX epoch")) } } #[doc(alias = "gst_date_time_new_from_unix_epoch_utc")] #[doc(alias = "new_from_unix_epoch_utc")] pub fn from_unix_epoch_utc(secs: i64) -> Result { assert_initialized_main_thread!(); unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_new_from_unix_epoch_utc(secs)) .ok_or_else(|| glib::bool_error!("Can't create DateTime from UNIX epoch")) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "gst_date_time_new_from_unix_epoch_utc_usecs")] #[doc(alias = "new_from_unix_epoch_utc_usecs")] pub fn from_unix_epoch_utc_usecs(usecs: i64) -> Result { assert_initialized_main_thread!(); unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_new_from_unix_epoch_utc_usecs(usecs)) .ok_or_else(|| glib::bool_error!("Can't create DateTime from UNIX epoch")) } } #[doc(alias = "gst_date_time_new_now_local_time")] pub fn new_now_local_time() -> Option { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_date_time_new_now_local_time()) } } #[doc(alias = "gst_date_time_new_now_utc")] pub fn new_now_utc() -> Option { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_date_time_new_now_utc()) } } #[doc(alias = "gst_date_time_get_year")] #[doc(alias = "get_year")] pub fn year(&self) -> i32 { unsafe { ffi::gst_date_time_get_year(self.to_glib_none().0) } } #[doc(alias = "gst_date_time_has_day")] pub fn has_day(&self) -> bool { unsafe { from_glib(ffi::gst_date_time_has_day(self.to_glib_none().0)) } } #[doc(alias = "gst_date_time_has_month")] pub fn has_month(&self) -> bool { unsafe { from_glib(ffi::gst_date_time_has_month(self.to_glib_none().0)) } } #[doc(alias = "gst_date_time_has_second")] pub fn has_second(&self) -> bool { unsafe { from_glib(ffi::gst_date_time_has_second(self.to_glib_none().0)) } } #[doc(alias = "gst_date_time_has_time")] pub fn has_time(&self) -> bool { unsafe { from_glib(ffi::gst_date_time_has_time(self.to_glib_none().0)) } } #[doc(alias = "gst_date_time_has_year")] pub fn has_year(&self) -> bool { unsafe { from_glib(ffi::gst_date_time_has_year(self.to_glib_none().0)) } } #[doc(alias = "gst_date_time_to_g_date_time")] pub fn to_g_date_time(&self) -> Result { unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_to_g_date_time(self.to_glib_none().0)) .ok_or_else(|| glib::bool_error!("Can't create glib::DateTime from DateTime")) } } #[doc(alias = "gst_date_time_to_iso8601_string")] pub fn to_iso8601_string(&self) -> Result { unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_to_iso8601_string(self.to_glib_none().0)) .ok_or_else(|| glib::bool_error!("Failed to create ISO-8601 string from DateTime")) } } } unsafe impl Send for DateTime {} unsafe impl Sync for DateTime {} gstreamer-0.23.5/src/auto/device.rs000064400000000000000000000106341046102023000152540ustar 00000000000000// 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::{ffi, Caps, Element, Object, Structure}; use glib::{ object::ObjectType as _, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstDevice")] pub struct Device(Object) @extends Object; match fn { type_ => || ffi::gst_device_get_type(), } } impl Device { pub const NONE: Option<&'static Device> = None; } unsafe impl Send for Device {} unsafe impl Sync for Device {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait DeviceExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_device_create_element")] fn create_element(&self, name: Option<&str>) -> Result { unsafe { Option::<_>::from_glib_none(ffi::gst_device_create_element( self.as_ref().to_glib_none().0, name.to_glib_none().0, )) .ok_or_else(|| glib::bool_error!("Failed to create element for device")) } } #[doc(alias = "gst_device_get_caps")] #[doc(alias = "get_caps")] fn caps(&self) -> Option { unsafe { from_glib_full(ffi::gst_device_get_caps(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_device_get_device_class")] #[doc(alias = "get_device_class")] #[doc(alias = "device-class")] fn device_class(&self) -> glib::GString { unsafe { from_glib_full(ffi::gst_device_get_device_class( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_device_get_display_name")] #[doc(alias = "get_display_name")] #[doc(alias = "display-name")] fn display_name(&self) -> glib::GString { unsafe { from_glib_full(ffi::gst_device_get_display_name( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_device_get_properties")] #[doc(alias = "get_properties")] fn properties(&self) -> Option { unsafe { from_glib_full(ffi::gst_device_get_properties( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_device_has_classes")] fn has_classes(&self, classes: &str) -> bool { unsafe { from_glib(ffi::gst_device_has_classes( self.as_ref().to_glib_none().0, classes.to_glib_none().0, )) } } #[doc(alias = "gst_device_has_classesv")] fn has_classesv(&self, classes: &[&str]) -> bool { unsafe { from_glib(ffi::gst_device_has_classesv( self.as_ref().to_glib_none().0, classes.to_glib_none().0, )) } } #[doc(alias = "gst_device_reconfigure_element")] fn reconfigure_element( &self, element: &impl IsA, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_device_reconfigure_element( self.as_ref().to_glib_none().0, element.as_ref().to_glib_none().0 ), "Failed to reconfigure the element to use this device" ) } } #[doc(alias = "removed")] fn connect_removed(&self, f: F) -> SignalHandlerId { unsafe extern "C" fn removed_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstDevice, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Device::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"removed\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( removed_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> DeviceExt for O {} gstreamer-0.23.5/src/auto/device_monitor.rs000064400000000000000000000102431046102023000170170ustar 00000000000000// 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::{ffi, Bus, Object}; use glib::{ prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstDeviceMonitor")] pub struct DeviceMonitor(Object) @extends Object; match fn { type_ => || ffi::gst_device_monitor_get_type(), } } impl DeviceMonitor { pub const NONE: Option<&'static DeviceMonitor> = None; #[doc(alias = "gst_device_monitor_new")] pub fn new() -> DeviceMonitor { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_device_monitor_new()) } } } impl Default for DeviceMonitor { fn default() -> Self { Self::new() } } unsafe impl Send for DeviceMonitor {} unsafe impl Sync for DeviceMonitor {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait DeviceMonitorExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_device_monitor_get_bus")] #[doc(alias = "get_bus")] fn bus(&self) -> Bus { unsafe { from_glib_full(ffi::gst_device_monitor_get_bus( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_device_monitor_get_providers")] #[doc(alias = "get_providers")] fn providers(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_device_monitor_get_providers( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_device_monitor_get_show_all_devices")] #[doc(alias = "get_show_all_devices")] fn shows_all_devices(&self) -> bool { unsafe { from_glib(ffi::gst_device_monitor_get_show_all_devices( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_device_monitor_set_show_all_devices")] fn set_show_all_devices(&self, show_all: bool) { unsafe { ffi::gst_device_monitor_set_show_all_devices( self.as_ref().to_glib_none().0, show_all.into_glib(), ); } } #[doc(alias = "gst_device_monitor_start")] fn start(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_device_monitor_start(self.as_ref().to_glib_none().0), "Failed to start" ) } } #[doc(alias = "gst_device_monitor_stop")] fn stop(&self) { unsafe { ffi::gst_device_monitor_stop(self.as_ref().to_glib_none().0); } } #[doc(alias = "show-all")] fn shows_all(&self) -> bool { ObjectExt::property(self.as_ref(), "show-all") } #[doc(alias = "show-all")] fn set_show_all(&self, show_all: bool) { ObjectExt::set_property(self.as_ref(), "show-all", show_all) } #[doc(alias = "show-all")] fn connect_show_all_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_show_all_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstDeviceMonitor, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(DeviceMonitor::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::show-all\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_show_all_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> DeviceMonitorExt for O {} gstreamer-0.23.5/src/auto/device_provider.rs000064400000000000000000000154701046102023000171710ustar 00000000000000// 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::{ffi, Bus, Device, DeviceProviderFactory, Object}; use glib::{ object::ObjectType as _, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstDeviceProvider")] pub struct DeviceProvider(Object) @extends Object; match fn { type_ => || ffi::gst_device_provider_get_type(), } } impl DeviceProvider { pub const NONE: Option<&'static DeviceProvider> = None; } unsafe impl Send for DeviceProvider {} unsafe impl Sync for DeviceProvider {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait DeviceProviderExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_device_provider_can_monitor")] fn can_monitor(&self) -> bool { unsafe { from_glib(ffi::gst_device_provider_can_monitor( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_device_provider_device_add")] fn device_add(&self, device: &impl IsA) { unsafe { ffi::gst_device_provider_device_add( self.as_ref().to_glib_none().0, device.as_ref().to_glib_none().0, ); } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "gst_device_provider_device_changed")] fn device_changed(&self, device: &impl IsA, changed_device: &impl IsA) { unsafe { ffi::gst_device_provider_device_changed( self.as_ref().to_glib_none().0, device.as_ref().to_glib_none().0, changed_device.as_ref().to_glib_none().0, ); } } #[doc(alias = "gst_device_provider_device_remove")] fn device_remove(&self, device: &impl IsA) { unsafe { ffi::gst_device_provider_device_remove( self.as_ref().to_glib_none().0, device.as_ref().to_glib_none().0, ); } } #[doc(alias = "gst_device_provider_get_bus")] #[doc(alias = "get_bus")] fn bus(&self) -> Bus { unsafe { from_glib_full(ffi::gst_device_provider_get_bus( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_device_provider_get_factory")] #[doc(alias = "get_factory")] fn factory(&self) -> Option { unsafe { from_glib_none(ffi::gst_device_provider_get_factory( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_device_provider_get_hidden_providers")] #[doc(alias = "get_hidden_providers")] fn hidden_providers(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_device_provider_get_hidden_providers( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_device_provider_hide_provider")] fn hide_provider(&self, name: &str) { unsafe { ffi::gst_device_provider_hide_provider( self.as_ref().to_glib_none().0, name.to_glib_none().0, ); } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[doc(alias = "gst_device_provider_is_started")] fn is_started(&self) -> bool { unsafe { from_glib(ffi::gst_device_provider_is_started( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_device_provider_start")] fn start(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_device_provider_start(self.as_ref().to_glib_none().0), "Failed to start" ) } } #[doc(alias = "gst_device_provider_stop")] fn stop(&self) { unsafe { ffi::gst_device_provider_stop(self.as_ref().to_glib_none().0); } } #[doc(alias = "gst_device_provider_unhide_provider")] fn unhide_provider(&self, name: &str) { unsafe { ffi::gst_device_provider_unhide_provider( self.as_ref().to_glib_none().0, name.to_glib_none().0, ); } } #[doc(alias = "provider-hidden")] fn connect_provider_hidden( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn provider_hidden_trampoline< P: IsA, F: Fn(&P, &str) + Send + Sync + 'static, >( this: *mut ffi::GstDeviceProvider, object: *mut std::ffi::c_char, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( DeviceProvider::from_glib_borrow(this).unsafe_cast_ref(), &glib::GString::from_glib_borrow(object), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"provider-hidden\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( provider_hidden_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "provider-unhidden")] fn connect_provider_unhidden( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn provider_unhidden_trampoline< P: IsA, F: Fn(&P, &str) + Send + Sync + 'static, >( this: *mut ffi::GstDeviceProvider, object: *mut std::ffi::c_char, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( DeviceProvider::from_glib_borrow(this).unsafe_cast_ref(), &glib::GString::from_glib_borrow(object), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"provider-unhidden\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( provider_unhidden_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> DeviceProviderExt for O {} gstreamer-0.23.5/src/auto/device_provider_factory.rs000064400000000000000000000055441046102023000207210ustar 00000000000000// 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::{ffi, DeviceProvider, Object, PluginFeature}; use glib::translate::*; glib::wrapper! { #[doc(alias = "GstDeviceProviderFactory")] pub struct DeviceProviderFactory(Object) @extends PluginFeature, Object; match fn { type_ => || ffi::gst_device_provider_factory_get_type(), } } impl DeviceProviderFactory { #[doc(alias = "gst_device_provider_factory_get")] pub fn get(&self) -> Option { unsafe { from_glib_full(ffi::gst_device_provider_factory_get(self.to_glib_none().0)) } } #[doc(alias = "gst_device_provider_factory_get_device_provider_type")] #[doc(alias = "get_device_provider_type")] pub fn device_provider_type(&self) -> glib::types::Type { unsafe { from_glib(ffi::gst_device_provider_factory_get_device_provider_type( self.to_glib_none().0, )) } } #[doc(alias = "gst_device_provider_factory_get_metadata_keys")] #[doc(alias = "get_metadata_keys")] pub fn metadata_keys(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full( ffi::gst_device_provider_factory_get_metadata_keys(self.to_glib_none().0), ) } } #[doc(alias = "gst_device_provider_factory_has_classes")] pub fn has_classes(&self, classes: Option<&str>) -> bool { unsafe { from_glib(ffi::gst_device_provider_factory_has_classes( self.to_glib_none().0, classes.to_glib_none().0, )) } } #[doc(alias = "gst_device_provider_factory_has_classesv")] pub fn has_classesv(&self, classes: &[&str]) -> bool { unsafe { from_glib(ffi::gst_device_provider_factory_has_classesv( self.to_glib_none().0, classes.to_glib_none().0, )) } } #[doc(alias = "gst_device_provider_factory_find")] pub fn find(name: &str) -> Option { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_device_provider_factory_find(name.to_glib_none().0)) } } #[doc(alias = "gst_device_provider_factory_get_by_name")] #[doc(alias = "get_by_name")] pub fn by_name(factoryname: &str) -> Option { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_device_provider_factory_get_by_name( factoryname.to_glib_none().0, )) } } } unsafe impl Send for DeviceProviderFactory {} unsafe impl Sync for DeviceProviderFactory {} gstreamer-0.23.5/src/auto/element.rs000064400000000000000000000447711046102023000154570ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git) // DO NOT EDIT #![allow(deprecated)] use crate::{ ffi, Bus, Caps, Clock, ClockTime, Context, ElementFactory, Message, Object, Pad, PadTemplate, State, StateChange, StateChangeError, StateChangeReturn, StateChangeSuccess, URIType, }; use glib::{ object::ObjectType as _, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstElement")] pub struct Element(Object) @extends Object; match fn { type_ => || ffi::gst_element_get_type(), } } impl Element { pub const NONE: Option<&'static Element> = None; #[doc(alias = "gst_element_make_from_uri")] pub fn make_from_uri( type_: URIType, uri: &str, elementname: Option<&str>, ) -> Result { assert_initialized_main_thread!(); unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::gst_element_make_from_uri( type_.into_glib(), uri.to_glib_none().0, elementname.to_glib_none().0, &mut error, ); if error.is_null() { Ok(from_glib_none(ret)) } else { Err(from_glib_full(error)) } } } } unsafe impl Send for Element {} unsafe impl Sync for Element {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait ElementExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_element_abort_state")] fn abort_state(&self) { unsafe { ffi::gst_element_abort_state(self.as_ref().to_glib_none().0); } } #[doc(alias = "gst_element_add_pad")] fn add_pad(&self, pad: &impl IsA) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_element_add_pad( self.as_ref().to_glib_none().0, pad.as_ref().to_glib_none().0 ), "Failed to add pad" ) } } #[doc(alias = "gst_element_change_state")] fn change_state( &self, transition: StateChange, ) -> Result { unsafe { try_from_glib(ffi::gst_element_change_state( self.as_ref().to_glib_none().0, transition.into_glib(), )) } } #[doc(alias = "gst_element_continue_state")] fn continue_state( &self, ret: impl Into, ) -> Result { unsafe { try_from_glib(ffi::gst_element_continue_state( self.as_ref().to_glib_none().0, ret.into().into_glib(), )) } } #[doc(alias = "gst_element_create_all_pads")] fn create_all_pads(&self) { unsafe { ffi::gst_element_create_all_pads(self.as_ref().to_glib_none().0); } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_element_decorate_stream_id")] fn decorate_stream_id(&self, stream_id: &str) -> glib::GString { unsafe { from_glib_full(ffi::gst_element_decorate_stream_id( self.as_ref().to_glib_none().0, stream_id.to_glib_none().0, )) } } #[doc(alias = "gst_element_foreach_pad")] fn foreach_pad bool>(&self, func: P) -> bool { let mut func_data: P = func; unsafe extern "C" fn func_func bool>( element: *mut ffi::GstElement, pad: *mut ffi::GstPad, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let element = from_glib_borrow(element); let pad = from_glib_borrow(pad); let callback = user_data as *mut P; (*callback)(&element, &pad).into_glib() } let func = Some(func_func::

as _); let super_callback0: &mut P = &mut func_data; unsafe { from_glib(ffi::gst_element_foreach_pad( self.as_ref().to_glib_none().0, func, super_callback0 as *mut _ as *mut _, )) } } #[doc(alias = "gst_element_foreach_sink_pad")] fn foreach_sink_pad bool>(&self, func: P) -> bool { let mut func_data: P = func; unsafe extern "C" fn func_func bool>( element: *mut ffi::GstElement, pad: *mut ffi::GstPad, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let element = from_glib_borrow(element); let pad = from_glib_borrow(pad); let callback = user_data as *mut P; (*callback)(&element, &pad).into_glib() } let func = Some(func_func::

as _); let super_callback0: &mut P = &mut func_data; unsafe { from_glib(ffi::gst_element_foreach_sink_pad( self.as_ref().to_glib_none().0, func, super_callback0 as *mut _ as *mut _, )) } } #[doc(alias = "gst_element_foreach_src_pad")] fn foreach_src_pad bool>(&self, func: P) -> bool { let mut func_data: P = func; unsafe extern "C" fn func_func bool>( element: *mut ffi::GstElement, pad: *mut ffi::GstPad, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let element = from_glib_borrow(element); let pad = from_glib_borrow(pad); let callback = user_data as *mut P; (*callback)(&element, &pad).into_glib() } let func = Some(func_func::

as _); let super_callback0: &mut P = &mut func_data; unsafe { from_glib(ffi::gst_element_foreach_src_pad( self.as_ref().to_glib_none().0, func, super_callback0 as *mut _ as *mut _, )) } } #[doc(alias = "gst_element_get_base_time")] #[doc(alias = "get_base_time")] fn base_time(&self) -> Option { unsafe { from_glib(ffi::gst_element_get_base_time( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_element_get_bus")] #[doc(alias = "get_bus")] fn bus(&self) -> Option { unsafe { from_glib_full(ffi::gst_element_get_bus(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_element_get_clock")] #[doc(alias = "get_clock")] fn clock(&self) -> Option { unsafe { from_glib_full(ffi::gst_element_get_clock(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_element_get_compatible_pad")] #[doc(alias = "get_compatible_pad")] fn compatible_pad(&self, pad: &impl IsA, caps: Option<&Caps>) -> Option { unsafe { from_glib_full(ffi::gst_element_get_compatible_pad( self.as_ref().to_glib_none().0, pad.as_ref().to_glib_none().0, caps.to_glib_none().0, )) } } #[doc(alias = "gst_element_get_compatible_pad_template")] #[doc(alias = "get_compatible_pad_template")] fn compatible_pad_template(&self, compattempl: &PadTemplate) -> Option { unsafe { from_glib_none(ffi::gst_element_get_compatible_pad_template( self.as_ref().to_glib_none().0, compattempl.to_glib_none().0, )) } } #[doc(alias = "gst_element_get_context")] #[doc(alias = "get_context")] fn context(&self, context_type: &str) -> Option { unsafe { from_glib_full(ffi::gst_element_get_context( self.as_ref().to_glib_none().0, context_type.to_glib_none().0, )) } } #[doc(alias = "gst_element_get_contexts")] #[doc(alias = "get_contexts")] fn contexts(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_element_get_contexts( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_element_get_factory")] #[doc(alias = "get_factory")] fn factory(&self) -> Option { unsafe { from_glib_none(ffi::gst_element_get_factory(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_element_get_start_time")] #[doc(alias = "get_start_time")] fn start_time(&self) -> Option { unsafe { from_glib(ffi::gst_element_get_start_time( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_element_get_state")] #[doc(alias = "get_state")] fn state( &self, timeout: impl Into>, ) -> (Result, State, State) { unsafe { let mut state = std::mem::MaybeUninit::uninit(); let mut pending = std::mem::MaybeUninit::uninit(); let ret = try_from_glib(ffi::gst_element_get_state( self.as_ref().to_glib_none().0, state.as_mut_ptr(), pending.as_mut_ptr(), timeout.into().into_glib(), )); ( ret, from_glib(state.assume_init()), from_glib(pending.assume_init()), ) } } #[doc(alias = "gst_element_get_static_pad")] #[doc(alias = "get_static_pad")] fn static_pad(&self, name: &str) -> Option { unsafe { from_glib_full(ffi::gst_element_get_static_pad( self.as_ref().to_glib_none().0, name.to_glib_none().0, )) } } #[doc(alias = "gst_element_is_locked_state")] fn is_locked_state(&self) -> bool { unsafe { from_glib(ffi::gst_element_is_locked_state( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_element_lost_state")] fn lost_state(&self) { unsafe { ffi::gst_element_lost_state(self.as_ref().to_glib_none().0); } } #[doc(alias = "gst_element_no_more_pads")] fn no_more_pads(&self) { unsafe { ffi::gst_element_no_more_pads(self.as_ref().to_glib_none().0); } } #[doc(alias = "gst_element_post_message")] fn post_message(&self, message: Message) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_element_post_message( self.as_ref().to_glib_none().0, message.into_glib_ptr() ), "Failed to post message" ) } } #[doc(alias = "gst_element_provide_clock")] fn provide_clock(&self) -> Option { unsafe { from_glib_full(ffi::gst_element_provide_clock( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_element_release_request_pad")] fn release_request_pad(&self, pad: &impl IsA) { unsafe { ffi::gst_element_release_request_pad( self.as_ref().to_glib_none().0, pad.as_ref().to_glib_none().0, ); } } #[doc(alias = "gst_element_remove_pad")] fn remove_pad(&self, pad: &impl IsA) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_element_remove_pad( self.as_ref().to_glib_none().0, pad.as_ref().to_glib_none().0 ), "Failed to remove pad" ) } } #[doc(alias = "gst_element_request_pad")] fn request_pad( &self, templ: &PadTemplate, name: Option<&str>, caps: Option<&Caps>, ) -> Option { unsafe { from_glib_full(ffi::gst_element_request_pad( self.as_ref().to_glib_none().0, templ.to_glib_none().0, name.to_glib_none().0, caps.to_glib_none().0, )) } } #[doc(alias = "gst_element_set_base_time")] fn set_base_time(&self, time: ClockTime) { unsafe { ffi::gst_element_set_base_time(self.as_ref().to_glib_none().0, time.into_glib()); } } #[doc(alias = "gst_element_set_bus")] fn set_bus(&self, bus: Option<&Bus>) { unsafe { ffi::gst_element_set_bus(self.as_ref().to_glib_none().0, bus.to_glib_none().0); } } #[doc(alias = "gst_element_set_clock")] fn set_clock(&self, clock: Option<&impl IsA>) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_element_set_clock( self.as_ref().to_glib_none().0, clock.map(|p| p.as_ref()).to_glib_none().0 ), "Failed to set clock" ) } } #[doc(alias = "gst_element_set_context")] fn set_context(&self, context: &Context) { unsafe { ffi::gst_element_set_context(self.as_ref().to_glib_none().0, context.to_glib_none().0); } } #[doc(alias = "gst_element_set_locked_state")] fn set_locked_state(&self, locked_state: bool) -> bool { unsafe { from_glib(ffi::gst_element_set_locked_state( self.as_ref().to_glib_none().0, locked_state.into_glib(), )) } } #[doc(alias = "gst_element_set_start_time")] fn set_start_time(&self, time: impl Into>) { unsafe { ffi::gst_element_set_start_time( self.as_ref().to_glib_none().0, time.into().into_glib(), ); } } #[doc(alias = "gst_element_set_state")] fn set_state(&self, state: State) -> Result { unsafe { try_from_glib(ffi::gst_element_set_state( self.as_ref().to_glib_none().0, state.into_glib(), )) } } #[doc(alias = "gst_element_sync_state_with_parent")] fn sync_state_with_parent(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_element_sync_state_with_parent(self.as_ref().to_glib_none().0), "Failed to sync state with parent" ) } } #[doc(alias = "gst_element_unlink")] fn unlink(&self, dest: &impl IsA) { unsafe { ffi::gst_element_unlink( self.as_ref().to_glib_none().0, dest.as_ref().to_glib_none().0, ); } } #[doc(alias = "gst_element_unlink_pads")] fn unlink_pads(&self, srcpadname: &str, dest: &impl IsA, destpadname: &str) { unsafe { ffi::gst_element_unlink_pads( self.as_ref().to_glib_none().0, srcpadname.to_glib_none().0, dest.as_ref().to_glib_none().0, destpadname.to_glib_none().0, ); } } #[doc(alias = "no-more-pads")] fn connect_no_more_pads(&self, f: F) -> SignalHandlerId { unsafe extern "C" fn no_more_pads_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstElement, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Element::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"no-more-pads\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( no_more_pads_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "pad-added")] fn connect_pad_added( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn pad_added_trampoline< P: IsA, F: Fn(&P, &Pad) + Send + Sync + 'static, >( this: *mut ffi::GstElement, new_pad: *mut ffi::GstPad, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( Element::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(new_pad), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"pad-added\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( pad_added_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "pad-removed")] fn connect_pad_removed( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn pad_removed_trampoline< P: IsA, F: Fn(&P, &Pad) + Send + Sync + 'static, >( this: *mut ffi::GstElement, old_pad: *mut ffi::GstPad, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( Element::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(old_pad), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"pad-removed\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( pad_removed_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> ElementExt for O {} gstreamer-0.23.5/src/auto/element_factory.rs000064400000000000000000000060011046102023000171660ustar 00000000000000// 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::{ffi, Object, PluginFeature, URIType}; use glib::translate::*; glib::wrapper! { #[doc(alias = "GstElementFactory")] pub struct ElementFactory(Object) @extends PluginFeature, Object; match fn { type_ => || ffi::gst_element_factory_get_type(), } } impl ElementFactory { #[doc(alias = "gst_element_factory_get_element_type")] #[doc(alias = "get_element_type")] pub fn element_type(&self) -> glib::types::Type { unsafe { from_glib(ffi::gst_element_factory_get_element_type( self.to_glib_none().0, )) } } #[doc(alias = "gst_element_factory_get_metadata_keys")] #[doc(alias = "get_metadata_keys")] pub fn metadata_keys(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_element_factory_get_metadata_keys( self.to_glib_none().0, )) } } #[doc(alias = "gst_element_factory_get_num_pad_templates")] #[doc(alias = "get_num_pad_templates")] pub fn num_pad_templates(&self) -> u32 { unsafe { ffi::gst_element_factory_get_num_pad_templates(self.to_glib_none().0) } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[doc(alias = "gst_element_factory_get_skip_documentation")] #[doc(alias = "get_skip_documentation")] pub fn skips_documentation(&self) -> bool { unsafe { from_glib(ffi::gst_element_factory_get_skip_documentation( self.to_glib_none().0, )) } } #[doc(alias = "gst_element_factory_get_uri_protocols")] #[doc(alias = "get_uri_protocols")] pub fn uri_protocols(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::gst_element_factory_get_uri_protocols( self.to_glib_none().0, )) } } #[doc(alias = "gst_element_factory_get_uri_type")] #[doc(alias = "get_uri_type")] pub fn uri_type(&self) -> URIType { unsafe { from_glib(ffi::gst_element_factory_get_uri_type(self.to_glib_none().0)) } } #[doc(alias = "gst_element_factory_has_interface")] pub fn has_interface(&self, interfacename: &str) -> bool { unsafe { from_glib(ffi::gst_element_factory_has_interface( self.to_glib_none().0, interfacename.to_glib_none().0, )) } } #[doc(alias = "gst_element_factory_find")] pub fn find(name: &str) -> Option { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_element_factory_find(name.to_glib_none().0)) } } } unsafe impl Send for ElementFactory {} unsafe impl Sync for ElementFactory {} gstreamer-0.23.5/src/auto/enums.rs000064400000000000000000003672561046102023000151630ustar 00000000000000// 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::{ffi, EventTypeFlags}; use glib::{prelude::*, translate::*, GStr}; #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstBufferingMode")] pub enum BufferingMode { #[doc(alias = "GST_BUFFERING_STREAM")] Stream, #[doc(alias = "GST_BUFFERING_DOWNLOAD")] Download, #[doc(alias = "GST_BUFFERING_TIMESHIFT")] Timeshift, #[doc(alias = "GST_BUFFERING_LIVE")] Live, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for BufferingMode { type GlibType = ffi::GstBufferingMode; #[inline] fn into_glib(self) -> ffi::GstBufferingMode { match self { Self::Stream => ffi::GST_BUFFERING_STREAM, Self::Download => ffi::GST_BUFFERING_DOWNLOAD, Self::Timeshift => ffi::GST_BUFFERING_TIMESHIFT, Self::Live => ffi::GST_BUFFERING_LIVE, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for BufferingMode { #[inline] unsafe fn from_glib(value: ffi::GstBufferingMode) -> Self { skip_assert_initialized!(); match value { ffi::GST_BUFFERING_STREAM => Self::Stream, ffi::GST_BUFFERING_DOWNLOAD => Self::Download, ffi::GST_BUFFERING_TIMESHIFT => Self::Timeshift, ffi::GST_BUFFERING_LIVE => Self::Live, value => Self::__Unknown(value), } } } impl StaticType for BufferingMode { #[inline] #[doc(alias = "gst_buffering_mode_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_buffering_mode_get_type()) } } } impl glib::HasParamSpec for BufferingMode { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for BufferingMode { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for BufferingMode { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for BufferingMode { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: BufferingMode) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstBusSyncReply")] pub enum BusSyncReply { #[doc(alias = "GST_BUS_DROP")] Drop = ffi::GST_BUS_DROP, #[doc(alias = "GST_BUS_PASS")] Pass = ffi::GST_BUS_PASS, #[doc(alias = "GST_BUS_ASYNC")] Async = ffi::GST_BUS_ASYNC, } #[doc(hidden)] impl IntoGlib for BusSyncReply { type GlibType = ffi::GstBusSyncReply; #[inline] fn into_glib(self) -> ffi::GstBusSyncReply { self as ffi::GstBusSyncReply } } #[doc(hidden)] impl FromGlib for BusSyncReply { #[inline] unsafe fn from_glib(value: ffi::GstBusSyncReply) -> Self { skip_assert_initialized!(); debug_assert!([ffi::GST_BUS_DROP, ffi::GST_BUS_PASS, ffi::GST_BUS_ASYNC].contains(&value)); std::mem::transmute(value) } } impl StaticType for BusSyncReply { #[inline] #[doc(alias = "gst_bus_sync_reply_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_bus_sync_reply_get_type()) } } } impl glib::HasParamSpec for BusSyncReply { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for BusSyncReply { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for BusSyncReply { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for BusSyncReply { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: BusSyncReply) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstCapsIntersectMode")] pub enum CapsIntersectMode { #[doc(alias = "GST_CAPS_INTERSECT_ZIG_ZAG")] ZigZag, #[doc(alias = "GST_CAPS_INTERSECT_FIRST")] First, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for CapsIntersectMode { type GlibType = ffi::GstCapsIntersectMode; #[inline] fn into_glib(self) -> ffi::GstCapsIntersectMode { match self { Self::ZigZag => ffi::GST_CAPS_INTERSECT_ZIG_ZAG, Self::First => ffi::GST_CAPS_INTERSECT_FIRST, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for CapsIntersectMode { #[inline] unsafe fn from_glib(value: ffi::GstCapsIntersectMode) -> Self { skip_assert_initialized!(); match value { ffi::GST_CAPS_INTERSECT_ZIG_ZAG => Self::ZigZag, ffi::GST_CAPS_INTERSECT_FIRST => Self::First, value => Self::__Unknown(value), } } } impl StaticType for CapsIntersectMode { #[inline] #[doc(alias = "gst_caps_intersect_mode_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_caps_intersect_mode_get_type()) } } } impl glib::HasParamSpec for CapsIntersectMode { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for CapsIntersectMode { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for CapsIntersectMode { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for CapsIntersectMode { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: CapsIntersectMode) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstClockEntryType")] pub enum ClockEntryType { #[doc(alias = "GST_CLOCK_ENTRY_SINGLE")] Single, #[doc(alias = "GST_CLOCK_ENTRY_PERIODIC")] Periodic, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for ClockEntryType { type GlibType = ffi::GstClockEntryType; #[inline] fn into_glib(self) -> ffi::GstClockEntryType { match self { Self::Single => ffi::GST_CLOCK_ENTRY_SINGLE, Self::Periodic => ffi::GST_CLOCK_ENTRY_PERIODIC, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for ClockEntryType { #[inline] unsafe fn from_glib(value: ffi::GstClockEntryType) -> Self { skip_assert_initialized!(); match value { ffi::GST_CLOCK_ENTRY_SINGLE => Self::Single, ffi::GST_CLOCK_ENTRY_PERIODIC => Self::Periodic, value => Self::__Unknown(value), } } } impl StaticType for ClockEntryType { #[inline] #[doc(alias = "gst_clock_entry_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_clock_entry_type_get_type()) } } } impl glib::HasParamSpec for ClockEntryType { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for ClockEntryType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for ClockEntryType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for ClockEntryType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: ClockEntryType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[must_use] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstClockReturn")] pub enum ClockReturn { #[doc(alias = "GST_CLOCK_OK")] Ok = ffi::GST_CLOCK_OK, #[doc(alias = "GST_CLOCK_EARLY")] Early = ffi::GST_CLOCK_EARLY, #[doc(alias = "GST_CLOCK_UNSCHEDULED")] Unscheduled = ffi::GST_CLOCK_UNSCHEDULED, #[doc(alias = "GST_CLOCK_BUSY")] Busy = ffi::GST_CLOCK_BUSY, #[doc(alias = "GST_CLOCK_BADTIME")] Badtime = ffi::GST_CLOCK_BADTIME, #[doc(alias = "GST_CLOCK_ERROR")] Error = ffi::GST_CLOCK_ERROR, #[doc(alias = "GST_CLOCK_UNSUPPORTED")] Unsupported = ffi::GST_CLOCK_UNSUPPORTED, #[doc(alias = "GST_CLOCK_DONE")] Done = ffi::GST_CLOCK_DONE, } #[doc(hidden)] impl IntoGlib for ClockReturn { type GlibType = ffi::GstClockReturn; #[inline] fn into_glib(self) -> ffi::GstClockReturn { self as ffi::GstClockReturn } } #[doc(hidden)] impl FromGlib for ClockReturn { #[inline] unsafe fn from_glib(value: ffi::GstClockReturn) -> Self { skip_assert_initialized!(); debug_assert!([ ffi::GST_CLOCK_OK, ffi::GST_CLOCK_EARLY, ffi::GST_CLOCK_UNSCHEDULED, ffi::GST_CLOCK_BUSY, ffi::GST_CLOCK_BADTIME, ffi::GST_CLOCK_ERROR, ffi::GST_CLOCK_UNSUPPORTED, ffi::GST_CLOCK_DONE ] .contains(&value)); std::mem::transmute(value) } } impl StaticType for ClockReturn { #[inline] #[doc(alias = "gst_clock_return_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_clock_return_get_type()) } } } impl glib::HasParamSpec for ClockReturn { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for ClockReturn { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for ClockReturn { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for ClockReturn { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: ClockReturn) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstClockType")] pub enum ClockType { #[doc(alias = "GST_CLOCK_TYPE_REALTIME")] Realtime, #[doc(alias = "GST_CLOCK_TYPE_MONOTONIC")] Monotonic, #[doc(alias = "GST_CLOCK_TYPE_OTHER")] Other, #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "GST_CLOCK_TYPE_TAI")] Tai, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for ClockType { type GlibType = ffi::GstClockType; #[inline] fn into_glib(self) -> ffi::GstClockType { match self { Self::Realtime => ffi::GST_CLOCK_TYPE_REALTIME, Self::Monotonic => ffi::GST_CLOCK_TYPE_MONOTONIC, Self::Other => ffi::GST_CLOCK_TYPE_OTHER, #[cfg(feature = "v1_18")] Self::Tai => ffi::GST_CLOCK_TYPE_TAI, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for ClockType { #[inline] unsafe fn from_glib(value: ffi::GstClockType) -> Self { skip_assert_initialized!(); match value { ffi::GST_CLOCK_TYPE_REALTIME => Self::Realtime, ffi::GST_CLOCK_TYPE_MONOTONIC => Self::Monotonic, ffi::GST_CLOCK_TYPE_OTHER => Self::Other, #[cfg(feature = "v1_18")] ffi::GST_CLOCK_TYPE_TAI => Self::Tai, value => Self::__Unknown(value), } } } impl StaticType for ClockType { #[inline] #[doc(alias = "gst_clock_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_clock_type_get_type()) } } } impl glib::HasParamSpec for ClockType { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for ClockType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for ClockType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for ClockType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: ClockType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstCoreError")] pub enum CoreError { #[doc(alias = "GST_CORE_ERROR_FAILED")] Failed, #[doc(alias = "GST_CORE_ERROR_TOO_LAZY")] TooLazy, #[doc(alias = "GST_CORE_ERROR_NOT_IMPLEMENTED")] NotImplemented, #[doc(alias = "GST_CORE_ERROR_STATE_CHANGE")] StateChange, #[doc(alias = "GST_CORE_ERROR_PAD")] Pad, #[doc(alias = "GST_CORE_ERROR_THREAD")] Thread, #[doc(alias = "GST_CORE_ERROR_NEGOTIATION")] Negotiation, #[doc(alias = "GST_CORE_ERROR_EVENT")] Event, #[doc(alias = "GST_CORE_ERROR_SEEK")] Seek, #[doc(alias = "GST_CORE_ERROR_CAPS")] Caps, #[doc(alias = "GST_CORE_ERROR_TAG")] Tag, #[doc(alias = "GST_CORE_ERROR_MISSING_PLUGIN")] MissingPlugin, #[doc(alias = "GST_CORE_ERROR_CLOCK")] Clock, #[doc(alias = "GST_CORE_ERROR_DISABLED")] Disabled, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for CoreError { type GlibType = ffi::GstCoreError; fn into_glib(self) -> ffi::GstCoreError { match self { Self::Failed => ffi::GST_CORE_ERROR_FAILED, Self::TooLazy => ffi::GST_CORE_ERROR_TOO_LAZY, Self::NotImplemented => ffi::GST_CORE_ERROR_NOT_IMPLEMENTED, Self::StateChange => ffi::GST_CORE_ERROR_STATE_CHANGE, Self::Pad => ffi::GST_CORE_ERROR_PAD, Self::Thread => ffi::GST_CORE_ERROR_THREAD, Self::Negotiation => ffi::GST_CORE_ERROR_NEGOTIATION, Self::Event => ffi::GST_CORE_ERROR_EVENT, Self::Seek => ffi::GST_CORE_ERROR_SEEK, Self::Caps => ffi::GST_CORE_ERROR_CAPS, Self::Tag => ffi::GST_CORE_ERROR_TAG, Self::MissingPlugin => ffi::GST_CORE_ERROR_MISSING_PLUGIN, Self::Clock => ffi::GST_CORE_ERROR_CLOCK, Self::Disabled => ffi::GST_CORE_ERROR_DISABLED, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for CoreError { unsafe fn from_glib(value: ffi::GstCoreError) -> Self { skip_assert_initialized!(); match value { ffi::GST_CORE_ERROR_FAILED => Self::Failed, ffi::GST_CORE_ERROR_TOO_LAZY => Self::TooLazy, ffi::GST_CORE_ERROR_NOT_IMPLEMENTED => Self::NotImplemented, ffi::GST_CORE_ERROR_STATE_CHANGE => Self::StateChange, ffi::GST_CORE_ERROR_PAD => Self::Pad, ffi::GST_CORE_ERROR_THREAD => Self::Thread, ffi::GST_CORE_ERROR_NEGOTIATION => Self::Negotiation, ffi::GST_CORE_ERROR_EVENT => Self::Event, ffi::GST_CORE_ERROR_SEEK => Self::Seek, ffi::GST_CORE_ERROR_CAPS => Self::Caps, ffi::GST_CORE_ERROR_TAG => Self::Tag, ffi::GST_CORE_ERROR_MISSING_PLUGIN => Self::MissingPlugin, ffi::GST_CORE_ERROR_CLOCK => Self::Clock, ffi::GST_CORE_ERROR_DISABLED => Self::Disabled, value => Self::__Unknown(value), } } } impl glib::error::ErrorDomain for CoreError { #[inline] fn domain() -> glib::Quark { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_core_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { skip_assert_initialized!(); match unsafe { from_glib(code) } { Self::__Unknown(_) => Some(Self::Failed), value => Some(value), } } } impl StaticType for CoreError { #[inline] #[doc(alias = "gst_core_error_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_core_error_get_type()) } } } impl glib::HasParamSpec for CoreError { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for CoreError { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for CoreError { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for CoreError { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: CoreError) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstDebugLevel")] pub enum DebugLevel { #[doc(alias = "GST_LEVEL_NONE")] None, #[doc(alias = "GST_LEVEL_ERROR")] Error, #[doc(alias = "GST_LEVEL_WARNING")] Warning, #[doc(alias = "GST_LEVEL_FIXME")] Fixme, #[doc(alias = "GST_LEVEL_INFO")] Info, #[doc(alias = "GST_LEVEL_DEBUG")] Debug, #[doc(alias = "GST_LEVEL_LOG")] Log, #[doc(alias = "GST_LEVEL_TRACE")] Trace, #[doc(alias = "GST_LEVEL_MEMDUMP")] Memdump, #[doc(hidden)] __Unknown(i32), } impl DebugLevel { pub fn name<'a>(self) -> &'a GStr { unsafe { GStr::from_ptr( ffi::gst_debug_level_get_name(self.into_glib()) .as_ref() .expect("gst_debug_level_get_name returned NULL"), ) } } } impl std::fmt::Display for DebugLevel { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(&self.name()) } } #[doc(hidden)] impl IntoGlib for DebugLevel { type GlibType = ffi::GstDebugLevel; #[inline] fn into_glib(self) -> ffi::GstDebugLevel { match self { Self::None => ffi::GST_LEVEL_NONE, Self::Error => ffi::GST_LEVEL_ERROR, Self::Warning => ffi::GST_LEVEL_WARNING, Self::Fixme => ffi::GST_LEVEL_FIXME, Self::Info => ffi::GST_LEVEL_INFO, Self::Debug => ffi::GST_LEVEL_DEBUG, Self::Log => ffi::GST_LEVEL_LOG, Self::Trace => ffi::GST_LEVEL_TRACE, Self::Memdump => ffi::GST_LEVEL_MEMDUMP, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for DebugLevel { #[inline] unsafe fn from_glib(value: ffi::GstDebugLevel) -> Self { skip_assert_initialized!(); match value { ffi::GST_LEVEL_NONE => Self::None, ffi::GST_LEVEL_ERROR => Self::Error, ffi::GST_LEVEL_WARNING => Self::Warning, ffi::GST_LEVEL_FIXME => Self::Fixme, ffi::GST_LEVEL_INFO => Self::Info, ffi::GST_LEVEL_DEBUG => Self::Debug, ffi::GST_LEVEL_LOG => Self::Log, ffi::GST_LEVEL_TRACE => Self::Trace, ffi::GST_LEVEL_MEMDUMP => Self::Memdump, value => Self::__Unknown(value), } } } impl StaticType for DebugLevel { #[inline] #[doc(alias = "gst_debug_level_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_debug_level_get_type()) } } } impl glib::HasParamSpec for DebugLevel { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for DebugLevel { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for DebugLevel { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for DebugLevel { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: DebugLevel) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstEventType")] pub enum EventType { #[doc(alias = "GST_EVENT_UNKNOWN")] Unknown, #[doc(alias = "GST_EVENT_FLUSH_START")] FlushStart, #[doc(alias = "GST_EVENT_FLUSH_STOP")] FlushStop, #[doc(alias = "GST_EVENT_STREAM_START")] StreamStart, #[doc(alias = "GST_EVENT_CAPS")] Caps, #[doc(alias = "GST_EVENT_SEGMENT")] Segment, #[doc(alias = "GST_EVENT_STREAM_COLLECTION")] StreamCollection, #[doc(alias = "GST_EVENT_TAG")] Tag, #[doc(alias = "GST_EVENT_BUFFERSIZE")] Buffersize, #[doc(alias = "GST_EVENT_SINK_MESSAGE")] SinkMessage, #[doc(alias = "GST_EVENT_STREAM_GROUP_DONE")] StreamGroupDone, #[doc(alias = "GST_EVENT_EOS")] Eos, #[doc(alias = "GST_EVENT_TOC")] Toc, #[doc(alias = "GST_EVENT_PROTECTION")] Protection, #[doc(alias = "GST_EVENT_SEGMENT_DONE")] SegmentDone, #[doc(alias = "GST_EVENT_GAP")] Gap, #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "GST_EVENT_INSTANT_RATE_CHANGE")] InstantRateChange, #[doc(alias = "GST_EVENT_QOS")] Qos, #[doc(alias = "GST_EVENT_SEEK")] Seek, #[doc(alias = "GST_EVENT_NAVIGATION")] Navigation, #[doc(alias = "GST_EVENT_LATENCY")] Latency, #[doc(alias = "GST_EVENT_STEP")] Step, #[doc(alias = "GST_EVENT_RECONFIGURE")] Reconfigure, #[doc(alias = "GST_EVENT_TOC_SELECT")] TocSelect, #[doc(alias = "GST_EVENT_SELECT_STREAMS")] SelectStreams, #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "GST_EVENT_INSTANT_RATE_SYNC_TIME")] InstantRateSyncTime, #[doc(alias = "GST_EVENT_CUSTOM_UPSTREAM")] CustomUpstream, #[doc(alias = "GST_EVENT_CUSTOM_DOWNSTREAM")] CustomDownstream, #[doc(alias = "GST_EVENT_CUSTOM_DOWNSTREAM_OOB")] CustomDownstreamOob, #[doc(alias = "GST_EVENT_CUSTOM_DOWNSTREAM_STICKY")] CustomDownstreamSticky, #[doc(alias = "GST_EVENT_CUSTOM_BOTH")] CustomBoth, #[doc(alias = "GST_EVENT_CUSTOM_BOTH_OOB")] CustomBothOob, #[doc(hidden)] __Unknown(i32), } impl EventType { #[doc(alias = "gst_event_type_get_flags")] #[doc(alias = "get_flags")] pub fn flags(self) -> EventTypeFlags { assert_initialized_main_thread!(); unsafe { from_glib(ffi::gst_event_type_get_flags(self.into_glib())) } } pub fn name<'a>(self) -> &'a GStr { unsafe { GStr::from_ptr( ffi::gst_event_type_get_name(self.into_glib()) .as_ref() .expect("gst_event_type_get_name returned NULL"), ) } } #[doc(alias = "gst_event_type_to_quark")] pub fn to_quark(self) -> glib::Quark { assert_initialized_main_thread!(); unsafe { from_glib(ffi::gst_event_type_to_quark(self.into_glib())) } } } impl std::fmt::Display for EventType { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(&self.name()) } } #[doc(hidden)] impl IntoGlib for EventType { type GlibType = ffi::GstEventType; fn into_glib(self) -> ffi::GstEventType { match self { Self::Unknown => ffi::GST_EVENT_UNKNOWN, Self::FlushStart => ffi::GST_EVENT_FLUSH_START, Self::FlushStop => ffi::GST_EVENT_FLUSH_STOP, Self::StreamStart => ffi::GST_EVENT_STREAM_START, Self::Caps => ffi::GST_EVENT_CAPS, Self::Segment => ffi::GST_EVENT_SEGMENT, Self::StreamCollection => ffi::GST_EVENT_STREAM_COLLECTION, Self::Tag => ffi::GST_EVENT_TAG, Self::Buffersize => ffi::GST_EVENT_BUFFERSIZE, Self::SinkMessage => ffi::GST_EVENT_SINK_MESSAGE, Self::StreamGroupDone => ffi::GST_EVENT_STREAM_GROUP_DONE, Self::Eos => ffi::GST_EVENT_EOS, Self::Toc => ffi::GST_EVENT_TOC, Self::Protection => ffi::GST_EVENT_PROTECTION, Self::SegmentDone => ffi::GST_EVENT_SEGMENT_DONE, Self::Gap => ffi::GST_EVENT_GAP, #[cfg(feature = "v1_18")] Self::InstantRateChange => ffi::GST_EVENT_INSTANT_RATE_CHANGE, Self::Qos => ffi::GST_EVENT_QOS, Self::Seek => ffi::GST_EVENT_SEEK, Self::Navigation => ffi::GST_EVENT_NAVIGATION, Self::Latency => ffi::GST_EVENT_LATENCY, Self::Step => ffi::GST_EVENT_STEP, Self::Reconfigure => ffi::GST_EVENT_RECONFIGURE, Self::TocSelect => ffi::GST_EVENT_TOC_SELECT, Self::SelectStreams => ffi::GST_EVENT_SELECT_STREAMS, #[cfg(feature = "v1_18")] Self::InstantRateSyncTime => ffi::GST_EVENT_INSTANT_RATE_SYNC_TIME, Self::CustomUpstream => ffi::GST_EVENT_CUSTOM_UPSTREAM, Self::CustomDownstream => ffi::GST_EVENT_CUSTOM_DOWNSTREAM, Self::CustomDownstreamOob => ffi::GST_EVENT_CUSTOM_DOWNSTREAM_OOB, Self::CustomDownstreamSticky => ffi::GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, Self::CustomBoth => ffi::GST_EVENT_CUSTOM_BOTH, Self::CustomBothOob => ffi::GST_EVENT_CUSTOM_BOTH_OOB, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for EventType { unsafe fn from_glib(value: ffi::GstEventType) -> Self { skip_assert_initialized!(); match value { ffi::GST_EVENT_UNKNOWN => Self::Unknown, ffi::GST_EVENT_FLUSH_START => Self::FlushStart, ffi::GST_EVENT_FLUSH_STOP => Self::FlushStop, ffi::GST_EVENT_STREAM_START => Self::StreamStart, ffi::GST_EVENT_CAPS => Self::Caps, ffi::GST_EVENT_SEGMENT => Self::Segment, ffi::GST_EVENT_STREAM_COLLECTION => Self::StreamCollection, ffi::GST_EVENT_TAG => Self::Tag, ffi::GST_EVENT_BUFFERSIZE => Self::Buffersize, ffi::GST_EVENT_SINK_MESSAGE => Self::SinkMessage, ffi::GST_EVENT_STREAM_GROUP_DONE => Self::StreamGroupDone, ffi::GST_EVENT_EOS => Self::Eos, ffi::GST_EVENT_TOC => Self::Toc, ffi::GST_EVENT_PROTECTION => Self::Protection, ffi::GST_EVENT_SEGMENT_DONE => Self::SegmentDone, ffi::GST_EVENT_GAP => Self::Gap, #[cfg(feature = "v1_18")] ffi::GST_EVENT_INSTANT_RATE_CHANGE => Self::InstantRateChange, ffi::GST_EVENT_QOS => Self::Qos, ffi::GST_EVENT_SEEK => Self::Seek, ffi::GST_EVENT_NAVIGATION => Self::Navigation, ffi::GST_EVENT_LATENCY => Self::Latency, ffi::GST_EVENT_STEP => Self::Step, ffi::GST_EVENT_RECONFIGURE => Self::Reconfigure, ffi::GST_EVENT_TOC_SELECT => Self::TocSelect, ffi::GST_EVENT_SELECT_STREAMS => Self::SelectStreams, #[cfg(feature = "v1_18")] ffi::GST_EVENT_INSTANT_RATE_SYNC_TIME => Self::InstantRateSyncTime, ffi::GST_EVENT_CUSTOM_UPSTREAM => Self::CustomUpstream, ffi::GST_EVENT_CUSTOM_DOWNSTREAM => Self::CustomDownstream, ffi::GST_EVENT_CUSTOM_DOWNSTREAM_OOB => Self::CustomDownstreamOob, ffi::GST_EVENT_CUSTOM_DOWNSTREAM_STICKY => Self::CustomDownstreamSticky, ffi::GST_EVENT_CUSTOM_BOTH => Self::CustomBoth, ffi::GST_EVENT_CUSTOM_BOTH_OOB => Self::CustomBothOob, value => Self::__Unknown(value), } } } impl StaticType for EventType { #[inline] #[doc(alias = "gst_event_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_event_type_get_type()) } } } impl glib::HasParamSpec for EventType { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for EventType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for EventType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for EventType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: EventType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstFormat")] pub enum Format { #[doc(alias = "GST_FORMAT_UNDEFINED")] Undefined, #[doc(alias = "GST_FORMAT_DEFAULT")] Default, #[doc(alias = "GST_FORMAT_BYTES")] Bytes, #[doc(alias = "GST_FORMAT_TIME")] Time, #[doc(alias = "GST_FORMAT_BUFFERS")] Buffers, #[doc(alias = "GST_FORMAT_PERCENT")] Percent, #[doc(hidden)] __Unknown(i32), } impl Format { #[doc(alias = "gst_format_get_by_nick")] #[doc(alias = "get_by_nick")] pub fn by_nick(nick: &str) -> Format { assert_initialized_main_thread!(); unsafe { from_glib(ffi::gst_format_get_by_nick(nick.to_glib_none().0)) } } //#[doc(alias = "gst_format_get_details")] //#[doc(alias = "get_details")] //pub fn details(self) -> /*Ignored*/Option { // unsafe { TODO: call ffi:gst_format_get_details() } //} #[doc(alias = "gst_format_get_name")] #[doc(alias = "get_name")] pub fn name(self) -> Option { assert_initialized_main_thread!(); unsafe { from_glib_none(ffi::gst_format_get_name(self.into_glib())) } } //#[doc(alias = "gst_format_iterate_definitions")] //pub fn iterate_definitions() -> /*Ignored*/Iterator { // unsafe { TODO: call ffi:gst_format_iterate_definitions() } //} #[doc(alias = "gst_format_to_quark")] pub fn to_quark(self) -> glib::Quark { assert_initialized_main_thread!(); unsafe { from_glib(ffi::gst_format_to_quark(self.into_glib())) } } } #[doc(hidden)] impl IntoGlib for Format { type GlibType = ffi::GstFormat; #[inline] fn into_glib(self) -> ffi::GstFormat { match self { Self::Undefined => ffi::GST_FORMAT_UNDEFINED, Self::Default => ffi::GST_FORMAT_DEFAULT, Self::Bytes => ffi::GST_FORMAT_BYTES, Self::Time => ffi::GST_FORMAT_TIME, Self::Buffers => ffi::GST_FORMAT_BUFFERS, Self::Percent => ffi::GST_FORMAT_PERCENT, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for Format { #[inline] unsafe fn from_glib(value: ffi::GstFormat) -> Self { skip_assert_initialized!(); match value { ffi::GST_FORMAT_UNDEFINED => Self::Undefined, ffi::GST_FORMAT_DEFAULT => Self::Default, ffi::GST_FORMAT_BYTES => Self::Bytes, ffi::GST_FORMAT_TIME => Self::Time, ffi::GST_FORMAT_BUFFERS => Self::Buffers, ffi::GST_FORMAT_PERCENT => Self::Percent, value => Self::__Unknown(value), } } } impl StaticType for Format { #[inline] #[doc(alias = "gst_format_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_format_get_type()) } } } impl glib::HasParamSpec for Format { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for Format { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for Format { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for Format { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: Format) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstLibraryError")] pub enum LibraryError { #[doc(alias = "GST_LIBRARY_ERROR_FAILED")] Failed, #[doc(alias = "GST_LIBRARY_ERROR_TOO_LAZY")] TooLazy, #[doc(alias = "GST_LIBRARY_ERROR_INIT")] Init, #[doc(alias = "GST_LIBRARY_ERROR_SHUTDOWN")] Shutdown, #[doc(alias = "GST_LIBRARY_ERROR_SETTINGS")] Settings, #[doc(alias = "GST_LIBRARY_ERROR_ENCODE")] Encode, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for LibraryError { type GlibType = ffi::GstLibraryError; #[inline] fn into_glib(self) -> ffi::GstLibraryError { match self { Self::Failed => ffi::GST_LIBRARY_ERROR_FAILED, Self::TooLazy => ffi::GST_LIBRARY_ERROR_TOO_LAZY, Self::Init => ffi::GST_LIBRARY_ERROR_INIT, Self::Shutdown => ffi::GST_LIBRARY_ERROR_SHUTDOWN, Self::Settings => ffi::GST_LIBRARY_ERROR_SETTINGS, Self::Encode => ffi::GST_LIBRARY_ERROR_ENCODE, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for LibraryError { #[inline] unsafe fn from_glib(value: ffi::GstLibraryError) -> Self { skip_assert_initialized!(); match value { ffi::GST_LIBRARY_ERROR_FAILED => Self::Failed, ffi::GST_LIBRARY_ERROR_TOO_LAZY => Self::TooLazy, ffi::GST_LIBRARY_ERROR_INIT => Self::Init, ffi::GST_LIBRARY_ERROR_SHUTDOWN => Self::Shutdown, ffi::GST_LIBRARY_ERROR_SETTINGS => Self::Settings, ffi::GST_LIBRARY_ERROR_ENCODE => Self::Encode, value => Self::__Unknown(value), } } } impl glib::error::ErrorDomain for LibraryError { #[inline] fn domain() -> glib::Quark { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_library_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { skip_assert_initialized!(); match unsafe { from_glib(code) } { Self::__Unknown(_) => Some(Self::Failed), value => Some(value), } } } impl StaticType for LibraryError { #[inline] #[doc(alias = "gst_library_error_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_library_error_get_type()) } } } impl glib::HasParamSpec for LibraryError { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for LibraryError { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for LibraryError { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for LibraryError { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: LibraryError) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstPadDirection")] pub enum PadDirection { #[doc(alias = "GST_PAD_UNKNOWN")] Unknown = ffi::GST_PAD_UNKNOWN, #[doc(alias = "GST_PAD_SRC")] Src = ffi::GST_PAD_SRC, #[doc(alias = "GST_PAD_SINK")] Sink = ffi::GST_PAD_SINK, } #[doc(hidden)] impl IntoGlib for PadDirection { type GlibType = ffi::GstPadDirection; #[inline] fn into_glib(self) -> ffi::GstPadDirection { self as ffi::GstPadDirection } } #[doc(hidden)] impl FromGlib for PadDirection { #[inline] unsafe fn from_glib(value: ffi::GstPadDirection) -> Self { skip_assert_initialized!(); debug_assert!([ffi::GST_PAD_UNKNOWN, ffi::GST_PAD_SRC, ffi::GST_PAD_SINK].contains(&value)); std::mem::transmute(value) } } impl StaticType for PadDirection { #[inline] #[doc(alias = "gst_pad_direction_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_pad_direction_get_type()) } } } impl glib::HasParamSpec for PadDirection { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for PadDirection { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PadDirection { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for PadDirection { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PadDirection) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstPadMode")] pub enum PadMode { #[doc(alias = "GST_PAD_MODE_NONE")] None = ffi::GST_PAD_MODE_NONE, #[doc(alias = "GST_PAD_MODE_PUSH")] Push = ffi::GST_PAD_MODE_PUSH, #[doc(alias = "GST_PAD_MODE_PULL")] Pull = ffi::GST_PAD_MODE_PULL, } impl PadMode { pub fn name<'a>(self) -> &'a GStr { unsafe { GStr::from_ptr( ffi::gst_pad_mode_get_name(self.into_glib()) .as_ref() .expect("gst_pad_mode_get_name returned NULL"), ) } } } impl std::fmt::Display for PadMode { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(&self.name()) } } #[doc(hidden)] impl IntoGlib for PadMode { type GlibType = ffi::GstPadMode; #[inline] fn into_glib(self) -> ffi::GstPadMode { self as ffi::GstPadMode } } #[doc(hidden)] impl FromGlib for PadMode { #[inline] unsafe fn from_glib(value: ffi::GstPadMode) -> Self { skip_assert_initialized!(); debug_assert!([ ffi::GST_PAD_MODE_NONE, ffi::GST_PAD_MODE_PUSH, ffi::GST_PAD_MODE_PULL ] .contains(&value)); std::mem::transmute(value) } } impl StaticType for PadMode { #[inline] #[doc(alias = "gst_pad_mode_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_pad_mode_get_type()) } } } impl glib::HasParamSpec for PadMode { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for PadMode { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PadMode { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for PadMode { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PadMode) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstPadPresence")] pub enum PadPresence { #[doc(alias = "GST_PAD_ALWAYS")] Always = ffi::GST_PAD_ALWAYS, #[doc(alias = "GST_PAD_SOMETIMES")] Sometimes = ffi::GST_PAD_SOMETIMES, #[doc(alias = "GST_PAD_REQUEST")] Request = ffi::GST_PAD_REQUEST, } #[doc(hidden)] impl IntoGlib for PadPresence { type GlibType = ffi::GstPadPresence; #[inline] fn into_glib(self) -> ffi::GstPadPresence { self as ffi::GstPadPresence } } #[doc(hidden)] impl FromGlib for PadPresence { #[inline] unsafe fn from_glib(value: ffi::GstPadPresence) -> Self { skip_assert_initialized!(); debug_assert!([ ffi::GST_PAD_ALWAYS, ffi::GST_PAD_SOMETIMES, ffi::GST_PAD_REQUEST ] .contains(&value)); std::mem::transmute(value) } } impl StaticType for PadPresence { #[inline] #[doc(alias = "gst_pad_presence_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_pad_presence_get_type()) } } } impl glib::HasParamSpec for PadPresence { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for PadPresence { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PadPresence { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for PadPresence { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PadPresence) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstPadProbeReturn")] pub enum PadProbeReturn { #[doc(alias = "GST_PAD_PROBE_DROP")] Drop = ffi::GST_PAD_PROBE_DROP, #[doc(alias = "GST_PAD_PROBE_OK")] Ok = ffi::GST_PAD_PROBE_OK, #[doc(alias = "GST_PAD_PROBE_REMOVE")] Remove = ffi::GST_PAD_PROBE_REMOVE, #[doc(alias = "GST_PAD_PROBE_PASS")] Pass = ffi::GST_PAD_PROBE_PASS, #[doc(alias = "GST_PAD_PROBE_HANDLED")] Handled = ffi::GST_PAD_PROBE_HANDLED, } #[doc(hidden)] impl IntoGlib for PadProbeReturn { type GlibType = ffi::GstPadProbeReturn; #[inline] fn into_glib(self) -> ffi::GstPadProbeReturn { self as ffi::GstPadProbeReturn } } #[doc(hidden)] impl FromGlib for PadProbeReturn { #[inline] unsafe fn from_glib(value: ffi::GstPadProbeReturn) -> Self { skip_assert_initialized!(); debug_assert!([ ffi::GST_PAD_PROBE_DROP, ffi::GST_PAD_PROBE_OK, ffi::GST_PAD_PROBE_REMOVE, ffi::GST_PAD_PROBE_PASS, ffi::GST_PAD_PROBE_HANDLED ] .contains(&value)); std::mem::transmute(value) } } impl StaticType for PadProbeReturn { #[inline] #[doc(alias = "gst_pad_probe_return_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_pad_probe_return_get_type()) } } } impl glib::HasParamSpec for PadProbeReturn { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for PadProbeReturn { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PadProbeReturn { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for PadProbeReturn { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PadProbeReturn) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstParseError")] pub enum ParseError { #[doc(alias = "GST_PARSE_ERROR_SYNTAX")] Syntax, #[doc(alias = "GST_PARSE_ERROR_NO_SUCH_ELEMENT")] NoSuchElement, #[doc(alias = "GST_PARSE_ERROR_NO_SUCH_PROPERTY")] NoSuchProperty, #[doc(alias = "GST_PARSE_ERROR_LINK")] Link, #[doc(alias = "GST_PARSE_ERROR_COULD_NOT_SET_PROPERTY")] CouldNotSetProperty, #[doc(alias = "GST_PARSE_ERROR_EMPTY_BIN")] EmptyBin, #[doc(alias = "GST_PARSE_ERROR_EMPTY")] Empty, #[doc(alias = "GST_PARSE_ERROR_DELAYED_LINK")] DelayedLink, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for ParseError { type GlibType = ffi::GstParseError; #[inline] fn into_glib(self) -> ffi::GstParseError { match self { Self::Syntax => ffi::GST_PARSE_ERROR_SYNTAX, Self::NoSuchElement => ffi::GST_PARSE_ERROR_NO_SUCH_ELEMENT, Self::NoSuchProperty => ffi::GST_PARSE_ERROR_NO_SUCH_PROPERTY, Self::Link => ffi::GST_PARSE_ERROR_LINK, Self::CouldNotSetProperty => ffi::GST_PARSE_ERROR_COULD_NOT_SET_PROPERTY, Self::EmptyBin => ffi::GST_PARSE_ERROR_EMPTY_BIN, Self::Empty => ffi::GST_PARSE_ERROR_EMPTY, Self::DelayedLink => ffi::GST_PARSE_ERROR_DELAYED_LINK, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for ParseError { #[inline] unsafe fn from_glib(value: ffi::GstParseError) -> Self { skip_assert_initialized!(); match value { ffi::GST_PARSE_ERROR_SYNTAX => Self::Syntax, ffi::GST_PARSE_ERROR_NO_SUCH_ELEMENT => Self::NoSuchElement, ffi::GST_PARSE_ERROR_NO_SUCH_PROPERTY => Self::NoSuchProperty, ffi::GST_PARSE_ERROR_LINK => Self::Link, ffi::GST_PARSE_ERROR_COULD_NOT_SET_PROPERTY => Self::CouldNotSetProperty, ffi::GST_PARSE_ERROR_EMPTY_BIN => Self::EmptyBin, ffi::GST_PARSE_ERROR_EMPTY => Self::Empty, ffi::GST_PARSE_ERROR_DELAYED_LINK => Self::DelayedLink, value => Self::__Unknown(value), } } } impl glib::error::ErrorDomain for ParseError { #[inline] fn domain() -> glib::Quark { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_parse_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { skip_assert_initialized!(); match unsafe { from_glib(code) } { value => Some(value), } } } impl StaticType for ParseError { #[inline] #[doc(alias = "gst_parse_error_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_parse_error_get_type()) } } } impl glib::HasParamSpec for ParseError { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for ParseError { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for ParseError { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for ParseError { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: ParseError) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstPluginError")] pub enum PluginError { #[doc(alias = "GST_PLUGIN_ERROR_MODULE")] Module, #[doc(alias = "GST_PLUGIN_ERROR_DEPENDENCIES")] Dependencies, #[doc(alias = "GST_PLUGIN_ERROR_NAME_MISMATCH")] NameMismatch, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for PluginError { type GlibType = ffi::GstPluginError; #[inline] fn into_glib(self) -> ffi::GstPluginError { match self { Self::Module => ffi::GST_PLUGIN_ERROR_MODULE, Self::Dependencies => ffi::GST_PLUGIN_ERROR_DEPENDENCIES, Self::NameMismatch => ffi::GST_PLUGIN_ERROR_NAME_MISMATCH, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for PluginError { #[inline] unsafe fn from_glib(value: ffi::GstPluginError) -> Self { skip_assert_initialized!(); match value { ffi::GST_PLUGIN_ERROR_MODULE => Self::Module, ffi::GST_PLUGIN_ERROR_DEPENDENCIES => Self::Dependencies, ffi::GST_PLUGIN_ERROR_NAME_MISMATCH => Self::NameMismatch, value => Self::__Unknown(value), } } } impl glib::error::ErrorDomain for PluginError { #[inline] fn domain() -> glib::Quark { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_plugin_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { skip_assert_initialized!(); match unsafe { from_glib(code) } { value => Some(value), } } } impl StaticType for PluginError { #[inline] #[doc(alias = "gst_plugin_error_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_plugin_error_get_type()) } } } impl glib::HasParamSpec for PluginError { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for PluginError { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PluginError { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for PluginError { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PluginError) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstProgressType")] pub enum ProgressType { #[doc(alias = "GST_PROGRESS_TYPE_START")] Start, #[doc(alias = "GST_PROGRESS_TYPE_CONTINUE")] Continue, #[doc(alias = "GST_PROGRESS_TYPE_COMPLETE")] Complete, #[doc(alias = "GST_PROGRESS_TYPE_CANCELED")] Canceled, #[doc(alias = "GST_PROGRESS_TYPE_ERROR")] Error, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for ProgressType { type GlibType = ffi::GstProgressType; #[inline] fn into_glib(self) -> ffi::GstProgressType { match self { Self::Start => ffi::GST_PROGRESS_TYPE_START, Self::Continue => ffi::GST_PROGRESS_TYPE_CONTINUE, Self::Complete => ffi::GST_PROGRESS_TYPE_COMPLETE, Self::Canceled => ffi::GST_PROGRESS_TYPE_CANCELED, Self::Error => ffi::GST_PROGRESS_TYPE_ERROR, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for ProgressType { #[inline] unsafe fn from_glib(value: ffi::GstProgressType) -> Self { skip_assert_initialized!(); match value { ffi::GST_PROGRESS_TYPE_START => Self::Start, ffi::GST_PROGRESS_TYPE_CONTINUE => Self::Continue, ffi::GST_PROGRESS_TYPE_COMPLETE => Self::Complete, ffi::GST_PROGRESS_TYPE_CANCELED => Self::Canceled, ffi::GST_PROGRESS_TYPE_ERROR => Self::Error, value => Self::__Unknown(value), } } } impl StaticType for ProgressType { #[inline] #[doc(alias = "gst_progress_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_progress_type_get_type()) } } } impl glib::HasParamSpec for ProgressType { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for ProgressType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for ProgressType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for ProgressType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: ProgressType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstPromiseResult")] pub enum PromiseResult { #[doc(alias = "GST_PROMISE_RESULT_PENDING")] Pending, #[doc(alias = "GST_PROMISE_RESULT_INTERRUPTED")] Interrupted, #[doc(alias = "GST_PROMISE_RESULT_REPLIED")] Replied, #[doc(alias = "GST_PROMISE_RESULT_EXPIRED")] Expired, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for PromiseResult { type GlibType = ffi::GstPromiseResult; #[inline] fn into_glib(self) -> ffi::GstPromiseResult { match self { Self::Pending => ffi::GST_PROMISE_RESULT_PENDING, Self::Interrupted => ffi::GST_PROMISE_RESULT_INTERRUPTED, Self::Replied => ffi::GST_PROMISE_RESULT_REPLIED, Self::Expired => ffi::GST_PROMISE_RESULT_EXPIRED, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for PromiseResult { #[inline] unsafe fn from_glib(value: ffi::GstPromiseResult) -> Self { skip_assert_initialized!(); match value { ffi::GST_PROMISE_RESULT_PENDING => Self::Pending, ffi::GST_PROMISE_RESULT_INTERRUPTED => Self::Interrupted, ffi::GST_PROMISE_RESULT_REPLIED => Self::Replied, ffi::GST_PROMISE_RESULT_EXPIRED => Self::Expired, value => Self::__Unknown(value), } } } impl StaticType for PromiseResult { #[inline] #[doc(alias = "gst_promise_result_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_promise_result_get_type()) } } } impl glib::HasParamSpec for PromiseResult { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for PromiseResult { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PromiseResult { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for PromiseResult { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PromiseResult) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstQOSType")] pub enum QOSType { #[doc(alias = "GST_QOS_TYPE_OVERFLOW")] Overflow, #[doc(alias = "GST_QOS_TYPE_UNDERFLOW")] Underflow, #[doc(alias = "GST_QOS_TYPE_THROTTLE")] Throttle, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for QOSType { type GlibType = ffi::GstQOSType; #[inline] fn into_glib(self) -> ffi::GstQOSType { match self { Self::Overflow => ffi::GST_QOS_TYPE_OVERFLOW, Self::Underflow => ffi::GST_QOS_TYPE_UNDERFLOW, Self::Throttle => ffi::GST_QOS_TYPE_THROTTLE, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for QOSType { #[inline] unsafe fn from_glib(value: ffi::GstQOSType) -> Self { skip_assert_initialized!(); match value { ffi::GST_QOS_TYPE_OVERFLOW => Self::Overflow, ffi::GST_QOS_TYPE_UNDERFLOW => Self::Underflow, ffi::GST_QOS_TYPE_THROTTLE => Self::Throttle, value => Self::__Unknown(value), } } } impl StaticType for QOSType { #[inline] #[doc(alias = "gst_qos_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_qos_type_get_type()) } } } impl glib::HasParamSpec for QOSType { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for QOSType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for QOSType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for QOSType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: QOSType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstResourceError")] pub enum ResourceError { #[doc(alias = "GST_RESOURCE_ERROR_FAILED")] Failed, #[doc(alias = "GST_RESOURCE_ERROR_TOO_LAZY")] TooLazy, #[doc(alias = "GST_RESOURCE_ERROR_NOT_FOUND")] NotFound, #[doc(alias = "GST_RESOURCE_ERROR_BUSY")] Busy, #[doc(alias = "GST_RESOURCE_ERROR_OPEN_READ")] OpenRead, #[doc(alias = "GST_RESOURCE_ERROR_OPEN_WRITE")] OpenWrite, #[doc(alias = "GST_RESOURCE_ERROR_OPEN_READ_WRITE")] OpenReadWrite, #[doc(alias = "GST_RESOURCE_ERROR_CLOSE")] Close, #[doc(alias = "GST_RESOURCE_ERROR_READ")] Read, #[doc(alias = "GST_RESOURCE_ERROR_WRITE")] Write, #[doc(alias = "GST_RESOURCE_ERROR_SEEK")] Seek, #[doc(alias = "GST_RESOURCE_ERROR_SYNC")] Sync, #[doc(alias = "GST_RESOURCE_ERROR_SETTINGS")] Settings, #[doc(alias = "GST_RESOURCE_ERROR_NO_SPACE_LEFT")] NoSpaceLeft, #[doc(alias = "GST_RESOURCE_ERROR_NOT_AUTHORIZED")] NotAuthorized, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for ResourceError { type GlibType = ffi::GstResourceError; fn into_glib(self) -> ffi::GstResourceError { match self { Self::Failed => ffi::GST_RESOURCE_ERROR_FAILED, Self::TooLazy => ffi::GST_RESOURCE_ERROR_TOO_LAZY, Self::NotFound => ffi::GST_RESOURCE_ERROR_NOT_FOUND, Self::Busy => ffi::GST_RESOURCE_ERROR_BUSY, Self::OpenRead => ffi::GST_RESOURCE_ERROR_OPEN_READ, Self::OpenWrite => ffi::GST_RESOURCE_ERROR_OPEN_WRITE, Self::OpenReadWrite => ffi::GST_RESOURCE_ERROR_OPEN_READ_WRITE, Self::Close => ffi::GST_RESOURCE_ERROR_CLOSE, Self::Read => ffi::GST_RESOURCE_ERROR_READ, Self::Write => ffi::GST_RESOURCE_ERROR_WRITE, Self::Seek => ffi::GST_RESOURCE_ERROR_SEEK, Self::Sync => ffi::GST_RESOURCE_ERROR_SYNC, Self::Settings => ffi::GST_RESOURCE_ERROR_SETTINGS, Self::NoSpaceLeft => ffi::GST_RESOURCE_ERROR_NO_SPACE_LEFT, Self::NotAuthorized => ffi::GST_RESOURCE_ERROR_NOT_AUTHORIZED, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for ResourceError { unsafe fn from_glib(value: ffi::GstResourceError) -> Self { skip_assert_initialized!(); match value { ffi::GST_RESOURCE_ERROR_FAILED => Self::Failed, ffi::GST_RESOURCE_ERROR_TOO_LAZY => Self::TooLazy, ffi::GST_RESOURCE_ERROR_NOT_FOUND => Self::NotFound, ffi::GST_RESOURCE_ERROR_BUSY => Self::Busy, ffi::GST_RESOURCE_ERROR_OPEN_READ => Self::OpenRead, ffi::GST_RESOURCE_ERROR_OPEN_WRITE => Self::OpenWrite, ffi::GST_RESOURCE_ERROR_OPEN_READ_WRITE => Self::OpenReadWrite, ffi::GST_RESOURCE_ERROR_CLOSE => Self::Close, ffi::GST_RESOURCE_ERROR_READ => Self::Read, ffi::GST_RESOURCE_ERROR_WRITE => Self::Write, ffi::GST_RESOURCE_ERROR_SEEK => Self::Seek, ffi::GST_RESOURCE_ERROR_SYNC => Self::Sync, ffi::GST_RESOURCE_ERROR_SETTINGS => Self::Settings, ffi::GST_RESOURCE_ERROR_NO_SPACE_LEFT => Self::NoSpaceLeft, ffi::GST_RESOURCE_ERROR_NOT_AUTHORIZED => Self::NotAuthorized, value => Self::__Unknown(value), } } } impl glib::error::ErrorDomain for ResourceError { #[inline] fn domain() -> glib::Quark { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_resource_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { skip_assert_initialized!(); match unsafe { from_glib(code) } { Self::__Unknown(_) => Some(Self::Failed), value => Some(value), } } } impl StaticType for ResourceError { #[inline] #[doc(alias = "gst_resource_error_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_resource_error_get_type()) } } } impl glib::HasParamSpec for ResourceError { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for ResourceError { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for ResourceError { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for ResourceError { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: ResourceError) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstSeekType")] pub enum SeekType { #[doc(alias = "GST_SEEK_TYPE_NONE")] None = ffi::GST_SEEK_TYPE_NONE, #[doc(alias = "GST_SEEK_TYPE_SET")] Set = ffi::GST_SEEK_TYPE_SET, #[doc(alias = "GST_SEEK_TYPE_END")] End = ffi::GST_SEEK_TYPE_END, } #[doc(hidden)] impl IntoGlib for SeekType { type GlibType = ffi::GstSeekType; #[inline] fn into_glib(self) -> ffi::GstSeekType { self as ffi::GstSeekType } } #[doc(hidden)] impl FromGlib for SeekType { #[inline] unsafe fn from_glib(value: ffi::GstSeekType) -> Self { skip_assert_initialized!(); debug_assert!([ ffi::GST_SEEK_TYPE_NONE, ffi::GST_SEEK_TYPE_SET, ffi::GST_SEEK_TYPE_END ] .contains(&value)); std::mem::transmute(value) } } impl StaticType for SeekType { #[inline] #[doc(alias = "gst_seek_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_seek_type_get_type()) } } } impl glib::HasParamSpec for SeekType { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for SeekType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for SeekType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for SeekType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: SeekType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstState")] pub enum State { #[doc(alias = "GST_STATE_VOID_PENDING")] VoidPending = ffi::GST_STATE_VOID_PENDING, #[doc(alias = "GST_STATE_NULL")] Null = ffi::GST_STATE_NULL, #[doc(alias = "GST_STATE_READY")] Ready = ffi::GST_STATE_READY, #[doc(alias = "GST_STATE_PAUSED")] Paused = ffi::GST_STATE_PAUSED, #[doc(alias = "GST_STATE_PLAYING")] Playing = ffi::GST_STATE_PLAYING, } #[doc(hidden)] impl IntoGlib for State { type GlibType = ffi::GstState; #[inline] fn into_glib(self) -> ffi::GstState { self as ffi::GstState } } #[doc(hidden)] impl FromGlib for State { #[inline] unsafe fn from_glib(value: ffi::GstState) -> Self { skip_assert_initialized!(); debug_assert!([ ffi::GST_STATE_VOID_PENDING, ffi::GST_STATE_NULL, ffi::GST_STATE_READY, ffi::GST_STATE_PAUSED, ffi::GST_STATE_PLAYING ] .contains(&value)); std::mem::transmute(value) } } impl StaticType for State { #[inline] #[doc(alias = "gst_state_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_state_get_type()) } } } impl glib::HasParamSpec for State { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for State { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for State { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for State { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: State) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstStateChange")] pub enum StateChange { #[doc(alias = "GST_STATE_CHANGE_NULL_TO_READY")] NullToReady = ffi::GST_STATE_CHANGE_NULL_TO_READY, #[doc(alias = "GST_STATE_CHANGE_READY_TO_PAUSED")] ReadyToPaused = ffi::GST_STATE_CHANGE_READY_TO_PAUSED, #[doc(alias = "GST_STATE_CHANGE_PAUSED_TO_PLAYING")] PausedToPlaying = ffi::GST_STATE_CHANGE_PAUSED_TO_PLAYING, #[doc(alias = "GST_STATE_CHANGE_PLAYING_TO_PAUSED")] PlayingToPaused = ffi::GST_STATE_CHANGE_PLAYING_TO_PAUSED, #[doc(alias = "GST_STATE_CHANGE_PAUSED_TO_READY")] PausedToReady = ffi::GST_STATE_CHANGE_PAUSED_TO_READY, #[doc(alias = "GST_STATE_CHANGE_READY_TO_NULL")] ReadyToNull = ffi::GST_STATE_CHANGE_READY_TO_NULL, #[doc(alias = "GST_STATE_CHANGE_NULL_TO_NULL")] NullToNull = ffi::GST_STATE_CHANGE_NULL_TO_NULL, #[doc(alias = "GST_STATE_CHANGE_READY_TO_READY")] ReadyToReady = ffi::GST_STATE_CHANGE_READY_TO_READY, #[doc(alias = "GST_STATE_CHANGE_PAUSED_TO_PAUSED")] PausedToPaused = ffi::GST_STATE_CHANGE_PAUSED_TO_PAUSED, #[doc(alias = "GST_STATE_CHANGE_PLAYING_TO_PLAYING")] PlayingToPlaying = ffi::GST_STATE_CHANGE_PLAYING_TO_PLAYING, } impl StateChange { pub fn name<'a>(self) -> &'a GStr { unsafe { GStr::from_ptr( ffi::gst_state_change_get_name(self.into_glib()) .as_ref() .expect("gst_state_change_get_name returned NULL"), ) } } } impl std::fmt::Display for StateChange { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(&self.name()) } } #[doc(hidden)] impl IntoGlib for StateChange { type GlibType = ffi::GstStateChange; #[inline] fn into_glib(self) -> ffi::GstStateChange { self as ffi::GstStateChange } } #[doc(hidden)] impl FromGlib for StateChange { #[inline] unsafe fn from_glib(value: ffi::GstStateChange) -> Self { skip_assert_initialized!(); debug_assert!([ ffi::GST_STATE_CHANGE_NULL_TO_READY, ffi::GST_STATE_CHANGE_READY_TO_PAUSED, ffi::GST_STATE_CHANGE_PAUSED_TO_PLAYING, ffi::GST_STATE_CHANGE_PLAYING_TO_PAUSED, ffi::GST_STATE_CHANGE_PAUSED_TO_READY, ffi::GST_STATE_CHANGE_READY_TO_NULL, ffi::GST_STATE_CHANGE_NULL_TO_NULL, ffi::GST_STATE_CHANGE_READY_TO_READY, ffi::GST_STATE_CHANGE_PAUSED_TO_PAUSED, ffi::GST_STATE_CHANGE_PLAYING_TO_PLAYING ] .contains(&value)); std::mem::transmute(value) } } impl StaticType for StateChange { #[inline] #[doc(alias = "gst_state_change_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_state_change_get_type()) } } } impl glib::HasParamSpec for StateChange { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for StateChange { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for StateChange { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for StateChange { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: StateChange) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[must_use] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstStateChangeReturn")] pub enum StateChangeReturn { #[doc(alias = "GST_STATE_CHANGE_FAILURE")] Failure = ffi::GST_STATE_CHANGE_FAILURE, #[doc(alias = "GST_STATE_CHANGE_SUCCESS")] Success = ffi::GST_STATE_CHANGE_SUCCESS, #[doc(alias = "GST_STATE_CHANGE_ASYNC")] Async = ffi::GST_STATE_CHANGE_ASYNC, #[doc(alias = "GST_STATE_CHANGE_NO_PREROLL")] NoPreroll = ffi::GST_STATE_CHANGE_NO_PREROLL, } #[doc(hidden)] impl IntoGlib for StateChangeReturn { type GlibType = ffi::GstStateChangeReturn; #[inline] fn into_glib(self) -> ffi::GstStateChangeReturn { self as ffi::GstStateChangeReturn } } #[doc(hidden)] impl FromGlib for StateChangeReturn { #[inline] unsafe fn from_glib(value: ffi::GstStateChangeReturn) -> Self { skip_assert_initialized!(); debug_assert!([ ffi::GST_STATE_CHANGE_FAILURE, ffi::GST_STATE_CHANGE_SUCCESS, ffi::GST_STATE_CHANGE_ASYNC, ffi::GST_STATE_CHANGE_NO_PREROLL ] .contains(&value)); std::mem::transmute(value) } } impl StaticType for StateChangeReturn { #[inline] #[doc(alias = "gst_state_change_return_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_state_change_return_get_type()) } } } impl glib::HasParamSpec for StateChangeReturn { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for StateChangeReturn { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for StateChangeReturn { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for StateChangeReturn { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: StateChangeReturn) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstStreamError")] pub enum StreamError { #[doc(alias = "GST_STREAM_ERROR_FAILED")] Failed, #[doc(alias = "GST_STREAM_ERROR_TOO_LAZY")] TooLazy, #[doc(alias = "GST_STREAM_ERROR_NOT_IMPLEMENTED")] NotImplemented, #[doc(alias = "GST_STREAM_ERROR_TYPE_NOT_FOUND")] TypeNotFound, #[doc(alias = "GST_STREAM_ERROR_WRONG_TYPE")] WrongType, #[doc(alias = "GST_STREAM_ERROR_CODEC_NOT_FOUND")] CodecNotFound, #[doc(alias = "GST_STREAM_ERROR_DECODE")] Decode, #[doc(alias = "GST_STREAM_ERROR_ENCODE")] Encode, #[doc(alias = "GST_STREAM_ERROR_DEMUX")] Demux, #[doc(alias = "GST_STREAM_ERROR_MUX")] Mux, #[doc(alias = "GST_STREAM_ERROR_FORMAT")] Format, #[doc(alias = "GST_STREAM_ERROR_DECRYPT")] Decrypt, #[doc(alias = "GST_STREAM_ERROR_DECRYPT_NOKEY")] DecryptNokey, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for StreamError { type GlibType = ffi::GstStreamError; fn into_glib(self) -> ffi::GstStreamError { match self { Self::Failed => ffi::GST_STREAM_ERROR_FAILED, Self::TooLazy => ffi::GST_STREAM_ERROR_TOO_LAZY, Self::NotImplemented => ffi::GST_STREAM_ERROR_NOT_IMPLEMENTED, Self::TypeNotFound => ffi::GST_STREAM_ERROR_TYPE_NOT_FOUND, Self::WrongType => ffi::GST_STREAM_ERROR_WRONG_TYPE, Self::CodecNotFound => ffi::GST_STREAM_ERROR_CODEC_NOT_FOUND, Self::Decode => ffi::GST_STREAM_ERROR_DECODE, Self::Encode => ffi::GST_STREAM_ERROR_ENCODE, Self::Demux => ffi::GST_STREAM_ERROR_DEMUX, Self::Mux => ffi::GST_STREAM_ERROR_MUX, Self::Format => ffi::GST_STREAM_ERROR_FORMAT, Self::Decrypt => ffi::GST_STREAM_ERROR_DECRYPT, Self::DecryptNokey => ffi::GST_STREAM_ERROR_DECRYPT_NOKEY, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for StreamError { unsafe fn from_glib(value: ffi::GstStreamError) -> Self { skip_assert_initialized!(); match value { ffi::GST_STREAM_ERROR_FAILED => Self::Failed, ffi::GST_STREAM_ERROR_TOO_LAZY => Self::TooLazy, ffi::GST_STREAM_ERROR_NOT_IMPLEMENTED => Self::NotImplemented, ffi::GST_STREAM_ERROR_TYPE_NOT_FOUND => Self::TypeNotFound, ffi::GST_STREAM_ERROR_WRONG_TYPE => Self::WrongType, ffi::GST_STREAM_ERROR_CODEC_NOT_FOUND => Self::CodecNotFound, ffi::GST_STREAM_ERROR_DECODE => Self::Decode, ffi::GST_STREAM_ERROR_ENCODE => Self::Encode, ffi::GST_STREAM_ERROR_DEMUX => Self::Demux, ffi::GST_STREAM_ERROR_MUX => Self::Mux, ffi::GST_STREAM_ERROR_FORMAT => Self::Format, ffi::GST_STREAM_ERROR_DECRYPT => Self::Decrypt, ffi::GST_STREAM_ERROR_DECRYPT_NOKEY => Self::DecryptNokey, value => Self::__Unknown(value), } } } impl glib::error::ErrorDomain for StreamError { #[inline] fn domain() -> glib::Quark { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_stream_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { skip_assert_initialized!(); match unsafe { from_glib(code) } { Self::__Unknown(_) => Some(Self::Failed), value => Some(value), } } } impl StaticType for StreamError { #[inline] #[doc(alias = "gst_stream_error_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_stream_error_get_type()) } } } impl glib::HasParamSpec for StreamError { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for StreamError { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for StreamError { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for StreamError { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: StreamError) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstStreamStatusType")] pub enum StreamStatusType { #[doc(alias = "GST_STREAM_STATUS_TYPE_CREATE")] Create, #[doc(alias = "GST_STREAM_STATUS_TYPE_ENTER")] Enter, #[doc(alias = "GST_STREAM_STATUS_TYPE_LEAVE")] Leave, #[doc(alias = "GST_STREAM_STATUS_TYPE_DESTROY")] Destroy, #[doc(alias = "GST_STREAM_STATUS_TYPE_START")] Start, #[doc(alias = "GST_STREAM_STATUS_TYPE_PAUSE")] Pause, #[doc(alias = "GST_STREAM_STATUS_TYPE_STOP")] Stop, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for StreamStatusType { type GlibType = ffi::GstStreamStatusType; #[inline] fn into_glib(self) -> ffi::GstStreamStatusType { match self { Self::Create => ffi::GST_STREAM_STATUS_TYPE_CREATE, Self::Enter => ffi::GST_STREAM_STATUS_TYPE_ENTER, Self::Leave => ffi::GST_STREAM_STATUS_TYPE_LEAVE, Self::Destroy => ffi::GST_STREAM_STATUS_TYPE_DESTROY, Self::Start => ffi::GST_STREAM_STATUS_TYPE_START, Self::Pause => ffi::GST_STREAM_STATUS_TYPE_PAUSE, Self::Stop => ffi::GST_STREAM_STATUS_TYPE_STOP, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for StreamStatusType { #[inline] unsafe fn from_glib(value: ffi::GstStreamStatusType) -> Self { skip_assert_initialized!(); match value { ffi::GST_STREAM_STATUS_TYPE_CREATE => Self::Create, ffi::GST_STREAM_STATUS_TYPE_ENTER => Self::Enter, ffi::GST_STREAM_STATUS_TYPE_LEAVE => Self::Leave, ffi::GST_STREAM_STATUS_TYPE_DESTROY => Self::Destroy, ffi::GST_STREAM_STATUS_TYPE_START => Self::Start, ffi::GST_STREAM_STATUS_TYPE_PAUSE => Self::Pause, ffi::GST_STREAM_STATUS_TYPE_STOP => Self::Stop, value => Self::__Unknown(value), } } } impl StaticType for StreamStatusType { #[inline] #[doc(alias = "gst_stream_status_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_stream_status_type_get_type()) } } } impl glib::HasParamSpec for StreamStatusType { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for StreamStatusType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for StreamStatusType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for StreamStatusType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: StreamStatusType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstStructureChangeType")] pub enum StructureChangeType { #[doc(alias = "GST_STRUCTURE_CHANGE_TYPE_PAD_LINK")] Link, #[doc(alias = "GST_STRUCTURE_CHANGE_TYPE_PAD_UNLINK")] Unlink, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for StructureChangeType { type GlibType = ffi::GstStructureChangeType; #[inline] fn into_glib(self) -> ffi::GstStructureChangeType { match self { Self::Link => ffi::GST_STRUCTURE_CHANGE_TYPE_PAD_LINK, Self::Unlink => ffi::GST_STRUCTURE_CHANGE_TYPE_PAD_UNLINK, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for StructureChangeType { #[inline] unsafe fn from_glib(value: ffi::GstStructureChangeType) -> Self { skip_assert_initialized!(); match value { ffi::GST_STRUCTURE_CHANGE_TYPE_PAD_LINK => Self::Link, ffi::GST_STRUCTURE_CHANGE_TYPE_PAD_UNLINK => Self::Unlink, value => Self::__Unknown(value), } } } impl StaticType for StructureChangeType { #[inline] #[doc(alias = "gst_structure_change_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_structure_change_type_get_type()) } } } impl glib::HasParamSpec for StructureChangeType { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for StructureChangeType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for StructureChangeType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for StructureChangeType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: StructureChangeType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstTagFlag")] pub enum TagFlag { #[doc(alias = "GST_TAG_FLAG_UNDEFINED")] Undefined, #[doc(alias = "GST_TAG_FLAG_META")] Meta, #[doc(alias = "GST_TAG_FLAG_ENCODED")] Encoded, #[doc(alias = "GST_TAG_FLAG_DECODED")] Decoded, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for TagFlag { type GlibType = ffi::GstTagFlag; #[inline] fn into_glib(self) -> ffi::GstTagFlag { match self { Self::Undefined => ffi::GST_TAG_FLAG_UNDEFINED, Self::Meta => ffi::GST_TAG_FLAG_META, Self::Encoded => ffi::GST_TAG_FLAG_ENCODED, Self::Decoded => ffi::GST_TAG_FLAG_DECODED, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for TagFlag { #[inline] unsafe fn from_glib(value: ffi::GstTagFlag) -> Self { skip_assert_initialized!(); match value { ffi::GST_TAG_FLAG_UNDEFINED => Self::Undefined, ffi::GST_TAG_FLAG_META => Self::Meta, ffi::GST_TAG_FLAG_ENCODED => Self::Encoded, ffi::GST_TAG_FLAG_DECODED => Self::Decoded, value => Self::__Unknown(value), } } } impl StaticType for TagFlag { #[inline] #[doc(alias = "gst_tag_flag_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_tag_flag_get_type()) } } } impl glib::HasParamSpec for TagFlag { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for TagFlag { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for TagFlag { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for TagFlag { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: TagFlag) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstTagMergeMode")] pub enum TagMergeMode { #[doc(alias = "GST_TAG_MERGE_UNDEFINED")] Undefined, #[doc(alias = "GST_TAG_MERGE_REPLACE_ALL")] ReplaceAll, #[doc(alias = "GST_TAG_MERGE_REPLACE")] Replace, #[doc(alias = "GST_TAG_MERGE_APPEND")] Append, #[doc(alias = "GST_TAG_MERGE_PREPEND")] Prepend, #[doc(alias = "GST_TAG_MERGE_KEEP")] Keep, #[doc(alias = "GST_TAG_MERGE_KEEP_ALL")] KeepAll, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for TagMergeMode { type GlibType = ffi::GstTagMergeMode; #[inline] fn into_glib(self) -> ffi::GstTagMergeMode { match self { Self::Undefined => ffi::GST_TAG_MERGE_UNDEFINED, Self::ReplaceAll => ffi::GST_TAG_MERGE_REPLACE_ALL, Self::Replace => ffi::GST_TAG_MERGE_REPLACE, Self::Append => ffi::GST_TAG_MERGE_APPEND, Self::Prepend => ffi::GST_TAG_MERGE_PREPEND, Self::Keep => ffi::GST_TAG_MERGE_KEEP, Self::KeepAll => ffi::GST_TAG_MERGE_KEEP_ALL, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for TagMergeMode { #[inline] unsafe fn from_glib(value: ffi::GstTagMergeMode) -> Self { skip_assert_initialized!(); match value { ffi::GST_TAG_MERGE_UNDEFINED => Self::Undefined, ffi::GST_TAG_MERGE_REPLACE_ALL => Self::ReplaceAll, ffi::GST_TAG_MERGE_REPLACE => Self::Replace, ffi::GST_TAG_MERGE_APPEND => Self::Append, ffi::GST_TAG_MERGE_PREPEND => Self::Prepend, ffi::GST_TAG_MERGE_KEEP => Self::Keep, ffi::GST_TAG_MERGE_KEEP_ALL => Self::KeepAll, value => Self::__Unknown(value), } } } impl StaticType for TagMergeMode { #[inline] #[doc(alias = "gst_tag_merge_mode_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_tag_merge_mode_get_type()) } } } impl glib::HasParamSpec for TagMergeMode { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for TagMergeMode { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for TagMergeMode { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for TagMergeMode { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: TagMergeMode) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstTagScope")] pub enum TagScope { #[doc(alias = "GST_TAG_SCOPE_STREAM")] Stream, #[doc(alias = "GST_TAG_SCOPE_GLOBAL")] Global, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for TagScope { type GlibType = ffi::GstTagScope; #[inline] fn into_glib(self) -> ffi::GstTagScope { match self { Self::Stream => ffi::GST_TAG_SCOPE_STREAM, Self::Global => ffi::GST_TAG_SCOPE_GLOBAL, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for TagScope { #[inline] unsafe fn from_glib(value: ffi::GstTagScope) -> Self { skip_assert_initialized!(); match value { ffi::GST_TAG_SCOPE_STREAM => Self::Stream, ffi::GST_TAG_SCOPE_GLOBAL => Self::Global, value => Self::__Unknown(value), } } } impl StaticType for TagScope { #[inline] #[doc(alias = "gst_tag_scope_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_tag_scope_get_type()) } } } impl glib::HasParamSpec for TagScope { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for TagScope { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for TagScope { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for TagScope { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: TagScope) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstTaskState")] pub enum TaskState { #[doc(alias = "GST_TASK_STARTED")] Started, #[doc(alias = "GST_TASK_STOPPED")] Stopped, #[doc(alias = "GST_TASK_PAUSED")] Paused, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for TaskState { type GlibType = ffi::GstTaskState; #[inline] fn into_glib(self) -> ffi::GstTaskState { match self { Self::Started => ffi::GST_TASK_STARTED, Self::Stopped => ffi::GST_TASK_STOPPED, Self::Paused => ffi::GST_TASK_PAUSED, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for TaskState { #[inline] unsafe fn from_glib(value: ffi::GstTaskState) -> Self { skip_assert_initialized!(); match value { ffi::GST_TASK_STARTED => Self::Started, ffi::GST_TASK_STOPPED => Self::Stopped, ffi::GST_TASK_PAUSED => Self::Paused, value => Self::__Unknown(value), } } } impl StaticType for TaskState { #[inline] #[doc(alias = "gst_task_state_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_task_state_get_type()) } } } impl glib::HasParamSpec for TaskState { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for TaskState { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for TaskState { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for TaskState { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: TaskState) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstTocEntryType")] pub enum TocEntryType { #[doc(alias = "GST_TOC_ENTRY_TYPE_ANGLE")] Angle, #[doc(alias = "GST_TOC_ENTRY_TYPE_VERSION")] Version, #[doc(alias = "GST_TOC_ENTRY_TYPE_EDITION")] Edition, #[doc(alias = "GST_TOC_ENTRY_TYPE_INVALID")] Invalid, #[doc(alias = "GST_TOC_ENTRY_TYPE_TITLE")] Title, #[doc(alias = "GST_TOC_ENTRY_TYPE_TRACK")] Track, #[doc(alias = "GST_TOC_ENTRY_TYPE_CHAPTER")] Chapter, #[doc(hidden)] __Unknown(i32), } impl TocEntryType { pub fn nick<'a>(self) -> &'a GStr { unsafe { GStr::from_ptr( ffi::gst_toc_entry_type_get_nick(self.into_glib()) .as_ref() .expect("gst_toc_entry_type_get_nick returned NULL"), ) } } } #[doc(hidden)] impl IntoGlib for TocEntryType { type GlibType = ffi::GstTocEntryType; #[inline] fn into_glib(self) -> ffi::GstTocEntryType { match self { Self::Angle => ffi::GST_TOC_ENTRY_TYPE_ANGLE, Self::Version => ffi::GST_TOC_ENTRY_TYPE_VERSION, Self::Edition => ffi::GST_TOC_ENTRY_TYPE_EDITION, Self::Invalid => ffi::GST_TOC_ENTRY_TYPE_INVALID, Self::Title => ffi::GST_TOC_ENTRY_TYPE_TITLE, Self::Track => ffi::GST_TOC_ENTRY_TYPE_TRACK, Self::Chapter => ffi::GST_TOC_ENTRY_TYPE_CHAPTER, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for TocEntryType { #[inline] unsafe fn from_glib(value: ffi::GstTocEntryType) -> Self { skip_assert_initialized!(); match value { ffi::GST_TOC_ENTRY_TYPE_ANGLE => Self::Angle, ffi::GST_TOC_ENTRY_TYPE_VERSION => Self::Version, ffi::GST_TOC_ENTRY_TYPE_EDITION => Self::Edition, ffi::GST_TOC_ENTRY_TYPE_INVALID => Self::Invalid, ffi::GST_TOC_ENTRY_TYPE_TITLE => Self::Title, ffi::GST_TOC_ENTRY_TYPE_TRACK => Self::Track, ffi::GST_TOC_ENTRY_TYPE_CHAPTER => Self::Chapter, value => Self::__Unknown(value), } } } impl StaticType for TocEntryType { #[inline] #[doc(alias = "gst_toc_entry_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_toc_entry_type_get_type()) } } } impl glib::HasParamSpec for TocEntryType { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for TocEntryType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for TocEntryType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for TocEntryType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: TocEntryType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstTocLoopType")] pub enum TocLoopType { #[doc(alias = "GST_TOC_LOOP_NONE")] None, #[doc(alias = "GST_TOC_LOOP_FORWARD")] Forward, #[doc(alias = "GST_TOC_LOOP_REVERSE")] Reverse, #[doc(alias = "GST_TOC_LOOP_PING_PONG")] PingPong, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for TocLoopType { type GlibType = ffi::GstTocLoopType; #[inline] fn into_glib(self) -> ffi::GstTocLoopType { match self { Self::None => ffi::GST_TOC_LOOP_NONE, Self::Forward => ffi::GST_TOC_LOOP_FORWARD, Self::Reverse => ffi::GST_TOC_LOOP_REVERSE, Self::PingPong => ffi::GST_TOC_LOOP_PING_PONG, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for TocLoopType { #[inline] unsafe fn from_glib(value: ffi::GstTocLoopType) -> Self { skip_assert_initialized!(); match value { ffi::GST_TOC_LOOP_NONE => Self::None, ffi::GST_TOC_LOOP_FORWARD => Self::Forward, ffi::GST_TOC_LOOP_REVERSE => Self::Reverse, ffi::GST_TOC_LOOP_PING_PONG => Self::PingPong, value => Self::__Unknown(value), } } } impl StaticType for TocLoopType { #[inline] #[doc(alias = "gst_toc_loop_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_toc_loop_type_get_type()) } } } impl glib::HasParamSpec for TocLoopType { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for TocLoopType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for TocLoopType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for TocLoopType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: TocLoopType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstTocScope")] pub enum TocScope { #[doc(alias = "GST_TOC_SCOPE_GLOBAL")] Global, #[doc(alias = "GST_TOC_SCOPE_CURRENT")] Current, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for TocScope { type GlibType = ffi::GstTocScope; #[inline] fn into_glib(self) -> ffi::GstTocScope { match self { Self::Global => ffi::GST_TOC_SCOPE_GLOBAL, Self::Current => ffi::GST_TOC_SCOPE_CURRENT, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for TocScope { #[inline] unsafe fn from_glib(value: ffi::GstTocScope) -> Self { skip_assert_initialized!(); match value { ffi::GST_TOC_SCOPE_GLOBAL => Self::Global, ffi::GST_TOC_SCOPE_CURRENT => Self::Current, value => Self::__Unknown(value), } } } impl StaticType for TocScope { #[inline] #[doc(alias = "gst_toc_scope_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_toc_scope_get_type()) } } } impl glib::HasParamSpec for TocScope { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for TocScope { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for TocScope { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for TocScope { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: TocScope) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstTypeFindProbability")] pub enum TypeFindProbability { #[doc(alias = "GST_TYPE_FIND_NONE")] None, #[doc(alias = "GST_TYPE_FIND_MINIMUM")] Minimum, #[doc(alias = "GST_TYPE_FIND_POSSIBLE")] Possible, #[doc(alias = "GST_TYPE_FIND_LIKELY")] Likely, #[doc(alias = "GST_TYPE_FIND_NEARLY_CERTAIN")] NearlyCertain, #[doc(alias = "GST_TYPE_FIND_MAXIMUM")] Maximum, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for TypeFindProbability { type GlibType = ffi::GstTypeFindProbability; #[inline] fn into_glib(self) -> ffi::GstTypeFindProbability { match self { Self::None => ffi::GST_TYPE_FIND_NONE, Self::Minimum => ffi::GST_TYPE_FIND_MINIMUM, Self::Possible => ffi::GST_TYPE_FIND_POSSIBLE, Self::Likely => ffi::GST_TYPE_FIND_LIKELY, Self::NearlyCertain => ffi::GST_TYPE_FIND_NEARLY_CERTAIN, Self::Maximum => ffi::GST_TYPE_FIND_MAXIMUM, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for TypeFindProbability { #[inline] unsafe fn from_glib(value: ffi::GstTypeFindProbability) -> Self { skip_assert_initialized!(); match value { ffi::GST_TYPE_FIND_NONE => Self::None, ffi::GST_TYPE_FIND_MINIMUM => Self::Minimum, ffi::GST_TYPE_FIND_POSSIBLE => Self::Possible, ffi::GST_TYPE_FIND_LIKELY => Self::Likely, ffi::GST_TYPE_FIND_NEARLY_CERTAIN => Self::NearlyCertain, ffi::GST_TYPE_FIND_MAXIMUM => Self::Maximum, value => Self::__Unknown(value), } } } impl StaticType for TypeFindProbability { #[inline] #[doc(alias = "gst_type_find_probability_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_type_find_probability_get_type()) } } } impl glib::HasParamSpec for TypeFindProbability { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for TypeFindProbability { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for TypeFindProbability { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for TypeFindProbability { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: TypeFindProbability) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[non_exhaustive] #[doc(alias = "GstURIError")] pub enum URIError { #[doc(alias = "GST_URI_ERROR_UNSUPPORTED_PROTOCOL")] UnsupportedProtocol, #[doc(alias = "GST_URI_ERROR_BAD_URI")] BadUri, #[doc(alias = "GST_URI_ERROR_BAD_STATE")] BadState, #[doc(alias = "GST_URI_ERROR_BAD_REFERENCE")] BadReference, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for URIError { type GlibType = ffi::GstURIError; #[inline] fn into_glib(self) -> ffi::GstURIError { match self { Self::UnsupportedProtocol => ffi::GST_URI_ERROR_UNSUPPORTED_PROTOCOL, Self::BadUri => ffi::GST_URI_ERROR_BAD_URI, Self::BadState => ffi::GST_URI_ERROR_BAD_STATE, Self::BadReference => ffi::GST_URI_ERROR_BAD_REFERENCE, Self::__Unknown(value) => value, } } } #[doc(hidden)] impl FromGlib for URIError { #[inline] unsafe fn from_glib(value: ffi::GstURIError) -> Self { skip_assert_initialized!(); match value { ffi::GST_URI_ERROR_UNSUPPORTED_PROTOCOL => Self::UnsupportedProtocol, ffi::GST_URI_ERROR_BAD_URI => Self::BadUri, ffi::GST_URI_ERROR_BAD_STATE => Self::BadState, ffi::GST_URI_ERROR_BAD_REFERENCE => Self::BadReference, value => Self::__Unknown(value), } } } impl glib::error::ErrorDomain for URIError { #[inline] fn domain() -> glib::Quark { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_uri_error_quark()) } } #[inline] fn code(self) -> i32 { self.into_glib() } #[inline] #[allow(clippy::match_single_binding)] fn from(code: i32) -> Option { skip_assert_initialized!(); match unsafe { from_glib(code) } { value => Some(value), } } } impl StaticType for URIError { #[inline] #[doc(alias = "gst_uri_error_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_uri_error_get_type()) } } } impl glib::HasParamSpec for URIError { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for URIError { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for URIError { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for URIError { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: URIError) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstURIType")] pub enum URIType { #[doc(alias = "GST_URI_UNKNOWN")] Unknown = ffi::GST_URI_UNKNOWN, #[doc(alias = "GST_URI_SINK")] Sink = ffi::GST_URI_SINK, #[doc(alias = "GST_URI_SRC")] Src = ffi::GST_URI_SRC, } #[doc(hidden)] impl IntoGlib for URIType { type GlibType = ffi::GstURIType; #[inline] fn into_glib(self) -> ffi::GstURIType { self as ffi::GstURIType } } #[doc(hidden)] impl FromGlib for URIType { #[inline] unsafe fn from_glib(value: ffi::GstURIType) -> Self { skip_assert_initialized!(); debug_assert!([ffi::GST_URI_UNKNOWN, ffi::GST_URI_SINK, ffi::GST_URI_SRC].contains(&value)); std::mem::transmute(value) } } impl StaticType for URIType { #[inline] #[doc(alias = "gst_uri_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_uri_type_get_type()) } } } impl glib::HasParamSpec for URIType { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for URIType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for URIType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for URIType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: URIType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } gstreamer-0.23.5/src/auto/flags.rs000064400000000000000000002320651046102023000151150ustar 00000000000000// 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::ffi; use glib::{bitflags::bitflags, prelude::*, translate::*, GStr}; bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstBinFlags")] pub struct BinFlags: u32 { #[doc(alias = "GST_BIN_FLAG_NO_RESYNC")] const NO_RESYNC = ffi::GST_BIN_FLAG_NO_RESYNC as _; #[doc(alias = "GST_BIN_FLAG_STREAMS_AWARE")] const STREAMS_AWARE = ffi::GST_BIN_FLAG_STREAMS_AWARE as _; } } #[doc(hidden)] impl IntoGlib for BinFlags { type GlibType = ffi::GstBinFlags; #[inline] fn into_glib(self) -> ffi::GstBinFlags { self.bits() } } #[doc(hidden)] impl FromGlib for BinFlags { #[inline] unsafe fn from_glib(value: ffi::GstBinFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for BinFlags { #[inline] #[doc(alias = "gst_bin_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_bin_flags_get_type()) } } } impl glib::HasParamSpec for BinFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for BinFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for BinFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for BinFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: BinFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstBufferCopyFlags")] pub struct BufferCopyFlags: u32 { #[doc(alias = "GST_BUFFER_COPY_FLAGS")] const FLAGS = ffi::GST_BUFFER_COPY_FLAGS as _; #[doc(alias = "GST_BUFFER_COPY_TIMESTAMPS")] const TIMESTAMPS = ffi::GST_BUFFER_COPY_TIMESTAMPS as _; #[doc(alias = "GST_BUFFER_COPY_META")] const META = ffi::GST_BUFFER_COPY_META as _; #[doc(alias = "GST_BUFFER_COPY_MEMORY")] const MEMORY = ffi::GST_BUFFER_COPY_MEMORY as _; #[doc(alias = "GST_BUFFER_COPY_MERGE")] const MERGE = ffi::GST_BUFFER_COPY_MERGE as _; #[doc(alias = "GST_BUFFER_COPY_DEEP")] const DEEP = ffi::GST_BUFFER_COPY_DEEP as _; } } #[doc(hidden)] impl IntoGlib for BufferCopyFlags { type GlibType = ffi::GstBufferCopyFlags; #[inline] fn into_glib(self) -> ffi::GstBufferCopyFlags { self.bits() } } #[doc(hidden)] impl FromGlib for BufferCopyFlags { #[inline] unsafe fn from_glib(value: ffi::GstBufferCopyFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for BufferCopyFlags { #[inline] #[doc(alias = "gst_buffer_copy_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_buffer_copy_flags_get_type()) } } } impl glib::HasParamSpec for BufferCopyFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for BufferCopyFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for BufferCopyFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for BufferCopyFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: BufferCopyFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstBufferFlags")] pub struct BufferFlags: u32 { #[doc(alias = "GST_BUFFER_FLAG_LIVE")] const LIVE = ffi::GST_BUFFER_FLAG_LIVE as _; #[doc(alias = "GST_BUFFER_FLAG_DECODE_ONLY")] const DECODE_ONLY = ffi::GST_BUFFER_FLAG_DECODE_ONLY as _; #[doc(alias = "GST_BUFFER_FLAG_DISCONT")] const DISCONT = ffi::GST_BUFFER_FLAG_DISCONT as _; #[doc(alias = "GST_BUFFER_FLAG_RESYNC")] const RESYNC = ffi::GST_BUFFER_FLAG_RESYNC as _; #[doc(alias = "GST_BUFFER_FLAG_CORRUPTED")] const CORRUPTED = ffi::GST_BUFFER_FLAG_CORRUPTED as _; #[doc(alias = "GST_BUFFER_FLAG_MARKER")] const MARKER = ffi::GST_BUFFER_FLAG_MARKER as _; #[doc(alias = "GST_BUFFER_FLAG_HEADER")] const HEADER = ffi::GST_BUFFER_FLAG_HEADER as _; #[doc(alias = "GST_BUFFER_FLAG_GAP")] const GAP = ffi::GST_BUFFER_FLAG_GAP as _; #[doc(alias = "GST_BUFFER_FLAG_DROPPABLE")] const DROPPABLE = ffi::GST_BUFFER_FLAG_DROPPABLE as _; #[doc(alias = "GST_BUFFER_FLAG_DELTA_UNIT")] const DELTA_UNIT = ffi::GST_BUFFER_FLAG_DELTA_UNIT as _; #[doc(alias = "GST_BUFFER_FLAG_TAG_MEMORY")] const TAG_MEMORY = ffi::GST_BUFFER_FLAG_TAG_MEMORY as _; #[doc(alias = "GST_BUFFER_FLAG_SYNC_AFTER")] const SYNC_AFTER = ffi::GST_BUFFER_FLAG_SYNC_AFTER as _; #[doc(alias = "GST_BUFFER_FLAG_NON_DROPPABLE")] const NON_DROPPABLE = ffi::GST_BUFFER_FLAG_NON_DROPPABLE as _; } } #[doc(hidden)] impl IntoGlib for BufferFlags { type GlibType = ffi::GstBufferFlags; #[inline] fn into_glib(self) -> ffi::GstBufferFlags { self.bits() } } #[doc(hidden)] impl FromGlib for BufferFlags { #[inline] unsafe fn from_glib(value: ffi::GstBufferFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for BufferFlags { #[inline] #[doc(alias = "gst_buffer_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_buffer_flags_get_type()) } } } impl glib::HasParamSpec for BufferFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for BufferFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for BufferFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for BufferFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: BufferFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstBufferPoolAcquireFlags")] pub struct BufferPoolAcquireFlags: u32 { #[doc(alias = "GST_BUFFER_POOL_ACQUIRE_FLAG_KEY_UNIT")] const KEY_UNIT = ffi::GST_BUFFER_POOL_ACQUIRE_FLAG_KEY_UNIT as _; #[doc(alias = "GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT")] const DONTWAIT = ffi::GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT as _; #[doc(alias = "GST_BUFFER_POOL_ACQUIRE_FLAG_DISCONT")] const DISCONT = ffi::GST_BUFFER_POOL_ACQUIRE_FLAG_DISCONT as _; } } #[doc(hidden)] impl IntoGlib for BufferPoolAcquireFlags { type GlibType = ffi::GstBufferPoolAcquireFlags; #[inline] fn into_glib(self) -> ffi::GstBufferPoolAcquireFlags { self.bits() } } #[doc(hidden)] impl FromGlib for BufferPoolAcquireFlags { #[inline] unsafe fn from_glib(value: ffi::GstBufferPoolAcquireFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for BufferPoolAcquireFlags { #[inline] #[doc(alias = "gst_buffer_pool_acquire_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_buffer_pool_acquire_flags_get_type()) } } } impl glib::HasParamSpec for BufferPoolAcquireFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for BufferPoolAcquireFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for BufferPoolAcquireFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for BufferPoolAcquireFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: BufferPoolAcquireFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstClockFlags")] pub struct ClockFlags: u32 { #[doc(alias = "GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC")] const CAN_DO_SINGLE_SYNC = ffi::GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC as _; #[doc(alias = "GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC")] const CAN_DO_SINGLE_ASYNC = ffi::GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC as _; #[doc(alias = "GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC")] const CAN_DO_PERIODIC_SYNC = ffi::GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC as _; #[doc(alias = "GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC")] const CAN_DO_PERIODIC_ASYNC = ffi::GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC as _; #[doc(alias = "GST_CLOCK_FLAG_CAN_SET_RESOLUTION")] const CAN_SET_RESOLUTION = ffi::GST_CLOCK_FLAG_CAN_SET_RESOLUTION as _; #[doc(alias = "GST_CLOCK_FLAG_CAN_SET_MASTER")] const CAN_SET_MASTER = ffi::GST_CLOCK_FLAG_CAN_SET_MASTER as _; #[doc(alias = "GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC")] const NEEDS_STARTUP_SYNC = ffi::GST_CLOCK_FLAG_NEEDS_STARTUP_SYNC as _; } } #[doc(hidden)] impl IntoGlib for ClockFlags { type GlibType = ffi::GstClockFlags; #[inline] fn into_glib(self) -> ffi::GstClockFlags { self.bits() } } #[doc(hidden)] impl FromGlib for ClockFlags { #[inline] unsafe fn from_glib(value: ffi::GstClockFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for ClockFlags { #[inline] #[doc(alias = "gst_clock_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_clock_flags_get_type()) } } } impl glib::HasParamSpec for ClockFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for ClockFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for ClockFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for ClockFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: ClockFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstDebugColorFlags")] pub struct DebugColorFlags: u32 { #[doc(alias = "GST_DEBUG_FG_BLACK")] const FG_BLACK = ffi::GST_DEBUG_FG_BLACK as _; #[doc(alias = "GST_DEBUG_FG_RED")] const FG_RED = ffi::GST_DEBUG_FG_RED as _; #[doc(alias = "GST_DEBUG_FG_GREEN")] const FG_GREEN = ffi::GST_DEBUG_FG_GREEN as _; #[doc(alias = "GST_DEBUG_FG_YELLOW")] const FG_YELLOW = ffi::GST_DEBUG_FG_YELLOW as _; #[doc(alias = "GST_DEBUG_FG_BLUE")] const FG_BLUE = ffi::GST_DEBUG_FG_BLUE as _; #[doc(alias = "GST_DEBUG_FG_MAGENTA")] const FG_MAGENTA = ffi::GST_DEBUG_FG_MAGENTA as _; #[doc(alias = "GST_DEBUG_FG_CYAN")] const FG_CYAN = ffi::GST_DEBUG_FG_CYAN as _; #[doc(alias = "GST_DEBUG_FG_WHITE")] const FG_WHITE = ffi::GST_DEBUG_FG_WHITE as _; #[doc(alias = "GST_DEBUG_BG_BLACK")] const BG_BLACK = ffi::GST_DEBUG_BG_BLACK as _; #[doc(alias = "GST_DEBUG_BG_RED")] const BG_RED = ffi::GST_DEBUG_BG_RED as _; #[doc(alias = "GST_DEBUG_BG_GREEN")] const BG_GREEN = ffi::GST_DEBUG_BG_GREEN as _; #[doc(alias = "GST_DEBUG_BG_YELLOW")] const BG_YELLOW = ffi::GST_DEBUG_BG_YELLOW as _; #[doc(alias = "GST_DEBUG_BG_BLUE")] const BG_BLUE = ffi::GST_DEBUG_BG_BLUE as _; #[doc(alias = "GST_DEBUG_BG_MAGENTA")] const BG_MAGENTA = ffi::GST_DEBUG_BG_MAGENTA as _; #[doc(alias = "GST_DEBUG_BG_CYAN")] const BG_CYAN = ffi::GST_DEBUG_BG_CYAN as _; #[doc(alias = "GST_DEBUG_BG_WHITE")] const BG_WHITE = ffi::GST_DEBUG_BG_WHITE as _; #[doc(alias = "GST_DEBUG_BOLD")] const BOLD = ffi::GST_DEBUG_BOLD as _; #[doc(alias = "GST_DEBUG_UNDERLINE")] const UNDERLINE = ffi::GST_DEBUG_UNDERLINE as _; } } #[doc(hidden)] impl IntoGlib for DebugColorFlags { type GlibType = ffi::GstDebugColorFlags; #[inline] fn into_glib(self) -> ffi::GstDebugColorFlags { self.bits() } } #[doc(hidden)] impl FromGlib for DebugColorFlags { #[inline] unsafe fn from_glib(value: ffi::GstDebugColorFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for DebugColorFlags { #[inline] #[doc(alias = "gst_debug_color_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_debug_color_flags_get_type()) } } } impl glib::HasParamSpec for DebugColorFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for DebugColorFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for DebugColorFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for DebugColorFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: DebugColorFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstDebugGraphDetails")] pub struct DebugGraphDetails: u32 { #[doc(alias = "GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE")] const MEDIA_TYPE = ffi::GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE as _; #[doc(alias = "GST_DEBUG_GRAPH_SHOW_CAPS_DETAILS")] const CAPS_DETAILS = ffi::GST_DEBUG_GRAPH_SHOW_CAPS_DETAILS as _; #[doc(alias = "GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS")] const NON_DEFAULT_PARAMS = ffi::GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS as _; #[doc(alias = "GST_DEBUG_GRAPH_SHOW_STATES")] const STATES = ffi::GST_DEBUG_GRAPH_SHOW_STATES as _; #[doc(alias = "GST_DEBUG_GRAPH_SHOW_FULL_PARAMS")] const FULL_PARAMS = ffi::GST_DEBUG_GRAPH_SHOW_FULL_PARAMS as _; #[doc(alias = "GST_DEBUG_GRAPH_SHOW_ALL")] const ALL = ffi::GST_DEBUG_GRAPH_SHOW_ALL as _; #[doc(alias = "GST_DEBUG_GRAPH_SHOW_VERBOSE")] const VERBOSE = ffi::GST_DEBUG_GRAPH_SHOW_VERBOSE as _; } } #[doc(hidden)] impl IntoGlib for DebugGraphDetails { type GlibType = ffi::GstDebugGraphDetails; #[inline] fn into_glib(self) -> ffi::GstDebugGraphDetails { self.bits() } } #[doc(hidden)] impl FromGlib for DebugGraphDetails { #[inline] unsafe fn from_glib(value: ffi::GstDebugGraphDetails) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for DebugGraphDetails { #[inline] #[doc(alias = "gst_debug_graph_details_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_debug_graph_details_get_type()) } } } impl glib::HasParamSpec for DebugGraphDetails { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for DebugGraphDetails { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for DebugGraphDetails { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for DebugGraphDetails { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: DebugGraphDetails) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstElementFlags")] pub struct ElementFlags: u32 { #[doc(alias = "GST_ELEMENT_FLAG_LOCKED_STATE")] const LOCKED_STATE = ffi::GST_ELEMENT_FLAG_LOCKED_STATE as _; #[doc(alias = "GST_ELEMENT_FLAG_SINK")] const SINK = ffi::GST_ELEMENT_FLAG_SINK as _; #[doc(alias = "GST_ELEMENT_FLAG_SOURCE")] const SOURCE = ffi::GST_ELEMENT_FLAG_SOURCE as _; #[doc(alias = "GST_ELEMENT_FLAG_PROVIDE_CLOCK")] const PROVIDE_CLOCK = ffi::GST_ELEMENT_FLAG_PROVIDE_CLOCK as _; #[doc(alias = "GST_ELEMENT_FLAG_REQUIRE_CLOCK")] const REQUIRE_CLOCK = ffi::GST_ELEMENT_FLAG_REQUIRE_CLOCK as _; #[doc(alias = "GST_ELEMENT_FLAG_INDEXABLE")] const INDEXABLE = ffi::GST_ELEMENT_FLAG_INDEXABLE as _; } } #[doc(hidden)] impl IntoGlib for ElementFlags { type GlibType = ffi::GstElementFlags; #[inline] fn into_glib(self) -> ffi::GstElementFlags { self.bits() } } #[doc(hidden)] impl FromGlib for ElementFlags { #[inline] unsafe fn from_glib(value: ffi::GstElementFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for ElementFlags { #[inline] #[doc(alias = "gst_element_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_element_flags_get_type()) } } } impl glib::HasParamSpec for ElementFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for ElementFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for ElementFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for ElementFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: ElementFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstEventTypeFlags")] pub struct EventTypeFlags: u32 { #[doc(alias = "GST_EVENT_TYPE_UPSTREAM")] const UPSTREAM = ffi::GST_EVENT_TYPE_UPSTREAM as _; #[doc(alias = "GST_EVENT_TYPE_DOWNSTREAM")] const DOWNSTREAM = ffi::GST_EVENT_TYPE_DOWNSTREAM as _; #[doc(alias = "GST_EVENT_TYPE_SERIALIZED")] const SERIALIZED = ffi::GST_EVENT_TYPE_SERIALIZED as _; #[doc(alias = "GST_EVENT_TYPE_STICKY")] const STICKY = ffi::GST_EVENT_TYPE_STICKY as _; #[doc(alias = "GST_EVENT_TYPE_STICKY_MULTI")] const STICKY_MULTI = ffi::GST_EVENT_TYPE_STICKY_MULTI as _; } } #[doc(hidden)] impl IntoGlib for EventTypeFlags { type GlibType = ffi::GstEventTypeFlags; #[inline] fn into_glib(self) -> ffi::GstEventTypeFlags { self.bits() } } #[doc(hidden)] impl FromGlib for EventTypeFlags { #[inline] unsafe fn from_glib(value: ffi::GstEventTypeFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for EventTypeFlags { #[inline] #[doc(alias = "gst_event_type_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_event_type_flags_get_type()) } } } impl glib::HasParamSpec for EventTypeFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for EventTypeFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for EventTypeFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for EventTypeFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: EventTypeFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg(feature = "v1_20")] bitflags! { #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstGapFlags")] pub struct GapFlags: u32 { #[doc(alias = "GST_GAP_FLAG_MISSING_DATA")] const DATA = ffi::GST_GAP_FLAG_MISSING_DATA as _; } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[doc(hidden)] impl IntoGlib for GapFlags { type GlibType = ffi::GstGapFlags; #[inline] fn into_glib(self) -> ffi::GstGapFlags { self.bits() } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[doc(hidden)] impl FromGlib for GapFlags { #[inline] unsafe fn from_glib(value: ffi::GstGapFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl StaticType for GapFlags { #[inline] #[doc(alias = "gst_gap_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_gap_flags_get_type()) } } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl glib::HasParamSpec for GapFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl glib::value::ValueType for GapFlags { type Type = Self; } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] unsafe impl<'a> glib::value::FromValue<'a> for GapFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl ToValue for GapFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl From for glib::Value { #[inline] fn from(v: GapFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstMemoryFlags")] pub struct MemoryFlags: u32 { #[doc(alias = "GST_MEMORY_FLAG_READONLY")] const READONLY = ffi::GST_MEMORY_FLAG_READONLY as _; #[doc(alias = "GST_MEMORY_FLAG_NO_SHARE")] const NO_SHARE = ffi::GST_MEMORY_FLAG_NO_SHARE as _; #[doc(alias = "GST_MEMORY_FLAG_ZERO_PREFIXED")] const ZERO_PREFIXED = ffi::GST_MEMORY_FLAG_ZERO_PREFIXED as _; #[doc(alias = "GST_MEMORY_FLAG_ZERO_PADDED")] const ZERO_PADDED = ffi::GST_MEMORY_FLAG_ZERO_PADDED as _; #[doc(alias = "GST_MEMORY_FLAG_PHYSICALLY_CONTIGUOUS")] const PHYSICALLY_CONTIGUOUS = ffi::GST_MEMORY_FLAG_PHYSICALLY_CONTIGUOUS as _; #[doc(alias = "GST_MEMORY_FLAG_NOT_MAPPABLE")] const NOT_MAPPABLE = ffi::GST_MEMORY_FLAG_NOT_MAPPABLE as _; } } #[doc(hidden)] impl IntoGlib for MemoryFlags { type GlibType = ffi::GstMemoryFlags; #[inline] fn into_glib(self) -> ffi::GstMemoryFlags { self.bits() } } #[doc(hidden)] impl FromGlib for MemoryFlags { #[inline] unsafe fn from_glib(value: ffi::GstMemoryFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for MemoryFlags { #[inline] #[doc(alias = "gst_memory_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_memory_flags_get_type()) } } } impl glib::HasParamSpec for MemoryFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for MemoryFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for MemoryFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for MemoryFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: MemoryFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstMetaFlags")] pub struct MetaFlags: u32 { #[doc(alias = "GST_META_FLAG_READONLY")] const READONLY = ffi::GST_META_FLAG_READONLY as _; #[doc(alias = "GST_META_FLAG_POOLED")] const POOLED = ffi::GST_META_FLAG_POOLED as _; #[doc(alias = "GST_META_FLAG_LOCKED")] const LOCKED = ffi::GST_META_FLAG_LOCKED as _; } } #[doc(hidden)] impl IntoGlib for MetaFlags { type GlibType = ffi::GstMetaFlags; #[inline] fn into_glib(self) -> ffi::GstMetaFlags { self.bits() } } #[doc(hidden)] impl FromGlib for MetaFlags { #[inline] unsafe fn from_glib(value: ffi::GstMetaFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for MetaFlags { #[inline] #[doc(alias = "gst_meta_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_meta_flags_get_type()) } } } impl glib::HasParamSpec for MetaFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for MetaFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for MetaFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for MetaFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: MetaFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstObjectFlags")] pub struct ObjectFlags: u32 { #[doc(alias = "GST_OBJECT_FLAG_MAY_BE_LEAKED")] const MAY_BE_LEAKED = ffi::GST_OBJECT_FLAG_MAY_BE_LEAKED as _; #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "GST_OBJECT_FLAG_CONSTRUCTED")] const CONSTRUCTED = ffi::GST_OBJECT_FLAG_CONSTRUCTED as _; } } #[doc(hidden)] impl IntoGlib for ObjectFlags { type GlibType = ffi::GstObjectFlags; #[inline] fn into_glib(self) -> ffi::GstObjectFlags { self.bits() } } #[doc(hidden)] impl FromGlib for ObjectFlags { #[inline] unsafe fn from_glib(value: ffi::GstObjectFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for ObjectFlags { #[inline] #[doc(alias = "gst_object_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_object_flags_get_type()) } } } impl glib::HasParamSpec for ObjectFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for ObjectFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for ObjectFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for ObjectFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: ObjectFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstPadFlags")] pub struct PadFlags: u32 { #[doc(alias = "GST_PAD_FLAG_BLOCKED")] const BLOCKED = ffi::GST_PAD_FLAG_BLOCKED as _; #[doc(alias = "GST_PAD_FLAG_FLUSHING")] const FLUSHING = ffi::GST_PAD_FLAG_FLUSHING as _; #[doc(alias = "GST_PAD_FLAG_EOS")] const EOS = ffi::GST_PAD_FLAG_EOS as _; #[doc(alias = "GST_PAD_FLAG_BLOCKING")] const BLOCKING = ffi::GST_PAD_FLAG_BLOCKING as _; #[doc(alias = "GST_PAD_FLAG_NEED_PARENT")] const NEED_PARENT = ffi::GST_PAD_FLAG_NEED_PARENT as _; #[doc(alias = "GST_PAD_FLAG_NEED_RECONFIGURE")] const NEED_RECONFIGURE = ffi::GST_PAD_FLAG_NEED_RECONFIGURE as _; #[doc(alias = "GST_PAD_FLAG_PENDING_EVENTS")] const PENDING_EVENTS = ffi::GST_PAD_FLAG_PENDING_EVENTS as _; #[doc(alias = "GST_PAD_FLAG_FIXED_CAPS")] const FIXED_CAPS = ffi::GST_PAD_FLAG_FIXED_CAPS as _; #[doc(alias = "GST_PAD_FLAG_PROXY_CAPS")] const PROXY_CAPS = ffi::GST_PAD_FLAG_PROXY_CAPS as _; #[doc(alias = "GST_PAD_FLAG_PROXY_ALLOCATION")] const PROXY_ALLOCATION = ffi::GST_PAD_FLAG_PROXY_ALLOCATION as _; #[doc(alias = "GST_PAD_FLAG_PROXY_SCHEDULING")] const PROXY_SCHEDULING = ffi::GST_PAD_FLAG_PROXY_SCHEDULING as _; #[doc(alias = "GST_PAD_FLAG_ACCEPT_INTERSECT")] const ACCEPT_INTERSECT = ffi::GST_PAD_FLAG_ACCEPT_INTERSECT as _; #[doc(alias = "GST_PAD_FLAG_ACCEPT_TEMPLATE")] const ACCEPT_TEMPLATE = ffi::GST_PAD_FLAG_ACCEPT_TEMPLATE as _; } } #[doc(hidden)] impl IntoGlib for PadFlags { type GlibType = ffi::GstPadFlags; #[inline] fn into_glib(self) -> ffi::GstPadFlags { self.bits() } } #[doc(hidden)] impl FromGlib for PadFlags { #[inline] unsafe fn from_glib(value: ffi::GstPadFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for PadFlags { #[inline] #[doc(alias = "gst_pad_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_pad_flags_get_type()) } } } impl glib::HasParamSpec for PadFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for PadFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PadFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for PadFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PadFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstPadLinkCheck")] pub struct PadLinkCheck: u32 { #[doc(alias = "GST_PAD_LINK_CHECK_HIERARCHY")] const HIERARCHY = ffi::GST_PAD_LINK_CHECK_HIERARCHY as _; #[doc(alias = "GST_PAD_LINK_CHECK_TEMPLATE_CAPS")] const TEMPLATE_CAPS = ffi::GST_PAD_LINK_CHECK_TEMPLATE_CAPS as _; #[doc(alias = "GST_PAD_LINK_CHECK_CAPS")] const CAPS = ffi::GST_PAD_LINK_CHECK_CAPS as _; #[doc(alias = "GST_PAD_LINK_CHECK_NO_RECONFIGURE")] const NO_RECONFIGURE = ffi::GST_PAD_LINK_CHECK_NO_RECONFIGURE as _; #[doc(alias = "GST_PAD_LINK_CHECK_DEFAULT")] const DEFAULT = ffi::GST_PAD_LINK_CHECK_DEFAULT as _; } } #[doc(hidden)] impl IntoGlib for PadLinkCheck { type GlibType = ffi::GstPadLinkCheck; #[inline] fn into_glib(self) -> ffi::GstPadLinkCheck { self.bits() } } #[doc(hidden)] impl FromGlib for PadLinkCheck { #[inline] unsafe fn from_glib(value: ffi::GstPadLinkCheck) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for PadLinkCheck { #[inline] #[doc(alias = "gst_pad_link_check_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_pad_link_check_get_type()) } } } impl glib::HasParamSpec for PadLinkCheck { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for PadLinkCheck { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PadLinkCheck { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for PadLinkCheck { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PadLinkCheck) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstPadProbeType")] pub struct PadProbeType: u32 { #[doc(alias = "GST_PAD_PROBE_TYPE_IDLE")] const IDLE = ffi::GST_PAD_PROBE_TYPE_IDLE as _; #[doc(alias = "GST_PAD_PROBE_TYPE_BLOCK")] const BLOCK = ffi::GST_PAD_PROBE_TYPE_BLOCK as _; #[doc(alias = "GST_PAD_PROBE_TYPE_BUFFER")] const BUFFER = ffi::GST_PAD_PROBE_TYPE_BUFFER as _; #[doc(alias = "GST_PAD_PROBE_TYPE_BUFFER_LIST")] const BUFFER_LIST = ffi::GST_PAD_PROBE_TYPE_BUFFER_LIST as _; #[doc(alias = "GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM")] const EVENT_DOWNSTREAM = ffi::GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM as _; #[doc(alias = "GST_PAD_PROBE_TYPE_EVENT_UPSTREAM")] const EVENT_UPSTREAM = ffi::GST_PAD_PROBE_TYPE_EVENT_UPSTREAM as _; #[doc(alias = "GST_PAD_PROBE_TYPE_EVENT_FLUSH")] const EVENT_FLUSH = ffi::GST_PAD_PROBE_TYPE_EVENT_FLUSH as _; #[doc(alias = "GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM")] const QUERY_DOWNSTREAM = ffi::GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM as _; #[doc(alias = "GST_PAD_PROBE_TYPE_QUERY_UPSTREAM")] const QUERY_UPSTREAM = ffi::GST_PAD_PROBE_TYPE_QUERY_UPSTREAM as _; #[doc(alias = "GST_PAD_PROBE_TYPE_PUSH")] const PUSH = ffi::GST_PAD_PROBE_TYPE_PUSH as _; #[doc(alias = "GST_PAD_PROBE_TYPE_PULL")] const PULL = ffi::GST_PAD_PROBE_TYPE_PULL as _; #[doc(alias = "GST_PAD_PROBE_TYPE_BLOCKING")] const BLOCKING = ffi::GST_PAD_PROBE_TYPE_BLOCKING as _; #[doc(alias = "GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM")] const DATA_DOWNSTREAM = ffi::GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM as _; #[doc(alias = "GST_PAD_PROBE_TYPE_DATA_UPSTREAM")] const DATA_UPSTREAM = ffi::GST_PAD_PROBE_TYPE_DATA_UPSTREAM as _; #[doc(alias = "GST_PAD_PROBE_TYPE_DATA_BOTH")] const DATA_BOTH = ffi::GST_PAD_PROBE_TYPE_DATA_BOTH as _; #[doc(alias = "GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM")] const BLOCK_DOWNSTREAM = ffi::GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM as _; #[doc(alias = "GST_PAD_PROBE_TYPE_BLOCK_UPSTREAM")] const BLOCK_UPSTREAM = ffi::GST_PAD_PROBE_TYPE_BLOCK_UPSTREAM as _; #[doc(alias = "GST_PAD_PROBE_TYPE_EVENT_BOTH")] const EVENT_BOTH = ffi::GST_PAD_PROBE_TYPE_EVENT_BOTH as _; #[doc(alias = "GST_PAD_PROBE_TYPE_QUERY_BOTH")] const QUERY_BOTH = ffi::GST_PAD_PROBE_TYPE_QUERY_BOTH as _; #[doc(alias = "GST_PAD_PROBE_TYPE_ALL_BOTH")] const ALL_BOTH = ffi::GST_PAD_PROBE_TYPE_ALL_BOTH as _; #[doc(alias = "GST_PAD_PROBE_TYPE_SCHEDULING")] const SCHEDULING = ffi::GST_PAD_PROBE_TYPE_SCHEDULING as _; } } #[doc(hidden)] impl IntoGlib for PadProbeType { type GlibType = ffi::GstPadProbeType; #[inline] fn into_glib(self) -> ffi::GstPadProbeType { self.bits() } } #[doc(hidden)] impl FromGlib for PadProbeType { #[inline] unsafe fn from_glib(value: ffi::GstPadProbeType) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for PadProbeType { #[inline] #[doc(alias = "gst_pad_probe_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_pad_probe_type_get_type()) } } } impl glib::HasParamSpec for PadProbeType { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for PadProbeType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PadProbeType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for PadProbeType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PadProbeType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstParseFlags")] pub struct ParseFlags: u32 { #[doc(alias = "GST_PARSE_FLAG_FATAL_ERRORS")] const FATAL_ERRORS = ffi::GST_PARSE_FLAG_FATAL_ERRORS as _; #[doc(alias = "GST_PARSE_FLAG_NO_SINGLE_ELEMENT_BINS")] const NO_SINGLE_ELEMENT_BINS = ffi::GST_PARSE_FLAG_NO_SINGLE_ELEMENT_BINS as _; #[doc(alias = "GST_PARSE_FLAG_PLACE_IN_BIN")] const PLACE_IN_BIN = ffi::GST_PARSE_FLAG_PLACE_IN_BIN as _; } } #[doc(hidden)] impl IntoGlib for ParseFlags { type GlibType = ffi::GstParseFlags; #[inline] fn into_glib(self) -> ffi::GstParseFlags { self.bits() } } #[doc(hidden)] impl FromGlib for ParseFlags { #[inline] unsafe fn from_glib(value: ffi::GstParseFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for ParseFlags { #[inline] #[doc(alias = "gst_parse_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_parse_flags_get_type()) } } } impl glib::HasParamSpec for ParseFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for ParseFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for ParseFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for ParseFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: ParseFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstPipelineFlags")] pub struct PipelineFlags: u32 { #[doc(alias = "GST_PIPELINE_FLAG_FIXED_CLOCK")] const FIXED_CLOCK = ffi::GST_PIPELINE_FLAG_FIXED_CLOCK as _; } } #[doc(hidden)] impl IntoGlib for PipelineFlags { type GlibType = ffi::GstPipelineFlags; #[inline] fn into_glib(self) -> ffi::GstPipelineFlags { self.bits() } } #[doc(hidden)] impl FromGlib for PipelineFlags { #[inline] unsafe fn from_glib(value: ffi::GstPipelineFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for PipelineFlags { #[inline] #[doc(alias = "gst_pipeline_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_pipeline_flags_get_type()) } } } impl glib::HasParamSpec for PipelineFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for PipelineFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PipelineFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for PipelineFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PipelineFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg(feature = "v1_18")] bitflags! { #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstPluginAPIFlags")] pub struct PluginAPIFlags: u32 { #[doc(alias = "GST_PLUGIN_API_FLAG_IGNORE_ENUM_MEMBERS")] const MEMBERS = ffi::GST_PLUGIN_API_FLAG_IGNORE_ENUM_MEMBERS as _; } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(hidden)] impl IntoGlib for PluginAPIFlags { type GlibType = ffi::GstPluginAPIFlags; #[inline] fn into_glib(self) -> ffi::GstPluginAPIFlags { self.bits() } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(hidden)] impl FromGlib for PluginAPIFlags { #[inline] unsafe fn from_glib(value: ffi::GstPluginAPIFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl StaticType for PluginAPIFlags { #[inline] #[doc(alias = "gst_plugin_api_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_plugin_api_flags_get_type()) } } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl glib::HasParamSpec for PluginAPIFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl glib::value::ValueType for PluginAPIFlags { type Type = Self; } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] unsafe impl<'a> glib::value::FromValue<'a> for PluginAPIFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl ToValue for PluginAPIFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl From for glib::Value { #[inline] fn from(v: PluginAPIFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstPluginDependencyFlags")] pub struct PluginDependencyFlags: u32 { #[doc(alias = "GST_PLUGIN_DEPENDENCY_FLAG_RECURSE")] const RECURSE = ffi::GST_PLUGIN_DEPENDENCY_FLAG_RECURSE as _; #[doc(alias = "GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY")] const PATHS_ARE_DEFAULT_ONLY = ffi::GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY as _; #[doc(alias = "GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX")] const FILE_NAME_IS_SUFFIX = ffi::GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX as _; #[doc(alias = "GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX")] const FILE_NAME_IS_PREFIX = ffi::GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX as _; #[doc(alias = "GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE")] const PATHS_ARE_RELATIVE_TO_EXE = ffi::GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE as _; } } #[doc(hidden)] impl IntoGlib for PluginDependencyFlags { type GlibType = ffi::GstPluginDependencyFlags; #[inline] fn into_glib(self) -> ffi::GstPluginDependencyFlags { self.bits() } } #[doc(hidden)] impl FromGlib for PluginDependencyFlags { #[inline] unsafe fn from_glib(value: ffi::GstPluginDependencyFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for PluginDependencyFlags { #[inline] #[doc(alias = "gst_plugin_dependency_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_plugin_dependency_flags_get_type()) } } } impl glib::HasParamSpec for PluginDependencyFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for PluginDependencyFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PluginDependencyFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for PluginDependencyFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PluginDependencyFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstPluginFlags")] pub struct PluginFlags: u32 { #[doc(alias = "GST_PLUGIN_FLAG_CACHED")] const CACHED = ffi::GST_PLUGIN_FLAG_CACHED as _; #[doc(alias = "GST_PLUGIN_FLAG_BLACKLISTED")] const BLACKLISTED = ffi::GST_PLUGIN_FLAG_BLACKLISTED as _; } } #[doc(hidden)] impl IntoGlib for PluginFlags { type GlibType = ffi::GstPluginFlags; #[inline] fn into_glib(self) -> ffi::GstPluginFlags { self.bits() } } #[doc(hidden)] impl FromGlib for PluginFlags { #[inline] unsafe fn from_glib(value: ffi::GstPluginFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for PluginFlags { #[inline] #[doc(alias = "gst_plugin_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_plugin_flags_get_type()) } } } impl glib::HasParamSpec for PluginFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for PluginFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for PluginFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for PluginFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PluginFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstSchedulingFlags")] pub struct SchedulingFlags: u32 { #[doc(alias = "GST_SCHEDULING_FLAG_SEEKABLE")] const SEEKABLE = ffi::GST_SCHEDULING_FLAG_SEEKABLE as _; #[doc(alias = "GST_SCHEDULING_FLAG_SEQUENTIAL")] const SEQUENTIAL = ffi::GST_SCHEDULING_FLAG_SEQUENTIAL as _; #[doc(alias = "GST_SCHEDULING_FLAG_BANDWIDTH_LIMITED")] const BANDWIDTH_LIMITED = ffi::GST_SCHEDULING_FLAG_BANDWIDTH_LIMITED as _; } } #[doc(hidden)] impl IntoGlib for SchedulingFlags { type GlibType = ffi::GstSchedulingFlags; #[inline] fn into_glib(self) -> ffi::GstSchedulingFlags { self.bits() } } #[doc(hidden)] impl FromGlib for SchedulingFlags { #[inline] unsafe fn from_glib(value: ffi::GstSchedulingFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for SchedulingFlags { #[inline] #[doc(alias = "gst_scheduling_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_scheduling_flags_get_type()) } } } impl glib::HasParamSpec for SchedulingFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for SchedulingFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for SchedulingFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for SchedulingFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: SchedulingFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstSeekFlags")] pub struct SeekFlags: u32 { #[doc(alias = "GST_SEEK_FLAG_FLUSH")] const FLUSH = ffi::GST_SEEK_FLAG_FLUSH as _; #[doc(alias = "GST_SEEK_FLAG_ACCURATE")] const ACCURATE = ffi::GST_SEEK_FLAG_ACCURATE as _; #[doc(alias = "GST_SEEK_FLAG_KEY_UNIT")] const KEY_UNIT = ffi::GST_SEEK_FLAG_KEY_UNIT as _; #[doc(alias = "GST_SEEK_FLAG_SEGMENT")] const SEGMENT = ffi::GST_SEEK_FLAG_SEGMENT as _; #[doc(alias = "GST_SEEK_FLAG_TRICKMODE")] const TRICKMODE = ffi::GST_SEEK_FLAG_TRICKMODE as _; #[doc(alias = "GST_SEEK_FLAG_SKIP")] const SKIP = ffi::GST_SEEK_FLAG_SKIP as _; #[doc(alias = "GST_SEEK_FLAG_SNAP_BEFORE")] const SNAP_BEFORE = ffi::GST_SEEK_FLAG_SNAP_BEFORE as _; #[doc(alias = "GST_SEEK_FLAG_SNAP_AFTER")] const SNAP_AFTER = ffi::GST_SEEK_FLAG_SNAP_AFTER as _; #[doc(alias = "GST_SEEK_FLAG_SNAP_NEAREST")] const SNAP_NEAREST = ffi::GST_SEEK_FLAG_SNAP_NEAREST as _; #[doc(alias = "GST_SEEK_FLAG_TRICKMODE_KEY_UNITS")] const TRICKMODE_KEY_UNITS = ffi::GST_SEEK_FLAG_TRICKMODE_KEY_UNITS as _; #[doc(alias = "GST_SEEK_FLAG_TRICKMODE_NO_AUDIO")] const TRICKMODE_NO_AUDIO = ffi::GST_SEEK_FLAG_TRICKMODE_NO_AUDIO as _; #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED")] const TRICKMODE_FORWARD_PREDICTED = ffi::GST_SEEK_FLAG_TRICKMODE_FORWARD_PREDICTED as _; #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "GST_SEEK_FLAG_INSTANT_RATE_CHANGE")] const INSTANT_RATE_CHANGE = ffi::GST_SEEK_FLAG_INSTANT_RATE_CHANGE as _; } } #[doc(hidden)] impl IntoGlib for SeekFlags { type GlibType = ffi::GstSeekFlags; #[inline] fn into_glib(self) -> ffi::GstSeekFlags { self.bits() } } #[doc(hidden)] impl FromGlib for SeekFlags { #[inline] unsafe fn from_glib(value: ffi::GstSeekFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for SeekFlags { #[inline] #[doc(alias = "gst_seek_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_seek_flags_get_type()) } } } impl glib::HasParamSpec for SeekFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for SeekFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for SeekFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for SeekFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: SeekFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstSegmentFlags")] pub struct SegmentFlags: u32 { #[doc(alias = "GST_SEGMENT_FLAG_RESET")] const RESET = ffi::GST_SEGMENT_FLAG_RESET as _; #[doc(alias = "GST_SEGMENT_FLAG_TRICKMODE")] const TRICKMODE = ffi::GST_SEGMENT_FLAG_TRICKMODE as _; #[doc(alias = "GST_SEGMENT_FLAG_SKIP")] const SKIP = ffi::GST_SEGMENT_FLAG_SKIP as _; #[doc(alias = "GST_SEGMENT_FLAG_SEGMENT")] const SEGMENT = ffi::GST_SEGMENT_FLAG_SEGMENT as _; #[doc(alias = "GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS")] const TRICKMODE_KEY_UNITS = ffi::GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS as _; #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "GST_SEGMENT_FLAG_TRICKMODE_FORWARD_PREDICTED")] const TRICKMODE_FORWARD_PREDICTED = ffi::GST_SEGMENT_FLAG_TRICKMODE_FORWARD_PREDICTED as _; #[doc(alias = "GST_SEGMENT_FLAG_TRICKMODE_NO_AUDIO")] const TRICKMODE_NO_AUDIO = ffi::GST_SEGMENT_FLAG_TRICKMODE_NO_AUDIO as _; } } #[doc(hidden)] impl IntoGlib for SegmentFlags { type GlibType = ffi::GstSegmentFlags; #[inline] fn into_glib(self) -> ffi::GstSegmentFlags { self.bits() } } #[doc(hidden)] impl FromGlib for SegmentFlags { #[inline] unsafe fn from_glib(value: ffi::GstSegmentFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for SegmentFlags { #[inline] #[doc(alias = "gst_segment_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_segment_flags_get_type()) } } } impl glib::HasParamSpec for SegmentFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for SegmentFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for SegmentFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for SegmentFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: SegmentFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } #[cfg(feature = "v1_20")] bitflags! { #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstSerializeFlags")] pub struct SerializeFlags: u32 { #[doc(alias = "GST_SERIALIZE_FLAG_NONE")] const NONE = ffi::GST_SERIALIZE_FLAG_NONE as _; #[doc(alias = "GST_SERIALIZE_FLAG_BACKWARD_COMPAT")] const BACKWARD_COMPAT = ffi::GST_SERIALIZE_FLAG_BACKWARD_COMPAT as _; } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[doc(hidden)] impl IntoGlib for SerializeFlags { type GlibType = ffi::GstSerializeFlags; #[inline] fn into_glib(self) -> ffi::GstSerializeFlags { self.bits() } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[doc(hidden)] impl FromGlib for SerializeFlags { #[inline] unsafe fn from_glib(value: ffi::GstSerializeFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl StaticType for SerializeFlags { #[inline] #[doc(alias = "gst_serialize_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_serialize_flags_get_type()) } } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl glib::HasParamSpec for SerializeFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl glib::value::ValueType for SerializeFlags { type Type = Self; } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] unsafe impl<'a> glib::value::FromValue<'a> for SerializeFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl ToValue for SerializeFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl From for glib::Value { #[inline] fn from(v: SerializeFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstStackTraceFlags")] pub struct StackTraceFlags: u32 { #[doc(alias = "GST_STACK_TRACE_SHOW_FULL")] const FULL = ffi::GST_STACK_TRACE_SHOW_FULL as _; } } #[doc(hidden)] impl IntoGlib for StackTraceFlags { type GlibType = ffi::GstStackTraceFlags; #[inline] fn into_glib(self) -> ffi::GstStackTraceFlags { self.bits() } } #[doc(hidden)] impl FromGlib for StackTraceFlags { #[inline] unsafe fn from_glib(value: ffi::GstStackTraceFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for StackTraceFlags { #[inline] #[doc(alias = "gst_stack_trace_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_stack_trace_flags_get_type()) } } } impl glib::HasParamSpec for StackTraceFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for StackTraceFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for StackTraceFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for StackTraceFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: StackTraceFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstStreamFlags")] pub struct StreamFlags: u32 { #[doc(alias = "GST_STREAM_FLAG_SPARSE")] const SPARSE = ffi::GST_STREAM_FLAG_SPARSE as _; #[doc(alias = "GST_STREAM_FLAG_SELECT")] const SELECT = ffi::GST_STREAM_FLAG_SELECT as _; #[doc(alias = "GST_STREAM_FLAG_UNSELECT")] const UNSELECT = ffi::GST_STREAM_FLAG_UNSELECT as _; } } #[doc(hidden)] impl IntoGlib for StreamFlags { type GlibType = ffi::GstStreamFlags; #[inline] fn into_glib(self) -> ffi::GstStreamFlags { self.bits() } } #[doc(hidden)] impl FromGlib for StreamFlags { #[inline] unsafe fn from_glib(value: ffi::GstStreamFlags) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for StreamFlags { #[inline] #[doc(alias = "gst_stream_flags_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_stream_flags_get_type()) } } } impl glib::HasParamSpec for StreamFlags { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for StreamFlags { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for StreamFlags { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for StreamFlags { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: StreamFlags) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[doc(alias = "GstStreamType")] pub struct StreamType: u32 { #[doc(alias = "GST_STREAM_TYPE_UNKNOWN")] const UNKNOWN = ffi::GST_STREAM_TYPE_UNKNOWN as _; #[doc(alias = "GST_STREAM_TYPE_AUDIO")] const AUDIO = ffi::GST_STREAM_TYPE_AUDIO as _; #[doc(alias = "GST_STREAM_TYPE_VIDEO")] const VIDEO = ffi::GST_STREAM_TYPE_VIDEO as _; #[doc(alias = "GST_STREAM_TYPE_CONTAINER")] const CONTAINER = ffi::GST_STREAM_TYPE_CONTAINER as _; #[doc(alias = "GST_STREAM_TYPE_TEXT")] const TEXT = ffi::GST_STREAM_TYPE_TEXT as _; } } impl StreamType { pub fn name<'a>(self) -> &'a GStr { unsafe { GStr::from_ptr( ffi::gst_stream_type_get_name(self.into_glib()) .as_ref() .expect("gst_stream_type_get_name returned NULL"), ) } } } impl std::fmt::Display for StreamType { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(&self.name()) } } #[doc(hidden)] impl IntoGlib for StreamType { type GlibType = ffi::GstStreamType; #[inline] fn into_glib(self) -> ffi::GstStreamType { self.bits() } } #[doc(hidden)] impl FromGlib for StreamType { #[inline] unsafe fn from_glib(value: ffi::GstStreamType) -> Self { skip_assert_initialized!(); Self::from_bits_truncate(value) } } impl StaticType for StreamType { #[inline] #[doc(alias = "gst_stream_type_get_type")] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_stream_type_get_type()) } } } impl glib::HasParamSpec for StreamType { type ParamSpec = glib::ParamSpecFlags; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecFlagsBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } impl glib::value::ValueType for StreamType { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for StreamType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_flags(value.to_glib_none().0)) } } impl ToValue for StreamType { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_flags(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: StreamType) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } gstreamer-0.23.5/src/auto/functions.rs000064400000000000000000000172561046102023000160340ustar 00000000000000// 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::{ffi, Bin, ClockTime, DebugGraphDetails, DebugLevel, Element, StackTraceFlags}; use glib::{prelude::*, translate::*}; #[doc(alias = "gst_debug_add_ring_buffer_logger")] pub fn debug_add_ring_buffer_logger(max_size_per_thread: u32, thread_timeout: u32) { skip_assert_initialized!(); unsafe { ffi::gst_debug_add_ring_buffer_logger(max_size_per_thread, thread_timeout); } } #[doc(alias = "gst_debug_bin_to_dot_data")] pub fn debug_bin_to_dot_data(bin: &impl IsA, details: DebugGraphDetails) -> glib::GString { skip_assert_initialized!(); unsafe { from_glib_full(ffi::gst_debug_bin_to_dot_data( bin.as_ref().to_glib_none().0, details.into_glib(), )) } } #[doc(alias = "gst_debug_bin_to_dot_file")] pub fn debug_bin_to_dot_file( bin: &impl IsA, details: DebugGraphDetails, file_name: impl AsRef, ) { skip_assert_initialized!(); unsafe { ffi::gst_debug_bin_to_dot_file( bin.as_ref().to_glib_none().0, details.into_glib(), file_name.as_ref().to_glib_none().0, ); } } #[doc(alias = "gst_debug_bin_to_dot_file_with_ts")] pub fn debug_bin_to_dot_file_with_ts( bin: &impl IsA, details: DebugGraphDetails, file_name: impl AsRef, ) { skip_assert_initialized!(); unsafe { ffi::gst_debug_bin_to_dot_file_with_ts( bin.as_ref().to_glib_none().0, details.into_glib(), file_name.as_ref().to_glib_none().0, ); } } #[doc(alias = "gst_debug_get_default_threshold")] pub fn debug_get_default_threshold() -> DebugLevel { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_debug_get_default_threshold()) } } #[doc(alias = "gst_debug_get_stack_trace")] pub fn debug_get_stack_trace(flags: StackTraceFlags) -> Result { skip_assert_initialized!(); unsafe { Option::<_>::from_glib_full(ffi::gst_debug_get_stack_trace(flags.into_glib())) .ok_or_else(|| glib::bool_error!("Failed to get stack trace")) } } #[doc(alias = "gst_debug_is_active")] pub fn debug_is_active() -> bool { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_debug_is_active()) } } #[doc(alias = "gst_debug_is_colored")] pub fn debug_is_colored() -> bool { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_debug_is_colored()) } } #[doc(alias = "gst_debug_print_stack_trace")] pub fn debug_print_stack_trace() { skip_assert_initialized!(); unsafe { ffi::gst_debug_print_stack_trace(); } } #[doc(alias = "gst_debug_remove_ring_buffer_logger")] pub fn debug_remove_ring_buffer_logger() { skip_assert_initialized!(); unsafe { ffi::gst_debug_remove_ring_buffer_logger(); } } #[doc(alias = "gst_debug_ring_buffer_logger_get_logs")] pub fn debug_ring_buffer_logger_get_logs() -> Vec { skip_assert_initialized!(); unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_debug_ring_buffer_logger_get_logs()) } } #[doc(alias = "gst_debug_set_active")] pub fn debug_set_active(active: bool) { skip_assert_initialized!(); unsafe { ffi::gst_debug_set_active(active.into_glib()); } } #[doc(alias = "gst_debug_set_colored")] pub fn debug_set_colored(colored: bool) { skip_assert_initialized!(); unsafe { ffi::gst_debug_set_colored(colored.into_glib()); } } #[doc(alias = "gst_debug_set_default_threshold")] pub fn debug_set_default_threshold(level: DebugLevel) { skip_assert_initialized!(); unsafe { ffi::gst_debug_set_default_threshold(level.into_glib()); } } #[doc(alias = "gst_debug_set_threshold_for_name")] pub fn debug_set_threshold_for_name(name: &str, level: DebugLevel) { skip_assert_initialized!(); unsafe { ffi::gst_debug_set_threshold_for_name(name.to_glib_none().0, level.into_glib()); } } #[doc(alias = "gst_debug_set_threshold_from_string")] pub fn debug_set_threshold_from_string(list: &str, reset: bool) { skip_assert_initialized!(); unsafe { ffi::gst_debug_set_threshold_from_string(list.to_glib_none().0, reset.into_glib()); } } #[doc(alias = "gst_debug_unset_threshold_for_name")] pub fn debug_unset_threshold_for_name(name: &str) { skip_assert_initialized!(); unsafe { ffi::gst_debug_unset_threshold_for_name(name.to_glib_none().0); } } #[doc(alias = "gst_get_main_executable_path")] #[doc(alias = "get_main_executable_path")] pub fn main_executable_path() -> Result { assert_initialized_main_thread!(); unsafe { Option::<_>::from_glib_none(ffi::gst_get_main_executable_path()) .ok_or_else(|| glib::bool_error!("Failed to get main executable path")) } } #[doc(alias = "gst_parse_bin_from_description")] pub fn parse_bin_from_description( bin_description: &str, ghost_unlinked_pads: bool, ) -> Result { assert_initialized_main_thread!(); unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::gst_parse_bin_from_description( bin_description.to_glib_none().0, ghost_unlinked_pads.into_glib(), &mut error, ); if error.is_null() { Ok(from_glib_none(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "gst_parse_launch")] pub fn parse_launch(pipeline_description: &str) -> Result { assert_initialized_main_thread!(); unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::gst_parse_launch(pipeline_description.to_glib_none().0, &mut error); if error.is_null() { Ok(from_glib_none(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "gst_parse_launchv")] pub fn parse_launchv(argv: &[&str]) -> Result { assert_initialized_main_thread!(); unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::gst_parse_launchv(argv.to_glib_none().0, &mut error); if error.is_null() { Ok(from_glib_none(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "gst_update_registry")] pub fn update_registry() -> Result<(), glib::error::BoolError> { assert_initialized_main_thread!(); unsafe { glib::result_from_gboolean!(ffi::gst_update_registry(), "Failed to update the registry") } } #[doc(alias = "gst_util_get_timestamp")] pub fn util_get_timestamp() -> ClockTime { skip_assert_initialized!(); unsafe { try_from_glib(ffi::gst_util_get_timestamp()).expect("mandatory glib value is None") } } #[doc(alias = "gst_version")] pub fn version() -> (u32, u32, u32, u32) { skip_assert_initialized!(); unsafe { let mut major = std::mem::MaybeUninit::uninit(); let mut minor = std::mem::MaybeUninit::uninit(); let mut micro = std::mem::MaybeUninit::uninit(); let mut nano = std::mem::MaybeUninit::uninit(); ffi::gst_version( major.as_mut_ptr(), minor.as_mut_ptr(), micro.as_mut_ptr(), nano.as_mut_ptr(), ); ( major.assume_init(), minor.assume_init(), micro.assume_init(), nano.assume_init(), ) } } #[doc(alias = "gst_version_string")] pub fn version_string() -> glib::GString { skip_assert_initialized!(); unsafe { from_glib_full(ffi::gst_version_string()) } } gstreamer-0.23.5/src/auto/ghost_pad.rs000064400000000000000000000031161046102023000157620ustar 00000000000000// 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::{ffi, Object, Pad, ProxyPad}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstGhostPad")] pub struct GhostPad(Object) @extends ProxyPad, Pad, Object; match fn { type_ => || ffi::gst_ghost_pad_get_type(), } } impl GhostPad { pub const NONE: Option<&'static GhostPad> = None; } unsafe impl Send for GhostPad {} unsafe impl Sync for GhostPad {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait GhostPadExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_ghost_pad_get_target")] #[doc(alias = "get_target")] fn target(&self) -> Option { unsafe { from_glib_full(ffi::gst_ghost_pad_get_target( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_ghost_pad_set_target")] fn set_target(&self, newtarget: Option<&impl IsA>) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_ghost_pad_set_target( self.as_ref().to_glib_none().0, newtarget.map(|p| p.as_ref()).to_glib_none().0 ), "Failed to set target" ) } } } impl> GhostPadExt for O {} gstreamer-0.23.5/src/auto/mod.rs000064400000000000000000000134161046102023000145750ustar 00000000000000// This file was generated by gir (https://github.com/gtk-rs/gir) // from gir-files (https://github.com/gtk-rs/gir-files) // from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git) // DO NOT EDIT mod allocator; pub use self::allocator::Allocator; mod bin; pub use self::bin::Bin; mod buffer_pool; pub use self::buffer_pool::BufferPool; mod bus; pub use self::bus::Bus; mod child_proxy; pub use self::child_proxy::ChildProxy; mod clock; pub use self::clock::Clock; mod control_binding; pub use self::control_binding::ControlBinding; mod control_source; pub use self::control_source::ControlSource; mod device; pub use self::device::Device; mod device_monitor; pub use self::device_monitor::DeviceMonitor; mod device_provider; pub use self::device_provider::DeviceProvider; mod device_provider_factory; pub use self::device_provider_factory::DeviceProviderFactory; mod element; pub use self::element::Element; mod element_factory; pub use self::element_factory::ElementFactory; mod ghost_pad; pub use self::ghost_pad::GhostPad; mod object; pub use self::object::Object; mod pad; pub use self::pad::Pad; mod pad_template; pub use self::pad_template::PadTemplate; mod pipeline; pub use self::pipeline::Pipeline; mod plugin; pub use self::plugin::Plugin; mod plugin_feature; pub use self::plugin_feature::PluginFeature; mod preset; pub use self::preset::Preset; mod proxy_pad; pub use self::proxy_pad::ProxyPad; mod registry; pub use self::registry::Registry; mod stream; pub use self::stream::Stream; mod stream_collection; pub use self::stream_collection::StreamCollection; mod system_clock; pub use self::system_clock::SystemClock; mod tag_setter; pub use self::tag_setter::TagSetter; mod task; pub use self::task::Task; mod task_pool; pub use self::task_pool::TaskPool; mod toc_setter; pub use self::toc_setter::TocSetter; mod tracer; pub use self::tracer::Tracer; mod tracer_factory; pub use self::tracer_factory::TracerFactory; mod type_find_factory; pub use self::type_find_factory::TypeFindFactory; mod uri_handler; pub use self::uri_handler::URIHandler; mod date_time; pub use self::date_time::DateTime; mod enums; pub use self::enums::BufferingMode; pub use self::enums::BusSyncReply; pub use self::enums::CapsIntersectMode; pub use self::enums::ClockEntryType; pub use self::enums::ClockReturn; pub use self::enums::ClockType; pub use self::enums::CoreError; pub use self::enums::DebugLevel; pub use self::enums::EventType; pub use self::enums::Format; pub use self::enums::LibraryError; pub use self::enums::PadDirection; pub use self::enums::PadMode; pub use self::enums::PadPresence; pub use self::enums::PadProbeReturn; pub use self::enums::ParseError; pub use self::enums::PluginError; pub use self::enums::ProgressType; pub use self::enums::PromiseResult; pub use self::enums::QOSType; pub use self::enums::ResourceError; pub use self::enums::SeekType; pub use self::enums::State; pub use self::enums::StateChange; pub use self::enums::StateChangeReturn; pub use self::enums::StreamError; pub use self::enums::StreamStatusType; pub use self::enums::StructureChangeType; pub use self::enums::TagFlag; pub use self::enums::TagMergeMode; pub use self::enums::TagScope; pub use self::enums::TaskState; pub use self::enums::TocEntryType; pub use self::enums::TocLoopType; pub use self::enums::TocScope; pub use self::enums::TypeFindProbability; pub use self::enums::URIError; pub use self::enums::URIType; mod flags; pub use self::flags::BinFlags; pub use self::flags::BufferCopyFlags; pub use self::flags::BufferFlags; pub use self::flags::BufferPoolAcquireFlags; pub use self::flags::ClockFlags; pub use self::flags::DebugColorFlags; pub use self::flags::DebugGraphDetails; pub use self::flags::ElementFlags; pub use self::flags::EventTypeFlags; #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] pub use self::flags::GapFlags; pub use self::flags::MemoryFlags; pub use self::flags::MetaFlags; pub use self::flags::ObjectFlags; pub use self::flags::PadFlags; pub use self::flags::PadLinkCheck; pub use self::flags::PadProbeType; pub use self::flags::ParseFlags; pub use self::flags::PipelineFlags; #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] pub use self::flags::PluginAPIFlags; pub use self::flags::PluginDependencyFlags; pub use self::flags::PluginFlags; pub use self::flags::SchedulingFlags; pub use self::flags::SeekFlags; pub use self::flags::SegmentFlags; #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] pub use self::flags::SerializeFlags; pub use self::flags::StackTraceFlags; pub use self::flags::StreamFlags; pub use self::flags::StreamType; mod alias; pub use self::alias::ClockTimeDiff; pub(crate) mod functions; pub(crate) mod traits { pub use super::allocator::AllocatorExt; pub use super::bin::GstBinExt; pub use super::buffer_pool::BufferPoolExt; pub use super::child_proxy::ChildProxyExt; pub use super::clock::ClockExt; pub use super::control_binding::ControlBindingExt; pub use super::control_source::ControlSourceExt; pub use super::device::DeviceExt; pub use super::device_monitor::DeviceMonitorExt; pub use super::device_provider::DeviceProviderExt; pub use super::element::ElementExt; pub use super::ghost_pad::GhostPadExt; pub use super::object::GstObjectExt; pub use super::pad::PadExt; pub use super::pipeline::PipelineExt; pub use super::plugin_feature::PluginFeatureExt; pub use super::preset::PresetExt; pub use super::proxy_pad::ProxyPadExt; pub use super::system_clock::SystemClockExt; pub use super::tag_setter::TagSetterExt; pub use super::task::TaskExt; pub use super::task_pool::TaskPoolExt; pub use super::toc_setter::TocSetterExt; pub use super::tracer::TracerExt; pub use super::uri_handler::URIHandlerExt; } gstreamer-0.23.5/src/auto/object.rs000064400000000000000000000234041046102023000152620ustar 00000000000000// 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::{ffi, ClockTime, ControlBinding}; use glib::{ prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstObject")] pub struct Object(Object); match fn { type_ => || ffi::gst_object_get_type(), } } impl Object { pub const NONE: Option<&'static Object> = None; #[doc(alias = "gst_object_check_uniqueness")] pub fn check_uniqueness(list: &[Object], name: &str) -> bool { assert_initialized_main_thread!(); unsafe { from_glib(ffi::gst_object_check_uniqueness( list.to_glib_none().0, name.to_glib_none().0, )) } } //#[doc(alias = "gst_object_default_deep_notify")] //pub fn default_deep_notify(object: &impl IsA, orig: &impl IsA, pspec: /*Ignored*/&glib::ParamSpec, excluded_props: &[&str]) { // unsafe { TODO: call ffi:gst_object_default_deep_notify() } //} //#[doc(alias = "gst_object_replace")] //pub fn replace(oldobj: Option>, newobj: Option<&impl IsA>) -> bool { // unsafe { TODO: call ffi:gst_object_replace() } //} } impl std::fmt::Display for Object { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(&GstObjectExt::name(self)) } } unsafe impl Send for Object {} unsafe impl Sync for Object {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait GstObjectExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_object_add_control_binding")] fn add_control_binding( &self, binding: &impl IsA, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_object_add_control_binding( self.as_ref().to_glib_none().0, binding.as_ref().to_glib_none().0 ), "Failed to add control binding" ) } } #[doc(alias = "gst_object_default_error")] fn default_error(&self, error: &glib::Error, debug: Option<&str>) { unsafe { ffi::gst_object_default_error( self.as_ref().to_glib_none().0, error.to_glib_none().0, debug.to_glib_none().0, ); } } #[doc(alias = "gst_object_get_control_binding")] #[doc(alias = "get_control_binding")] fn control_binding(&self, property_name: &str) -> Option { unsafe { from_glib_full(ffi::gst_object_get_control_binding( self.as_ref().to_glib_none().0, property_name.to_glib_none().0, )) } } #[doc(alias = "gst_object_get_control_rate")] #[doc(alias = "get_control_rate")] fn control_rate(&self) -> Option { unsafe { from_glib(ffi::gst_object_get_control_rate( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_object_get_name")] #[doc(alias = "get_name")] fn name(&self) -> glib::GString { unsafe { from_glib_full(ffi::gst_object_get_name(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_object_get_parent")] #[doc(alias = "get_parent")] #[must_use] fn parent(&self) -> Option { unsafe { from_glib_full(ffi::gst_object_get_parent(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_object_get_path_string")] #[doc(alias = "get_path_string")] fn path_string(&self) -> glib::GString { unsafe { from_glib_full(ffi::gst_object_get_path_string( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_object_get_value")] #[doc(alias = "get_value")] fn value( &self, property_name: &str, timestamp: impl Into>, ) -> Option { unsafe { from_glib_full(ffi::gst_object_get_value( self.as_ref().to_glib_none().0, property_name.to_glib_none().0, timestamp.into().into_glib(), )) } } //#[doc(alias = "gst_object_get_value_array")] //#[doc(alias = "get_value_array")] //fn is_value_array(&self, property_name: &str, timestamp: impl Into>, interval: impl Into>, values: /*Unimplemented*/&[&Basic: Pointer]) -> bool { // unsafe { TODO: call ffi:gst_object_get_value_array() } //} #[doc(alias = "gst_object_has_active_control_bindings")] fn has_active_control_bindings(&self) -> bool { unsafe { from_glib(ffi::gst_object_has_active_control_bindings( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_object_has_ancestor")] fn has_ancestor(&self, ancestor: &impl IsA) -> bool { unsafe { from_glib(ffi::gst_object_has_ancestor( self.as_ref().to_glib_none().0, ancestor.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_object_has_as_ancestor")] fn has_as_ancestor(&self, ancestor: &impl IsA) -> bool { unsafe { from_glib(ffi::gst_object_has_as_ancestor( self.as_ref().to_glib_none().0, ancestor.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_object_has_as_parent")] fn has_as_parent(&self, parent: &impl IsA) -> bool { unsafe { from_glib(ffi::gst_object_has_as_parent( self.as_ref().to_glib_none().0, parent.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_object_remove_control_binding")] fn remove_control_binding(&self, binding: &impl IsA) -> bool { unsafe { from_glib(ffi::gst_object_remove_control_binding( self.as_ref().to_glib_none().0, binding.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_object_set_control_binding_disabled")] fn set_control_binding_disabled(&self, property_name: &str, disabled: bool) { unsafe { ffi::gst_object_set_control_binding_disabled( self.as_ref().to_glib_none().0, property_name.to_glib_none().0, disabled.into_glib(), ); } } #[doc(alias = "gst_object_set_control_bindings_disabled")] fn set_control_bindings_disabled(&self, disabled: bool) { unsafe { ffi::gst_object_set_control_bindings_disabled( self.as_ref().to_glib_none().0, disabled.into_glib(), ); } } #[doc(alias = "gst_object_set_control_rate")] fn set_control_rate(&self, control_rate: impl Into>) { unsafe { ffi::gst_object_set_control_rate( self.as_ref().to_glib_none().0, control_rate.into().into_glib(), ); } } #[doc(alias = "gst_object_set_parent")] #[doc(alias = "parent")] fn set_parent(&self, parent: &impl IsA) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_object_set_parent( self.as_ref().to_glib_none().0, parent.as_ref().to_glib_none().0 ), "Failed to set parent object" ) } } #[doc(alias = "gst_object_suggest_next_sync")] fn suggest_next_sync(&self) -> Option { unsafe { from_glib(ffi::gst_object_suggest_next_sync( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_object_sync_values")] fn sync_values(&self, timestamp: ClockTime) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_object_sync_values(self.as_ref().to_glib_none().0, timestamp.into_glib()), "Failed to sync values" ) } } #[doc(alias = "gst_object_unparent")] fn unparent(&self) { unsafe { ffi::gst_object_unparent(self.as_ref().to_glib_none().0); } } //#[doc(alias = "deep-notify")] //fn connect_deep_notify(&self, detail: Option<&str>, f: F) -> SignalHandlerId { // Ignored prop: GObject.ParamSpec //} #[doc(alias = "parent")] fn connect_parent_notify(&self, f: F) -> SignalHandlerId { unsafe extern "C" fn notify_parent_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstObject, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Object::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::parent\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_parent_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> GstObjectExt for O {} gstreamer-0.23.5/src/auto/pad.rs000064400000000000000000000465011046102023000145630ustar 00000000000000// 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::{ ffi, Buffer, BufferList, Caps, Element, Event, FlowError, FlowSuccess, Object, PadDirection, PadLinkCheck, PadLinkError, PadLinkSuccess, PadMode, PadTemplate, Stream, TaskState, }; use glib::{ object::ObjectType as _, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstPad")] pub struct Pad(Object) @extends Object; match fn { type_ => || ffi::gst_pad_get_type(), } } impl Pad { pub const NONE: Option<&'static Pad> = None; } unsafe impl Send for Pad {} unsafe impl Sync for Pad {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait PadExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_pad_activate_mode")] fn activate_mode(&self, mode: PadMode, active: bool) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_pad_activate_mode( self.as_ref().to_glib_none().0, mode.into_glib(), active.into_glib() ), "Failed to activate mode pad" ) } } #[doc(alias = "gst_pad_can_link")] fn can_link(&self, sinkpad: &impl IsA) -> bool { unsafe { from_glib(ffi::gst_pad_can_link( self.as_ref().to_glib_none().0, sinkpad.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_chain")] fn chain(&self, buffer: Buffer) -> Result { unsafe { try_from_glib(ffi::gst_pad_chain( self.as_ref().to_glib_none().0, buffer.into_glib_ptr(), )) } } #[doc(alias = "gst_pad_chain_list")] fn chain_list(&self, list: BufferList) -> Result { unsafe { try_from_glib(ffi::gst_pad_chain_list( self.as_ref().to_glib_none().0, list.into_glib_ptr(), )) } } #[doc(alias = "gst_pad_check_reconfigure")] fn check_reconfigure(&self) -> bool { unsafe { from_glib(ffi::gst_pad_check_reconfigure( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_create_stream_id")] fn create_stream_id( &self, parent: &impl IsA, stream_id: Option<&str>, ) -> glib::GString { unsafe { from_glib_full(ffi::gst_pad_create_stream_id( self.as_ref().to_glib_none().0, parent.as_ref().to_glib_none().0, stream_id.to_glib_none().0, )) } } //#[doc(alias = "gst_pad_create_stream_id_printf")] //fn create_stream_id_printf(&self, parent: &impl IsA, stream_id: Option<&str>, : /*Unknown conversion*//*Unimplemented*/Basic: VarArgs) -> glib::GString { // unsafe { TODO: call ffi:gst_pad_create_stream_id_printf() } //} //#[doc(alias = "gst_pad_create_stream_id_printf_valist")] //fn create_stream_id_printf_valist(&self, parent: &impl IsA, stream_id: Option<&str>, var_args: /*Unknown conversion*//*Unimplemented*/Unsupported) -> glib::GString { // unsafe { TODO: call ffi:gst_pad_create_stream_id_printf_valist() } //} #[doc(alias = "gst_pad_forward")] fn forward bool>(&self, forward: P) -> bool { let mut forward_data: P = forward; unsafe extern "C" fn forward_func bool>( pad: *mut ffi::GstPad, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let pad = from_glib_borrow(pad); let callback = user_data as *mut P; (*callback)(&pad).into_glib() } let forward = Some(forward_func::

as _); let super_callback0: &mut P = &mut forward_data; unsafe { from_glib(ffi::gst_pad_forward( self.as_ref().to_glib_none().0, forward, super_callback0 as *mut _ as *mut _, )) } } #[doc(alias = "gst_pad_get_allowed_caps")] #[doc(alias = "get_allowed_caps")] fn allowed_caps(&self) -> Option { unsafe { from_glib_full(ffi::gst_pad_get_allowed_caps( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_get_current_caps")] #[doc(alias = "get_current_caps")] fn current_caps(&self) -> Option { unsafe { from_glib_full(ffi::gst_pad_get_current_caps( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_get_direction")] #[doc(alias = "get_direction")] fn direction(&self) -> PadDirection { unsafe { from_glib(ffi::gst_pad_get_direction(self.as_ref().to_glib_none().0)) } } //#[doc(alias = "gst_pad_get_element_private")] //#[doc(alias = "get_element_private")] //fn element_private(&self) -> /*Unimplemented*/Option { // unsafe { TODO: call ffi:gst_pad_get_element_private() } //} #[doc(alias = "gst_pad_get_last_flow_return")] #[doc(alias = "get_last_flow_return")] fn last_flow_result(&self) -> Result { unsafe { try_from_glib(ffi::gst_pad_get_last_flow_return( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_get_offset")] #[doc(alias = "get_offset")] fn offset(&self) -> i64 { unsafe { ffi::gst_pad_get_offset(self.as_ref().to_glib_none().0) } } #[doc(alias = "gst_pad_get_pad_template")] #[doc(alias = "get_pad_template")] fn pad_template(&self) -> Option { unsafe { from_glib_full(ffi::gst_pad_get_pad_template( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_get_pad_template_caps")] #[doc(alias = "get_pad_template_caps")] fn pad_template_caps(&self) -> Caps { unsafe { from_glib_full(ffi::gst_pad_get_pad_template_caps( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_get_parent_element")] #[doc(alias = "get_parent_element")] fn parent_element(&self) -> Option { unsafe { from_glib_full(ffi::gst_pad_get_parent_element( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_get_peer")] #[doc(alias = "get_peer")] #[must_use] fn peer(&self) -> Option { unsafe { from_glib_full(ffi::gst_pad_get_peer(self.as_ref().to_glib_none().0)) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "gst_pad_get_single_internal_link")] #[doc(alias = "get_single_internal_link")] #[must_use] fn single_internal_link(&self) -> Option { unsafe { from_glib_full(ffi::gst_pad_get_single_internal_link( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_get_stream")] #[doc(alias = "get_stream")] fn stream(&self) -> Option { unsafe { from_glib_full(ffi::gst_pad_get_stream(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_pad_get_stream_id")] #[doc(alias = "get_stream_id")] fn stream_id(&self) -> Option { unsafe { from_glib_full(ffi::gst_pad_get_stream_id(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_pad_get_task_state")] #[doc(alias = "get_task_state")] fn task_state(&self) -> TaskState { unsafe { from_glib(ffi::gst_pad_get_task_state(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_pad_has_current_caps")] fn has_current_caps(&self) -> bool { unsafe { from_glib(ffi::gst_pad_has_current_caps( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_is_active")] fn is_active(&self) -> bool { unsafe { from_glib(ffi::gst_pad_is_active(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_pad_is_blocked")] fn is_blocked(&self) -> bool { unsafe { from_glib(ffi::gst_pad_is_blocked(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_pad_is_blocking")] fn is_blocking(&self) -> bool { unsafe { from_glib(ffi::gst_pad_is_blocking(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_pad_is_linked")] fn is_linked(&self) -> bool { unsafe { from_glib(ffi::gst_pad_is_linked(self.as_ref().to_glib_none().0)) } } //#[doc(alias = "gst_pad_iterate_internal_links")] //fn iterate_internal_links(&self) -> /*Ignored*/Option { // unsafe { TODO: call ffi:gst_pad_iterate_internal_links() } //} //#[doc(alias = "gst_pad_iterate_internal_links_default")] //fn iterate_internal_links_default(&self, parent: Option<&impl IsA>) -> /*Ignored*/Option { // unsafe { TODO: call ffi:gst_pad_iterate_internal_links_default() } //} #[doc(alias = "gst_pad_link")] fn link(&self, sinkpad: &impl IsA) -> Result { unsafe { try_from_glib(ffi::gst_pad_link( self.as_ref().to_glib_none().0, sinkpad.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_link_full")] fn link_full( &self, sinkpad: &impl IsA, flags: PadLinkCheck, ) -> Result { unsafe { try_from_glib(ffi::gst_pad_link_full( self.as_ref().to_glib_none().0, sinkpad.as_ref().to_glib_none().0, flags.into_glib(), )) } } #[doc(alias = "gst_pad_link_maybe_ghosting")] fn link_maybe_ghosting(&self, sink: &impl IsA) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_pad_link_maybe_ghosting( self.as_ref().to_glib_none().0, sink.as_ref().to_glib_none().0 ), "Failed to link pads, possibly ghosting" ) } } #[doc(alias = "gst_pad_link_maybe_ghosting_full")] fn link_maybe_ghosting_full( &self, sink: &impl IsA, flags: PadLinkCheck, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_pad_link_maybe_ghosting_full( self.as_ref().to_glib_none().0, sink.as_ref().to_glib_none().0, flags.into_glib() ), "Failed to link pads, possibly ghosting" ) } } #[doc(alias = "gst_pad_mark_reconfigure")] fn mark_reconfigure(&self) { unsafe { ffi::gst_pad_mark_reconfigure(self.as_ref().to_glib_none().0); } } #[doc(alias = "gst_pad_needs_reconfigure")] fn needs_reconfigure(&self) -> bool { unsafe { from_glib(ffi::gst_pad_needs_reconfigure( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pad_pause_task")] fn pause_task(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_pad_pause_task(self.as_ref().to_glib_none().0), "Failed to pause pad task" ) } } #[doc(alias = "gst_pad_peer_query_accept_caps")] fn peer_query_accept_caps(&self, caps: &Caps) -> bool { unsafe { from_glib(ffi::gst_pad_peer_query_accept_caps( self.as_ref().to_glib_none().0, caps.to_glib_none().0, )) } } #[doc(alias = "gst_pad_peer_query_caps")] fn peer_query_caps(&self, filter: Option<&Caps>) -> Caps { unsafe { from_glib_full(ffi::gst_pad_peer_query_caps( self.as_ref().to_glib_none().0, filter.to_glib_none().0, )) } } #[doc(alias = "gst_pad_push")] fn push(&self, buffer: Buffer) -> Result { unsafe { try_from_glib(ffi::gst_pad_push( self.as_ref().to_glib_none().0, buffer.into_glib_ptr(), )) } } #[doc(alias = "gst_pad_push_list")] fn push_list(&self, list: BufferList) -> Result { unsafe { try_from_glib(ffi::gst_pad_push_list( self.as_ref().to_glib_none().0, list.into_glib_ptr(), )) } } #[doc(alias = "gst_pad_query_accept_caps")] fn query_accept_caps(&self, caps: &Caps) -> bool { unsafe { from_glib(ffi::gst_pad_query_accept_caps( self.as_ref().to_glib_none().0, caps.to_glib_none().0, )) } } #[doc(alias = "gst_pad_query_caps")] fn query_caps(&self, filter: Option<&Caps>) -> Caps { unsafe { from_glib_full(ffi::gst_pad_query_caps( self.as_ref().to_glib_none().0, filter.to_glib_none().0, )) } } #[doc(alias = "gst_pad_set_active")] fn set_active(&self, active: bool) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_pad_set_active(self.as_ref().to_glib_none().0, active.into_glib()), "Failed to activate pad" ) } } //#[doc(alias = "gst_pad_set_element_private")] //fn set_element_private(&self, priv_: /*Unimplemented*/Option) { // unsafe { TODO: call ffi:gst_pad_set_element_private() } //} #[doc(alias = "gst_pad_set_offset")] #[doc(alias = "offset")] fn set_offset(&self, offset: i64) { unsafe { ffi::gst_pad_set_offset(self.as_ref().to_glib_none().0, offset); } } #[doc(alias = "gst_pad_stop_task")] fn stop_task(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_pad_stop_task(self.as_ref().to_glib_none().0), "Failed to stop pad task" ) } } #[doc(alias = "gst_pad_store_sticky_event")] fn store_sticky_event(&self, event: &Event) -> Result { unsafe { try_from_glib(ffi::gst_pad_store_sticky_event( self.as_ref().to_glib_none().0, event.to_glib_none().0, )) } } #[doc(alias = "gst_pad_unlink")] fn unlink(&self, sinkpad: &impl IsA) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_pad_unlink( self.as_ref().to_glib_none().0, sinkpad.as_ref().to_glib_none().0 ), "Failed to unlink pad" ) } } #[doc(alias = "gst_pad_use_fixed_caps")] fn use_fixed_caps(&self) { unsafe { ffi::gst_pad_use_fixed_caps(self.as_ref().to_glib_none().0); } } #[doc(alias = "linked")] fn connect_linked(&self, f: F) -> SignalHandlerId { unsafe extern "C" fn linked_trampoline< P: IsA, F: Fn(&P, &Pad) + Send + Sync + 'static, >( this: *mut ffi::GstPad, peer: *mut ffi::GstPad, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( Pad::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(peer), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"linked\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( linked_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "unlinked")] fn connect_unlinked( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn unlinked_trampoline< P: IsA, F: Fn(&P, &Pad) + Send + Sync + 'static, >( this: *mut ffi::GstPad, peer: *mut ffi::GstPad, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f( Pad::from_glib_borrow(this).unsafe_cast_ref(), &from_glib_borrow(peer), ) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"unlinked\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( unlinked_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "caps")] fn connect_caps_notify(&self, f: F) -> SignalHandlerId { unsafe extern "C" fn notify_caps_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstPad, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Pad::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::caps\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_caps_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "offset")] fn connect_offset_notify(&self, f: F) -> SignalHandlerId { unsafe extern "C" fn notify_offset_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstPad, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Pad::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::offset\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_offset_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> PadExt for O {} gstreamer-0.23.5/src/auto/pad_template.rs000064400000000000000000000064031046102023000164530ustar 00000000000000// 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::{ffi, Caps, Object, Pad, PadDirection, PadPresence}; use glib::{ object::ObjectType as _, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstPadTemplate")] pub struct PadTemplate(Object) @extends Object; match fn { type_ => || ffi::gst_pad_template_get_type(), } } impl PadTemplate { #[doc(alias = "gst_pad_template_new")] pub fn new( name_template: &str, direction: PadDirection, presence: PadPresence, caps: &Caps, ) -> Result { assert_initialized_main_thread!(); unsafe { Option::<_>::from_glib_none(ffi::gst_pad_template_new( name_template.to_glib_none().0, direction.into_glib(), presence.into_glib(), caps.to_glib_none().0, )) .ok_or_else(|| glib::bool_error!("Failed to create pad template")) } } #[doc(alias = "gst_pad_template_new_with_gtype")] #[doc(alias = "new_with_gtype")] pub fn with_gtype( name_template: &str, direction: PadDirection, presence: PadPresence, caps: &Caps, pad_type: glib::types::Type, ) -> Result { assert_initialized_main_thread!(); unsafe { Option::<_>::from_glib_none(ffi::gst_pad_template_new_with_gtype( name_template.to_glib_none().0, direction.into_glib(), presence.into_glib(), caps.to_glib_none().0, pad_type.into_glib(), )) .ok_or_else(|| glib::bool_error!("Failed to create pad template")) } } #[doc(alias = "gst_pad_template_pad_created")] pub fn pad_created(&self, pad: &impl IsA) { unsafe { ffi::gst_pad_template_pad_created(self.to_glib_none().0, pad.as_ref().to_glib_none().0); } } #[doc(alias = "pad-created")] pub fn connect_pad_created( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn pad_created_trampoline< F: Fn(&PadTemplate, &Pad) + Send + Sync + 'static, >( this: *mut ffi::GstPadTemplate, pad: *mut ffi::GstPad, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this), &from_glib_borrow(pad)) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"pad-created\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( pad_created_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } unsafe impl Send for PadTemplate {} unsafe impl Sync for PadTemplate {} gstreamer-0.23.5/src/auto/pipeline.rs000064400000000000000000000160061046102023000156210ustar 00000000000000// 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::{ffi, Bin, ChildProxy, Clock, ClockTime, Element, Object}; use glib::{ prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstPipeline")] pub struct Pipeline(Object) @extends Bin, Element, Object, @implements ChildProxy; match fn { type_ => || ffi::gst_pipeline_get_type(), } } impl Pipeline { pub const NONE: Option<&'static Pipeline> = None; } unsafe impl Send for Pipeline {} unsafe impl Sync for Pipeline {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait PipelineExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_pipeline_auto_clock")] fn auto_clock(&self) { unsafe { ffi::gst_pipeline_auto_clock(self.as_ref().to_glib_none().0); } } #[doc(alias = "gst_pipeline_get_auto_flush_bus")] #[doc(alias = "get_auto_flush_bus")] #[doc(alias = "auto-flush-bus")] fn is_auto_flush_bus(&self) -> bool { unsafe { from_glib(ffi::gst_pipeline_get_auto_flush_bus( self.as_ref().to_glib_none().0, )) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_pipeline_get_configured_latency")] #[doc(alias = "get_configured_latency")] fn configured_latency(&self) -> Option { unsafe { from_glib(ffi::gst_pipeline_get_configured_latency( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pipeline_get_delay")] #[doc(alias = "get_delay")] fn delay(&self) -> ClockTime { unsafe { try_from_glib(ffi::gst_pipeline_get_delay(self.as_ref().to_glib_none().0)) .expect("mandatory glib value is None") } } #[doc(alias = "gst_pipeline_get_latency")] #[doc(alias = "get_latency")] fn latency(&self) -> Option { unsafe { from_glib(ffi::gst_pipeline_get_latency( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_pipeline_get_pipeline_clock")] #[doc(alias = "get_pipeline_clock")] fn pipeline_clock(&self) -> Clock { unsafe { from_glib_full(ffi::gst_pipeline_get_pipeline_clock( self.as_ref().to_glib_none().0, )) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_pipeline_is_live")] fn is_live(&self) -> bool { unsafe { from_glib(ffi::gst_pipeline_is_live(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_pipeline_set_auto_flush_bus")] #[doc(alias = "auto-flush-bus")] fn set_auto_flush_bus(&self, auto_flush: bool) { unsafe { ffi::gst_pipeline_set_auto_flush_bus( self.as_ref().to_glib_none().0, auto_flush.into_glib(), ); } } #[doc(alias = "gst_pipeline_set_delay")] #[doc(alias = "delay")] fn set_delay(&self, delay: ClockTime) { unsafe { ffi::gst_pipeline_set_delay(self.as_ref().to_glib_none().0, delay.into_glib()); } } #[doc(alias = "gst_pipeline_set_latency")] #[doc(alias = "latency")] fn set_latency(&self, latency: impl Into>) { unsafe { ffi::gst_pipeline_set_latency( self.as_ref().to_glib_none().0, latency.into().into_glib(), ); } } #[doc(alias = "gst_pipeline_use_clock")] fn use_clock(&self, clock: Option<&impl IsA>) { unsafe { ffi::gst_pipeline_use_clock( self.as_ref().to_glib_none().0, clock.map(|p| p.as_ref()).to_glib_none().0, ); } } #[doc(alias = "auto-flush-bus")] fn connect_auto_flush_bus_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_auto_flush_bus_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstPipeline, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Pipeline::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::auto-flush-bus\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_auto_flush_bus_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "delay")] fn connect_delay_notify(&self, f: F) -> SignalHandlerId { unsafe extern "C" fn notify_delay_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstPipeline, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Pipeline::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::delay\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_delay_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "latency")] fn connect_latency_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_latency_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstPipeline, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Pipeline::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::latency\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_latency_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> PipelineExt for O {} gstreamer-0.23.5/src/auto/plugin.rs000064400000000000000000000166601046102023000153200ustar 00000000000000// 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::{ffi, Object, PluginDependencyFlags, Structure}; use glib::translate::*; glib::wrapper! { #[doc(alias = "GstPlugin")] pub struct Plugin(Object) @extends Object; match fn { type_ => || ffi::gst_plugin_get_type(), } } impl Plugin { #[doc(alias = "gst_plugin_add_dependency")] pub fn add_dependency( &self, env_vars: &[&str], paths: &[&str], names: &[&str], flags: PluginDependencyFlags, ) { unsafe { ffi::gst_plugin_add_dependency( self.to_glib_none().0, env_vars.to_glib_none().0, paths.to_glib_none().0, names.to_glib_none().0, flags.into_glib(), ); } } #[doc(alias = "gst_plugin_add_dependency_simple")] pub fn add_dependency_simple( &self, env_vars: Option<&str>, paths: Option<&str>, names: Option<&str>, flags: PluginDependencyFlags, ) { unsafe { ffi::gst_plugin_add_dependency_simple( self.to_glib_none().0, env_vars.to_glib_none().0, paths.to_glib_none().0, names.to_glib_none().0, flags.into_glib(), ); } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_plugin_add_status_error")] pub fn add_status_error(&self, message: &str) { unsafe { ffi::gst_plugin_add_status_error(self.to_glib_none().0, message.to_glib_none().0); } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_plugin_add_status_info")] pub fn add_status_info(&self, message: &str) { unsafe { ffi::gst_plugin_add_status_info(self.to_glib_none().0, message.to_glib_none().0); } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_plugin_add_status_warning")] pub fn add_status_warning(&self, message: &str) { unsafe { ffi::gst_plugin_add_status_warning(self.to_glib_none().0, message.to_glib_none().0); } } #[doc(alias = "gst_plugin_get_description")] #[doc(alias = "get_description")] pub fn description(&self) -> glib::GString { unsafe { from_glib_none(ffi::gst_plugin_get_description(self.to_glib_none().0)) } } #[doc(alias = "gst_plugin_get_filename")] #[doc(alias = "get_filename")] pub fn filename(&self) -> Option { unsafe { from_glib_none(ffi::gst_plugin_get_filename(self.to_glib_none().0)) } } #[doc(alias = "gst_plugin_get_license")] #[doc(alias = "get_license")] pub fn license(&self) -> glib::GString { unsafe { from_glib_none(ffi::gst_plugin_get_license(self.to_glib_none().0)) } } #[doc(alias = "gst_plugin_get_name")] #[doc(alias = "get_name")] pub fn plugin_name(&self) -> glib::GString { unsafe { from_glib_none(ffi::gst_plugin_get_name(self.to_glib_none().0)) } } #[doc(alias = "gst_plugin_get_origin")] #[doc(alias = "get_origin")] pub fn origin(&self) -> glib::GString { unsafe { from_glib_none(ffi::gst_plugin_get_origin(self.to_glib_none().0)) } } #[doc(alias = "gst_plugin_get_package")] #[doc(alias = "get_package")] pub fn package(&self) -> glib::GString { unsafe { from_glib_none(ffi::gst_plugin_get_package(self.to_glib_none().0)) } } #[doc(alias = "gst_plugin_get_release_date_string")] #[doc(alias = "get_release_date_string")] pub fn release_date_string(&self) -> Option { unsafe { from_glib_none(ffi::gst_plugin_get_release_date_string( self.to_glib_none().0, )) } } #[doc(alias = "gst_plugin_get_source")] #[doc(alias = "get_source")] pub fn source(&self) -> glib::GString { unsafe { from_glib_none(ffi::gst_plugin_get_source(self.to_glib_none().0)) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_plugin_get_status_errors")] #[doc(alias = "get_status_errors")] pub fn status_errors(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_plugin_get_status_errors( self.to_glib_none().0, )) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_plugin_get_status_infos")] #[doc(alias = "get_status_infos")] pub fn status_infos(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_plugin_get_status_infos( self.to_glib_none().0, )) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_plugin_get_status_warnings")] #[doc(alias = "get_status_warnings")] pub fn status_warnings(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_plugin_get_status_warnings( self.to_glib_none().0, )) } } #[doc(alias = "gst_plugin_get_version")] #[doc(alias = "get_version")] pub fn version(&self) -> glib::GString { unsafe { from_glib_none(ffi::gst_plugin_get_version(self.to_glib_none().0)) } } #[doc(alias = "gst_plugin_is_loaded")] pub fn is_loaded(&self) -> bool { unsafe { from_glib(ffi::gst_plugin_is_loaded(self.to_glib_none().0)) } } #[doc(alias = "gst_plugin_load")] pub fn load(&self) -> Result { unsafe { Option::<_>::from_glib_full(ffi::gst_plugin_load(self.to_glib_none().0)) .ok_or_else(|| glib::bool_error!("Failed to load plugin")) } } #[doc(alias = "gst_plugin_set_cache_data")] pub fn set_cache_data(&self, cache_data: Structure) { unsafe { ffi::gst_plugin_set_cache_data(self.to_glib_none().0, cache_data.into_glib_ptr()); } } #[doc(alias = "gst_plugin_load_by_name")] pub fn load_by_name(name: &str) -> Result { assert_initialized_main_thread!(); unsafe { Option::<_>::from_glib_full(ffi::gst_plugin_load_by_name(name.to_glib_none().0)) .ok_or_else(|| glib::bool_error!("Failed to load plugin")) } } #[doc(alias = "gst_plugin_load_file")] pub fn load_file(filename: impl AsRef) -> Result { assert_initialized_main_thread!(); unsafe { let mut error = std::ptr::null_mut(); let ret = ffi::gst_plugin_load_file(filename.as_ref().to_glib_none().0, &mut error); if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) } } } } impl std::fmt::Display for Plugin { #[inline] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.write_str(&self.plugin_name()) } } unsafe impl Send for Plugin {} unsafe impl Sync for Plugin {} gstreamer-0.23.5/src/auto/plugin_feature.rs000064400000000000000000000035641046102023000170320ustar 00000000000000// 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::{ffi, Object, Plugin}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstPluginFeature")] pub struct PluginFeature(Object) @extends Object; match fn { type_ => || ffi::gst_plugin_feature_get_type(), } } impl PluginFeature { pub const NONE: Option<&'static PluginFeature> = None; } unsafe impl Send for PluginFeature {} unsafe impl Sync for PluginFeature {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait PluginFeatureExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_plugin_feature_check_version")] fn check_version(&self, min_major: u32, min_minor: u32, min_micro: u32) -> bool { unsafe { from_glib(ffi::gst_plugin_feature_check_version( self.as_ref().to_glib_none().0, min_major, min_minor, min_micro, )) } } #[doc(alias = "gst_plugin_feature_get_plugin")] #[doc(alias = "get_plugin")] fn plugin(&self) -> Option { unsafe { from_glib_full(ffi::gst_plugin_feature_get_plugin( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_plugin_feature_get_plugin_name")] #[doc(alias = "get_plugin_name")] fn plugin_name(&self) -> Option { unsafe { from_glib_none(ffi::gst_plugin_feature_get_plugin_name( self.as_ref().to_glib_none().0, )) } } } impl> PluginFeatureExt for O {} gstreamer-0.23.5/src/auto/preset.rs000064400000000000000000000116521046102023000153200ustar 00000000000000// 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::ffi; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstPreset")] pub struct Preset(Interface); match fn { type_ => || ffi::gst_preset_get_type(), } } impl Preset { pub const NONE: Option<&'static Preset> = None; #[doc(alias = "gst_preset_get_app_dir")] #[doc(alias = "get_app_dir")] pub fn app_dir() -> Option { assert_initialized_main_thread!(); unsafe { from_glib_none(ffi::gst_preset_get_app_dir()) } } #[doc(alias = "gst_preset_set_app_dir")] pub fn set_app_dir(app_dir: impl AsRef) -> Result<(), glib::error::BoolError> { assert_initialized_main_thread!(); unsafe { glib::result_from_gboolean!( ffi::gst_preset_set_app_dir(app_dir.as_ref().to_glib_none().0), "Failed to set app preset directory" ) } } } unsafe impl Send for Preset {} unsafe impl Sync for Preset {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait PresetExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_preset_delete_preset")] fn delete_preset(&self, name: &str) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_preset_delete_preset( self.as_ref().to_glib_none().0, name.to_glib_none().0 ), "Failed to delete preset" ) } } #[doc(alias = "gst_preset_get_meta")] #[doc(alias = "get_meta")] fn meta(&self, name: &str, tag: &str) -> Option { unsafe { let mut value = std::ptr::null_mut(); let ret = from_glib(ffi::gst_preset_get_meta( self.as_ref().to_glib_none().0, name.to_glib_none().0, tag.to_glib_none().0, &mut value, )); if ret { Some(from_glib_full(value)) } else { None } } } #[doc(alias = "gst_preset_get_preset_names")] #[doc(alias = "get_preset_names")] fn preset_names(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_preset_get_preset_names( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_preset_get_property_names")] #[doc(alias = "get_property_names")] fn property_names(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_preset_get_property_names( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_preset_is_editable")] fn is_editable(&self) -> bool { unsafe { from_glib(ffi::gst_preset_is_editable(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_preset_load_preset")] fn load_preset(&self, name: &str) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_preset_load_preset(self.as_ref().to_glib_none().0, name.to_glib_none().0), "Failed to load preset" ) } } #[doc(alias = "gst_preset_rename_preset")] fn rename_preset(&self, old_name: &str, new_name: &str) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_preset_rename_preset( self.as_ref().to_glib_none().0, old_name.to_glib_none().0, new_name.to_glib_none().0 ), "Failed to rename preset" ) } } #[doc(alias = "gst_preset_save_preset")] fn save_preset(&self, name: &str) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_preset_save_preset(self.as_ref().to_glib_none().0, name.to_glib_none().0), "Failed to save preset" ) } } #[doc(alias = "gst_preset_set_meta")] fn set_meta( &self, name: &str, tag: &str, value: Option<&str>, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_preset_set_meta( self.as_ref().to_glib_none().0, name.to_glib_none().0, tag.to_glib_none().0, value.to_glib_none().0 ), "Failed to set preset meta" ) } } } impl> PresetExt for O {} gstreamer-0.23.5/src/auto/proxy_pad.rs000064400000000000000000000026611046102023000160230ustar 00000000000000// 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::{ffi, Object, Pad}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstProxyPad")] pub struct ProxyPad(Object) @extends Pad, Object; match fn { type_ => || ffi::gst_proxy_pad_get_type(), } } impl ProxyPad { pub const NONE: Option<&'static ProxyPad> = None; //#[doc(alias = "gst_proxy_pad_iterate_internal_links_default")] //pub fn iterate_internal_links_default(pad: &impl IsA, parent: Option<&impl IsA>) -> /*Ignored*/Option { // unsafe { TODO: call ffi:gst_proxy_pad_iterate_internal_links_default() } //} } unsafe impl Send for ProxyPad {} unsafe impl Sync for ProxyPad {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait ProxyPadExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_proxy_pad_get_internal")] #[doc(alias = "get_internal")] #[must_use] fn internal(&self) -> Option { unsafe { from_glib_full(ffi::gst_proxy_pad_get_internal( self.as_ref().to_glib_none().0, )) } } } impl> ProxyPadExt for O {} gstreamer-0.23.5/src/auto/registry.rs000064400000000000000000000145461046102023000156730ustar 00000000000000// 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::{ffi, Object, Plugin, PluginFeature}; use glib::{ object::ObjectType as _, prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstRegistry")] pub struct Registry(Object) @extends Object; match fn { type_ => || ffi::gst_registry_get_type(), } } impl Registry { #[doc(alias = "gst_registry_add_feature")] pub fn add_feature( &self, feature: &impl IsA, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_registry_add_feature( self.to_glib_none().0, feature.as_ref().to_glib_none().0 ), "Failed to add feature" ) } } #[doc(alias = "gst_registry_add_plugin")] pub fn add_plugin(&self, plugin: &Plugin) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_registry_add_plugin(self.to_glib_none().0, plugin.to_glib_none().0), "Failed to add plugin" ) } } #[doc(alias = "gst_registry_check_feature_version")] pub fn check_feature_version( &self, feature_name: &str, min_major: u32, min_minor: u32, min_micro: u32, ) -> bool { unsafe { from_glib(ffi::gst_registry_check_feature_version( self.to_glib_none().0, feature_name.to_glib_none().0, min_major, min_minor, min_micro, )) } } #[doc(alias = "gst_registry_find_feature")] pub fn find_feature(&self, name: &str, type_: glib::types::Type) -> Option { unsafe { from_glib_full(ffi::gst_registry_find_feature( self.to_glib_none().0, name.to_glib_none().0, type_.into_glib(), )) } } #[doc(alias = "gst_registry_find_plugin")] pub fn find_plugin(&self, name: &str) -> Option { unsafe { from_glib_full(ffi::gst_registry_find_plugin( self.to_glib_none().0, name.to_glib_none().0, )) } } #[doc(alias = "gst_registry_get_feature_list_cookie")] #[doc(alias = "get_feature_list_cookie")] pub fn feature_list_cookie(&self) -> u32 { unsafe { ffi::gst_registry_get_feature_list_cookie(self.to_glib_none().0) } } #[doc(alias = "gst_registry_lookup")] pub fn lookup(&self, filename: &str) -> Option { unsafe { from_glib_full(ffi::gst_registry_lookup( self.to_glib_none().0, filename.to_glib_none().0, )) } } #[doc(alias = "gst_registry_lookup_feature")] pub fn lookup_feature(&self, name: &str) -> Option { unsafe { from_glib_full(ffi::gst_registry_lookup_feature( self.to_glib_none().0, name.to_glib_none().0, )) } } #[doc(alias = "gst_registry_remove_feature")] pub fn remove_feature(&self, feature: &impl IsA) { unsafe { ffi::gst_registry_remove_feature( self.to_glib_none().0, feature.as_ref().to_glib_none().0, ); } } #[doc(alias = "gst_registry_remove_plugin")] pub fn remove_plugin(&self, plugin: &Plugin) { unsafe { ffi::gst_registry_remove_plugin(self.to_glib_none().0, plugin.to_glib_none().0); } } #[doc(alias = "gst_registry_scan_path")] pub fn scan_path(&self, path: impl AsRef) -> bool { unsafe { from_glib(ffi::gst_registry_scan_path( self.to_glib_none().0, path.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_registry_get")] pub fn get() -> Registry { assert_initialized_main_thread!(); unsafe { from_glib_none(ffi::gst_registry_get()) } } #[doc(alias = "feature-added")] pub fn connect_feature_added( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn feature_added_trampoline< F: Fn(&Registry, &PluginFeature) + Send + Sync + 'static, >( this: *mut ffi::GstRegistry, feature: *mut ffi::GstPluginFeature, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this), &from_glib_borrow(feature)) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"feature-added\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( feature_added_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "plugin-added")] pub fn connect_plugin_added( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn plugin_added_trampoline< F: Fn(&Registry, &Plugin) + Send + Sync + 'static, >( this: *mut ffi::GstRegistry, plugin: *mut ffi::GstPlugin, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this), &from_glib_borrow(plugin)) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"plugin-added\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( plugin_added_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } unsafe impl Send for Registry {} unsafe impl Sync for Registry {} gstreamer-0.23.5/src/auto/stream.rs000064400000000000000000000155631046102023000153160ustar 00000000000000// 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::{ffi, Caps, Object, StreamFlags, StreamType, TagList}; use glib::{ prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstStream")] pub struct Stream(Object) @extends Object; match fn { type_ => || ffi::gst_stream_get_type(), } } impl Stream { #[doc(alias = "gst_stream_new")] pub fn new( stream_id: Option<&str>, caps: Option<&Caps>, type_: StreamType, flags: StreamFlags, ) -> Stream { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_stream_new( stream_id.to_glib_none().0, caps.to_glib_none().0, type_.into_glib(), flags.into_glib(), )) } } #[doc(alias = "gst_stream_get_caps")] #[doc(alias = "get_caps")] pub fn caps(&self) -> Option { unsafe { from_glib_full(ffi::gst_stream_get_caps(self.to_glib_none().0)) } } #[doc(alias = "gst_stream_get_stream_flags")] #[doc(alias = "get_stream_flags")] #[doc(alias = "stream-flags")] pub fn stream_flags(&self) -> StreamFlags { unsafe { from_glib(ffi::gst_stream_get_stream_flags(self.to_glib_none().0)) } } #[doc(alias = "gst_stream_get_stream_id")] #[doc(alias = "get_stream_id")] #[doc(alias = "stream-id")] pub fn stream_id(&self) -> Option { unsafe { from_glib_none(ffi::gst_stream_get_stream_id(self.to_glib_none().0)) } } #[doc(alias = "gst_stream_get_stream_type")] #[doc(alias = "get_stream_type")] #[doc(alias = "stream-type")] pub fn stream_type(&self) -> StreamType { unsafe { from_glib(ffi::gst_stream_get_stream_type(self.to_glib_none().0)) } } #[doc(alias = "gst_stream_get_tags")] #[doc(alias = "get_tags")] pub fn tags(&self) -> Option { unsafe { from_glib_full(ffi::gst_stream_get_tags(self.to_glib_none().0)) } } #[doc(alias = "gst_stream_set_caps")] #[doc(alias = "caps")] pub fn set_caps(&self, caps: Option<&Caps>) { unsafe { ffi::gst_stream_set_caps(self.to_glib_none().0, caps.to_glib_none().0); } } #[doc(alias = "gst_stream_set_stream_flags")] #[doc(alias = "stream-flags")] pub fn set_stream_flags(&self, flags: StreamFlags) { unsafe { ffi::gst_stream_set_stream_flags(self.to_glib_none().0, flags.into_glib()); } } #[doc(alias = "gst_stream_set_stream_type")] #[doc(alias = "stream-type")] pub fn set_stream_type(&self, stream_type: StreamType) { unsafe { ffi::gst_stream_set_stream_type(self.to_glib_none().0, stream_type.into_glib()); } } #[doc(alias = "gst_stream_set_tags")] #[doc(alias = "tags")] pub fn set_tags(&self, tags: Option<&TagList>) { unsafe { ffi::gst_stream_set_tags(self.to_glib_none().0, tags.to_glib_none().0); } } #[doc(alias = "caps")] pub fn connect_caps_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_caps_trampoline( this: *mut ffi::GstStream, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this)) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::caps\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_caps_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "stream-flags")] pub fn connect_stream_flags_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_stream_flags_trampoline< F: Fn(&Stream) + Send + Sync + 'static, >( this: *mut ffi::GstStream, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this)) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::stream-flags\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_stream_flags_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "stream-type")] pub fn connect_stream_type_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_stream_type_trampoline< F: Fn(&Stream) + Send + Sync + 'static, >( this: *mut ffi::GstStream, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this)) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::stream-type\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_stream_type_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[doc(alias = "tags")] pub fn connect_tags_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_tags_trampoline( this: *mut ffi::GstStream, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(&from_glib_borrow(this)) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::tags\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_tags_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } unsafe impl Send for Stream {} unsafe impl Sync for Stream {} gstreamer-0.23.5/src/auto/stream_collection.rs000064400000000000000000000032751046102023000175260ustar 00000000000000// 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::{ffi, Object, Stream}; use glib::translate::*; glib::wrapper! { #[doc(alias = "GstStreamCollection")] pub struct StreamCollection(Object) @extends Object; match fn { type_ => || ffi::gst_stream_collection_get_type(), } } impl StreamCollection { #[doc(alias = "gst_stream_collection_get_size")] #[doc(alias = "get_size")] pub fn size(&self) -> u32 { unsafe { ffi::gst_stream_collection_get_size(self.to_glib_none().0) } } #[doc(alias = "gst_stream_collection_get_stream")] #[doc(alias = "get_stream")] pub fn stream(&self, index: u32) -> Option { unsafe { from_glib_none(ffi::gst_stream_collection_get_stream( self.to_glib_none().0, index, )) } } #[doc(alias = "gst_stream_collection_get_upstream_id")] #[doc(alias = "get_upstream_id")] #[doc(alias = "upstream-id")] pub fn upstream_id(&self) -> Option { unsafe { from_glib_none(ffi::gst_stream_collection_get_upstream_id( self.to_glib_none().0, )) } } //#[doc(alias = "stream-notify")] //pub fn connect_stream_notify(&self, detail: Option<&str>, f: F) -> SignalHandlerId { // Ignored prop: GObject.ParamSpec //} } unsafe impl Send for StreamCollection {} unsafe impl Sync for StreamCollection {} gstreamer-0.23.5/src/auto/system_clock.rs000064400000000000000000000053361046102023000165170ustar 00000000000000// 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::{ffi, Clock, ClockType, Object}; use glib::{ prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstSystemClock")] pub struct SystemClock(Object) @extends Clock, Object; match fn { type_ => || ffi::gst_system_clock_get_type(), } } impl SystemClock { pub const NONE: Option<&'static SystemClock> = None; #[doc(alias = "gst_system_clock_obtain")] pub fn obtain() -> Clock { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_system_clock_obtain()) } } #[doc(alias = "gst_system_clock_set_default")] pub fn set_default(new_clock: Option<&impl IsA>) { assert_initialized_main_thread!(); unsafe { ffi::gst_system_clock_set_default(new_clock.map(|p| p.as_ref()).to_glib_none().0); } } } unsafe impl Send for SystemClock {} unsafe impl Sync for SystemClock {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait SystemClockExt: IsA + sealed::Sealed + 'static { #[doc(alias = "clock-type")] fn clock_type(&self) -> ClockType { ObjectExt::property(self.as_ref(), "clock-type") } #[doc(alias = "clock-type")] fn set_clock_type(&self, clock_type: ClockType) { ObjectExt::set_property(self.as_ref(), "clock-type", clock_type) } #[doc(alias = "clock-type")] fn connect_clock_type_notify( &self, f: F, ) -> SignalHandlerId { unsafe extern "C" fn notify_clock_type_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstSystemClock, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(SystemClock::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::clock-type\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_clock_type_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> SystemClockExt for O {} gstreamer-0.23.5/src/auto/tag_setter.rs000064400000000000000000000060271046102023000161570ustar 00000000000000// 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::{ffi, Element, Object, TagList, TagMergeMode}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstTagSetter")] pub struct TagSetter(Interface) @requires Element, Object; match fn { type_ => || ffi::gst_tag_setter_get_type(), } } impl TagSetter { pub const NONE: Option<&'static TagSetter> = None; } unsafe impl Send for TagSetter {} unsafe impl Sync for TagSetter {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait TagSetterExt: IsA + sealed::Sealed + 'static { //#[doc(alias = "gst_tag_setter_add_tag_valist")] //fn add_tag_valist(&self, mode: TagMergeMode, tag: &str, var_args: /*Unknown conversion*//*Unimplemented*/Unsupported) { // unsafe { TODO: call ffi:gst_tag_setter_add_tag_valist() } //} //#[doc(alias = "gst_tag_setter_add_tag_valist_values")] //fn add_tag_valist_values(&self, mode: TagMergeMode, tag: &str, var_args: /*Unknown conversion*//*Unimplemented*/Unsupported) { // unsafe { TODO: call ffi:gst_tag_setter_add_tag_valist_values() } //} //#[doc(alias = "gst_tag_setter_add_tag_values")] //fn add_tag_values(&self, mode: TagMergeMode, tag: &str, : /*Unknown conversion*//*Unimplemented*/Basic: VarArgs) { // unsafe { TODO: call ffi:gst_tag_setter_add_tag_values() } //} #[doc(alias = "gst_tag_setter_get_tag_list")] #[doc(alias = "get_tag_list")] fn tag_list(&self) -> Option { unsafe { from_glib_none(ffi::gst_tag_setter_get_tag_list( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_tag_setter_get_tag_merge_mode")] #[doc(alias = "get_tag_merge_mode")] fn tag_merge_mode(&self) -> TagMergeMode { unsafe { from_glib(ffi::gst_tag_setter_get_tag_merge_mode( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_tag_setter_merge_tags")] fn merge_tags(&self, list: &TagList, mode: TagMergeMode) { unsafe { ffi::gst_tag_setter_merge_tags( self.as_ref().to_glib_none().0, list.to_glib_none().0, mode.into_glib(), ); } } #[doc(alias = "gst_tag_setter_reset_tags")] fn reset_tags(&self) { unsafe { ffi::gst_tag_setter_reset_tags(self.as_ref().to_glib_none().0); } } #[doc(alias = "gst_tag_setter_set_tag_merge_mode")] fn set_tag_merge_mode(&self, mode: TagMergeMode) { unsafe { ffi::gst_tag_setter_set_tag_merge_mode( self.as_ref().to_glib_none().0, mode.into_glib(), ); } } } impl> TagSetterExt for O {} gstreamer-0.23.5/src/auto/task.rs000064400000000000000000000067661046102023000147720ustar 00000000000000// 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::{ffi, Object, TaskPool, TaskState}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstTask")] pub struct Task(Object) @extends Object; match fn { type_ => || ffi::gst_task_get_type(), } } impl Task { pub const NONE: Option<&'static Task> = None; #[doc(alias = "gst_task_cleanup_all")] pub fn cleanup_all() { assert_initialized_main_thread!(); unsafe { ffi::gst_task_cleanup_all(); } } } unsafe impl Send for Task {} unsafe impl Sync for Task {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait TaskExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_task_get_pool")] #[doc(alias = "get_pool")] fn pool(&self) -> TaskPool { unsafe { from_glib_full(ffi::gst_task_get_pool(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_task_get_state")] #[doc(alias = "get_state")] fn state(&self) -> TaskState { unsafe { from_glib(ffi::gst_task_get_state(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_task_join")] fn join(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_task_join(self.as_ref().to_glib_none().0), "Failed to join task" ) } } #[doc(alias = "gst_task_pause")] fn pause(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_task_pause(self.as_ref().to_glib_none().0), "Failed to pause task" ) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "gst_task_resume")] fn resume(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_task_resume(self.as_ref().to_glib_none().0), "Failed to resume task" ) } } #[doc(alias = "gst_task_set_pool")] fn set_pool(&self, pool: &impl IsA) { unsafe { ffi::gst_task_set_pool( self.as_ref().to_glib_none().0, pool.as_ref().to_glib_none().0, ); } } #[doc(alias = "gst_task_set_state")] fn set_state(&self, state: TaskState) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_task_set_state(self.as_ref().to_glib_none().0, state.into_glib()), "Failed to set task state" ) } } #[doc(alias = "gst_task_start")] fn start(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_task_start(self.as_ref().to_glib_none().0), "Failed to start task" ) } } #[doc(alias = "gst_task_stop")] fn stop(&self) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_task_stop(self.as_ref().to_glib_none().0), "Failed to stop task" ) } } } impl> TaskExt for O {} gstreamer-0.23.5/src/auto/task_pool.rs000064400000000000000000000032371046102023000160110ustar 00000000000000// 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::{ffi, Object}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstTaskPool")] pub struct TaskPool(Object) @extends Object; match fn { type_ => || ffi::gst_task_pool_get_type(), } } impl TaskPool { pub const NONE: Option<&'static TaskPool> = None; #[doc(alias = "gst_task_pool_new")] pub fn new() -> TaskPool { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_task_pool_new()) } } } impl Default for TaskPool { fn default() -> Self { Self::new() } } unsafe impl Send for TaskPool {} unsafe impl Sync for TaskPool {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait TaskPoolExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_task_pool_cleanup")] fn cleanup(&self) { unsafe { ffi::gst_task_pool_cleanup(self.as_ref().to_glib_none().0); } } #[doc(alias = "gst_task_pool_prepare")] fn prepare(&self) -> Result<(), glib::Error> { unsafe { let mut error = std::ptr::null_mut(); let _ = ffi::gst_task_pool_prepare(self.as_ref().to_glib_none().0, &mut error); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } } impl> TaskPoolExt for O {} gstreamer-0.23.5/src/auto/toc_setter.rs000064400000000000000000000027271046102023000161740ustar 00000000000000// 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::{ffi, Element, Object, Toc}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstTocSetter")] pub struct TocSetter(Interface) @requires Element, Object; match fn { type_ => || ffi::gst_toc_setter_get_type(), } } impl TocSetter { pub const NONE: Option<&'static TocSetter> = None; } unsafe impl Send for TocSetter {} unsafe impl Sync for TocSetter {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait TocSetterExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_toc_setter_get_toc")] #[doc(alias = "get_toc")] fn toc(&self) -> Option { unsafe { from_glib_full(ffi::gst_toc_setter_get_toc(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_toc_setter_reset")] fn reset(&self) { unsafe { ffi::gst_toc_setter_reset(self.as_ref().to_glib_none().0); } } #[doc(alias = "gst_toc_setter_set_toc")] fn set_toc(&self, toc: Option<&Toc>) { unsafe { ffi::gst_toc_setter_set_toc(self.as_ref().to_glib_none().0, toc.to_glib_none().0); } } } impl> TocSetterExt for O {} gstreamer-0.23.5/src/auto/tracer.rs000064400000000000000000000040331046102023000152710ustar 00000000000000// 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::{ffi, Object}; use glib::{ prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, }; use std::boxed::Box as Box_; glib::wrapper! { #[doc(alias = "GstTracer")] pub struct Tracer(Object) @extends Object; match fn { type_ => || ffi::gst_tracer_get_type(), } } impl Tracer { pub const NONE: Option<&'static Tracer> = None; } unsafe impl Send for Tracer {} unsafe impl Sync for Tracer {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait TracerExt: IsA + sealed::Sealed + 'static { fn params(&self) -> Option { ObjectExt::property(self.as_ref(), "params") } fn set_params(&self, params: Option<&str>) { ObjectExt::set_property(self.as_ref(), "params", params) } #[doc(alias = "params")] fn connect_params_notify(&self, f: F) -> SignalHandlerId { unsafe extern "C" fn notify_params_trampoline< P: IsA, F: Fn(&P) + Send + Sync + 'static, >( this: *mut ffi::GstTracer, _param_spec: glib::ffi::gpointer, f: glib::ffi::gpointer, ) { let f: &F = &*(f as *const F); f(Tracer::from_glib_borrow(this).unsafe_cast_ref()) } unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"notify::params\0".as_ptr() as *const _, Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>( notify_params_trampoline:: as *const (), )), Box_::into_raw(f), ) } } } impl> TracerExt for O {} gstreamer-0.23.5/src/auto/tracer_factory.rs000064400000000000000000000016551046102023000170270ustar 00000000000000// 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::{ffi, Object, PluginFeature}; use glib::translate::*; glib::wrapper! { #[doc(alias = "GstTracerFactory")] pub struct TracerFactory(Object) @extends PluginFeature, Object; match fn { type_ => || ffi::gst_tracer_factory_get_type(), } } impl TracerFactory { #[doc(alias = "gst_tracer_factory_get_tracer_type")] #[doc(alias = "get_tracer_type")] pub fn tracer_type(&self) -> glib::types::Type { unsafe { from_glib(ffi::gst_tracer_factory_get_tracer_type( self.to_glib_none().0, )) } } } unsafe impl Send for TracerFactory {} unsafe impl Sync for TracerFactory {} gstreamer-0.23.5/src/auto/type_find_factory.rs000064400000000000000000000026751046102023000175330ustar 00000000000000// 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::{ffi, Caps, Object, PluginFeature}; use glib::translate::*; glib::wrapper! { #[doc(alias = "GstTypeFindFactory")] pub struct TypeFindFactory(Object) @extends PluginFeature, Object; match fn { type_ => || ffi::gst_type_find_factory_get_type(), } } impl TypeFindFactory { #[doc(alias = "gst_type_find_factory_get_caps")] #[doc(alias = "get_caps")] pub fn caps(&self) -> Option { unsafe { from_glib_none(ffi::gst_type_find_factory_get_caps(self.to_glib_none().0)) } } #[doc(alias = "gst_type_find_factory_get_extensions")] #[doc(alias = "get_extensions")] pub fn extensions(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::gst_type_find_factory_get_extensions( self.to_glib_none().0, )) } } #[doc(alias = "gst_type_find_factory_has_function")] pub fn has_function(&self) -> bool { unsafe { from_glib(ffi::gst_type_find_factory_has_function( self.to_glib_none().0, )) } } } unsafe impl Send for TypeFindFactory {} unsafe impl Sync for TypeFindFactory {} gstreamer-0.23.5/src/auto/uri_handler.rs000064400000000000000000000043421046102023000163100ustar 00000000000000// 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::{ffi, URIType}; use glib::{prelude::*, translate::*}; glib::wrapper! { #[doc(alias = "GstURIHandler")] pub struct URIHandler(Interface); match fn { type_ => || ffi::gst_uri_handler_get_type(), } } impl URIHandler { pub const NONE: Option<&'static URIHandler> = None; } unsafe impl Send for URIHandler {} unsafe impl Sync for URIHandler {} mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait URIHandlerExt: IsA + sealed::Sealed + 'static { #[doc(alias = "gst_uri_handler_get_protocols")] #[doc(alias = "get_protocols")] fn protocols(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_none(ffi::gst_uri_handler_get_protocols( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_uri_handler_get_uri")] #[doc(alias = "get_uri")] fn uri(&self) -> Option { unsafe { from_glib_full(ffi::gst_uri_handler_get_uri(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_uri_handler_get_uri_type")] #[doc(alias = "get_uri_type")] fn uri_type(&self) -> URIType { unsafe { from_glib(ffi::gst_uri_handler_get_uri_type( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_uri_handler_set_uri")] fn set_uri(&self, uri: &str) -> Result<(), glib::Error> { unsafe { let mut error = std::ptr::null_mut(); let is_ok = ffi::gst_uri_handler_set_uri( self.as_ref().to_glib_none().0, uri.to_glib_none().0, &mut error, ); debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null()); if error.is_null() { Ok(()) } else { Err(from_glib_full(error)) } } } } impl> URIHandlerExt for O {} gstreamer-0.23.5/src/auto/versions.txt000064400000000000000000000003421046102023000160530ustar 00000000000000Generated by gir (https://github.com/gtk-rs/gir @ 2b05eaddce95) from gir-files (https://github.com/gtk-rs/gir-files @ 5089b7ff80cd) from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git @ 26898eacb093) gstreamer-0.23.5/src/bin.rs000064400000000000000000000245601046102023000136200ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{boxed::Box as Box_, mem::transmute, path}; use glib::{ prelude::*, signal::{connect_raw, SignalHandlerId}, translate::*, GString, }; use crate::{ffi, prelude::*, Bin, BinFlags, Element, LoggableError}; impl Bin { // rustdoc-stripper-ignore-next /// Creates a new [`Bin`] object with a default name. /// /// Use [`Bin::with_name()`] to create a [`Bin`] with a specific name. /// Use [`Bin::builder()`] for additional configuration. #[doc(alias = "gst_bin_new")] pub fn new() -> Bin { assert_initialized_main_thread!(); unsafe { Element::from_glib_none(ffi::gst_bin_new(std::ptr::null())).unsafe_cast() } } // rustdoc-stripper-ignore-next /// Creates a new [`Bin`] object with the specified name. /// /// Use [`Bin::builder()`] for additional configuration. #[doc(alias = "gst_bin_new")] pub fn with_name(name: &str) -> Bin { assert_initialized_main_thread!(); unsafe { Element::from_glib_none(ffi::gst_bin_new(name.to_glib_none().0)).unsafe_cast() } } // rustdoc-stripper-ignore-next /// Creates a new builder-pattern struct instance to construct [`Bin`] objects. /// /// This method returns an instance of [`BinBuilder`] which can be used to create [`Bin`] objects. pub fn builder() -> BinBuilder { BinBuilder::new() } } mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait GstBinExtManual: sealed::Sealed + IsA + 'static { #[doc(alias = "gst_bin_add_many")] fn add_many( &self, elements: impl IntoIterator>, ) -> Result<(), glib::BoolError> { for e in elements { unsafe { glib::result_from_gboolean!( ffi::gst_bin_add(self.as_ref().to_glib_none().0, e.as_ref().to_glib_none().0), "Failed to add elements" )?; } } Ok(()) } #[doc(alias = "gst_bin_remove_many")] fn remove_many( &self, elements: impl IntoIterator>, ) -> Result<(), glib::BoolError> { for e in elements { unsafe { glib::result_from_gboolean!( ffi::gst_bin_remove( self.as_ref().to_glib_none().0, e.as_ref().to_glib_none().0, ), "Failed to remove elements" )?; } } Ok(()) } #[doc(alias = "do-latency")] fn connect_do_latency Result<(), LoggableError> + Send + Sync + 'static>( &self, f: F, ) -> SignalHandlerId { unsafe { let f: Box_ = Box_::new(f); connect_raw( self.as_ptr() as *mut _, b"do-latency\0".as_ptr() as *const _, Some(transmute::<*const (), unsafe extern "C" fn()>( do_latency_trampoline:: as *const (), )), Box_::into_raw(f), ) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "gst_bin_iterate_all_by_element_factory_name")] fn iterate_all_by_element_factory_name(&self, factory_name: &str) -> crate::Iterator { unsafe { from_glib_full(ffi::gst_bin_iterate_all_by_element_factory_name( self.as_ref().to_glib_none().0, factory_name.to_glib_none().0, )) } } #[doc(alias = "gst_bin_iterate_all_by_interface")] fn iterate_all_by_interface(&self, iface: glib::types::Type) -> crate::Iterator { unsafe { from_glib_full(ffi::gst_bin_iterate_all_by_interface( self.as_ref().to_glib_none().0, iface.into_glib(), )) } } #[doc(alias = "gst_bin_iterate_elements")] fn iterate_elements(&self) -> crate::Iterator { unsafe { from_glib_full(ffi::gst_bin_iterate_elements( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_bin_iterate_recurse")] fn iterate_recurse(&self) -> crate::Iterator { unsafe { from_glib_full(ffi::gst_bin_iterate_recurse(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_bin_iterate_sinks")] fn iterate_sinks(&self) -> crate::Iterator { unsafe { from_glib_full(ffi::gst_bin_iterate_sinks(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_bin_iterate_sorted")] fn iterate_sorted(&self) -> crate::Iterator { unsafe { from_glib_full(ffi::gst_bin_iterate_sorted(self.as_ref().to_glib_none().0)) } } #[doc(alias = "gst_bin_iterate_sources")] fn iterate_sources(&self) -> crate::Iterator { unsafe { from_glib_full(ffi::gst_bin_iterate_sources(self.as_ref().to_glib_none().0)) } } #[doc(alias = "get_children")] fn children(&self) -> Vec { unsafe { let bin: &ffi::GstBin = &*(self.as_ptr() as *const _); let _guard = self.as_ref().object_lock(); FromGlibPtrContainer::from_glib_none(bin.children) } } #[doc(alias = "gst_debug_bin_to_dot_data")] fn debug_to_dot_data(&self, details: crate::DebugGraphDetails) -> GString { crate::auto::functions::debug_bin_to_dot_data(self, details) } #[doc(alias = "GST_DEBUG_BIN_TO_DOT_FILE")] #[doc(alias = "gst_debug_bin_to_dot_file")] fn debug_to_dot_file( &self, details: crate::DebugGraphDetails, file_name: impl AsRef, ) { crate::auto::functions::debug_bin_to_dot_file(self, details, file_name) } #[doc(alias = "GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS")] #[doc(alias = "gst_debug_bin_to_dot_file_with_ts")] fn debug_to_dot_file_with_ts( &self, details: crate::DebugGraphDetails, file_name: impl AsRef, ) { crate::auto::functions::debug_bin_to_dot_file_with_ts(self, details, file_name) } fn set_bin_flags(&self, flags: BinFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags |= flags.into_glib(); } } fn unset_bin_flags(&self, flags: BinFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags &= !flags.into_glib(); } } #[doc(alias = "get_bin_flags")] fn bin_flags(&self) -> BinFlags { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); from_glib((*ptr).flags) } } } impl> GstBinExtManual for O {} impl Default for Bin { fn default() -> Self { glib::object::Object::new() } } // rustdoc-stripper-ignore-next /// A [builder-pattern] type to construct [`Bin`] objects. /// /// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html #[must_use = "The builder must be built to be used"] pub struct BinBuilder { builder: glib::object::ObjectBuilder<'static, Bin>, } impl BinBuilder { fn new() -> Self { Self { builder: glib::Object::builder(), } } // rustdoc-stripper-ignore-next /// Build the [`Bin`]. #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"] pub fn build(self) -> Bin { self.builder.build() } pub fn async_handling(self, async_handling: bool) -> Self { Self { builder: self.builder.property("async-handling", async_handling), } } pub fn async_handling_if_some(self, async_handling: Option) -> Self { if let Some(async_handling) = async_handling { self.async_handling(async_handling) } else { self } } pub fn message_forward(self, message_forward: bool) -> Self { Self { builder: self.builder.property("message-forward", message_forward), } } pub fn message_forward_if_some(self, message_forward: Option) -> Self { if let Some(message_forward) = message_forward { self.message_forward(message_forward) } else { self } } pub fn name(self, name: impl Into) -> Self { Self { builder: self.builder.property("name", name.into()), } } pub fn name_if(self, name: impl Into, predicate: bool) -> Self { if predicate { self.name(name) } else { self } } pub fn name_if_some(self, name: Option>) -> Self { if let Some(name) = name { self.name(name) } else { self } } } unsafe extern "C" fn do_latency_trampoline< P, F: Fn(&P) -> Result<(), LoggableError> + Send + Sync + 'static, >( this: *mut ffi::GstBin, f: glib::ffi::gpointer, ) -> glib::ffi::gboolean where P: IsA, { let f: &F = &*(f as *const F); match f(Bin::from_glib_borrow(this).unsafe_cast_ref()) { Ok(()) => true, Err(err) => { err.log_with_object(&*Bin::from_glib_borrow(this)); false } } .into_glib() } #[cfg(test)] mod tests { use super::*; #[test] fn test_get_children() { crate::init().unwrap(); let bin = crate::Bin::new(); bin.add( &crate::ElementFactory::make("identity") .name("identity0") .build() .unwrap(), ) .unwrap(); bin.add( &crate::ElementFactory::make("identity") .name("identity1") .build() .unwrap(), ) .unwrap(); let mut child_names = bin .children() .iter() .map(|c| c.name()) .collect::>(); child_names.sort(); assert_eq!( child_names, vec![String::from("identity0"), String::from("identity1")] ); } } gstreamer-0.23.5/src/buffer.rs000064400000000000000000001725771046102023000143350ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ cmp, fmt, marker::PhantomData, mem, ops, ops::{Bound, ControlFlow, Range, RangeBounds}, ptr, slice, }; use glib::translate::*; use crate::{ ffi, meta::*, BufferCursor, BufferFlags, BufferRefCursor, ClockTime, Memory, MemoryRef, }; pub enum Readable {} pub enum Writable {} #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum BufferMetaForeachAction { Keep, Remove, } mini_object_wrapper!(Buffer, BufferRef, ffi::GstBuffer, || { ffi::gst_buffer_get_type() }); pub struct BufferMap<'a, T> { buffer: &'a BufferRef, map_info: ffi::GstMapInfo, phantom: PhantomData, } pub struct MappedBuffer { buffer: Buffer, map_info: ffi::GstMapInfo, phantom: PhantomData, } impl Buffer { #[doc(alias = "gst_buffer_new")] #[inline] pub fn new() -> Self { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_buffer_new()) } } #[doc(alias = "gst_buffer_new_allocate")] #[doc(alias = "gst_buffer_new_and_alloc")] #[inline] pub fn with_size(size: usize) -> Result { assert_initialized_main_thread!(); unsafe { Option::<_>::from_glib_full(ffi::gst_buffer_new_allocate( ptr::null_mut(), size, ptr::null_mut(), )) .ok_or_else(|| glib::bool_error!("Failed to allocate buffer")) } } #[doc(alias = "gst_buffer_new_wrapped")] #[doc(alias = "gst_buffer_new_wrapped_full")] #[inline] pub fn from_mut_slice + Send + 'static>(slice: T) -> Self { assert_initialized_main_thread!(); let mem = Memory::from_mut_slice(slice); let mut buffer = Buffer::new(); { let buffer = buffer.get_mut().unwrap(); buffer.append_memory(mem); buffer.unset_flags(BufferFlags::TAG_MEMORY); } buffer } #[doc(alias = "gst_buffer_new_wrapped")] #[doc(alias = "gst_buffer_new_wrapped_full")] #[inline] pub fn from_slice + Send + 'static>(slice: T) -> Self { assert_initialized_main_thread!(); let mem = Memory::from_slice(slice); let mut buffer = Buffer::new(); { let buffer = buffer.get_mut().unwrap(); buffer.append_memory(mem); buffer.unset_flags(BufferFlags::TAG_MEMORY); } buffer } #[doc(alias = "gst_buffer_map")] #[inline] pub fn into_mapped_buffer_readable(self) -> Result, Self> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res: bool = from_glib(ffi::gst_buffer_map( self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READ, )); if res { Ok(MappedBuffer { buffer: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(self) } } } #[doc(alias = "gst_buffer_map")] #[inline] pub fn into_mapped_buffer_writable(self) -> Result, Self> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res: bool = from_glib(ffi::gst_buffer_map( self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READWRITE, )); if res { Ok(MappedBuffer { buffer: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(self) } } } #[inline] pub fn into_cursor_readable(self) -> BufferCursor { BufferCursor::new_readable(self) } #[inline] pub fn into_cursor_writable(self) -> Result, glib::BoolError> { BufferCursor::new_writable(self) } #[doc(alias = "gst_buffer_append")] pub fn append(&mut self, other: Self) { unsafe { let ptr = ffi::gst_buffer_append(self.as_mut_ptr(), other.into_glib_ptr()); self.replace_ptr(ptr); } } } impl Default for Buffer { fn default() -> Self { Self::new() } } impl BufferRef { #[doc(alias = "gst_buffer_map")] #[inline] pub fn map_readable(&self) -> Result, glib::BoolError> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res = ffi::gst_buffer_map(self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READ); if res == glib::ffi::GTRUE { Ok(BufferMap { buffer: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(glib::bool_error!("Failed to map buffer readable")) } } } #[doc(alias = "gst_buffer_map")] #[inline] pub fn map_writable(&mut self) -> Result, glib::BoolError> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res = ffi::gst_buffer_map( self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READWRITE, ); if res == glib::ffi::GTRUE { Ok(BufferMap { buffer: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(glib::bool_error!("Failed to map buffer writable")) } } } fn memory_range_into_idx_len( &self, range: impl RangeBounds, ) -> Result<(u32, i32), glib::BoolError> { let n_memory = self.n_memory(); debug_assert!(n_memory <= u32::MAX as usize); let start_idx = match range.start_bound() { ops::Bound::Included(idx) if *idx >= n_memory => { return Err(glib::bool_error!("Invalid range start")); } ops::Bound::Included(idx) => *idx, ops::Bound::Excluded(idx) if idx.checked_add(1).map_or(true, |idx| idx >= n_memory) => { return Err(glib::bool_error!("Invalid range start")); } ops::Bound::Excluded(idx) => *idx + 1, ops::Bound::Unbounded => 0, }; let end_idx = match range.end_bound() { ops::Bound::Included(idx) if idx.checked_add(1).map_or(true, |idx| idx > n_memory) => { return Err(glib::bool_error!("Invalid range end")); } ops::Bound::Included(idx) => *idx + 1, ops::Bound::Excluded(idx) if *idx > n_memory => { return Err(glib::bool_error!("Invalid range end")); } ops::Bound::Excluded(idx) => *idx, ops::Bound::Unbounded => n_memory, }; Ok(( start_idx as u32, i32::try_from(end_idx - start_idx).map_err(|_| glib::bool_error!("Too large range"))?, )) } #[doc(alias = "gst_buffer_map_range")] #[inline] pub fn map_range_readable( &self, range: impl RangeBounds, ) -> Result, glib::BoolError> { let (idx, len) = self.memory_range_into_idx_len(range)?; unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res = ffi::gst_buffer_map_range( self.as_mut_ptr(), idx, len, map_info.as_mut_ptr(), ffi::GST_MAP_READ, ); if res == glib::ffi::GTRUE { Ok(BufferMap { buffer: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(glib::bool_error!("Failed to map buffer readable")) } } } #[doc(alias = "gst_buffer_map_range")] #[inline] pub fn map_range_writable( &mut self, range: impl RangeBounds, ) -> Result, glib::BoolError> { let (idx, len) = self.memory_range_into_idx_len(range)?; unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res = ffi::gst_buffer_map_range( self.as_mut_ptr(), idx, len, map_info.as_mut_ptr(), ffi::GST_MAP_READWRITE, ); if res == glib::ffi::GTRUE { Ok(BufferMap { buffer: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(glib::bool_error!("Failed to map buffer writable")) } } } pub(crate) fn byte_range_into_offset_len( &self, range: impl RangeBounds, ) -> Result<(usize, usize), glib::BoolError> { let size = self.size(); let start_idx = match range.start_bound() { ops::Bound::Included(idx) if *idx >= size => { return Err(glib::bool_error!("Invalid range start")); } ops::Bound::Included(idx) => *idx, ops::Bound::Excluded(idx) if idx.checked_add(1).map_or(true, |idx| idx >= size) => { return Err(glib::bool_error!("Invalid range start")); } ops::Bound::Excluded(idx) => *idx + 1, ops::Bound::Unbounded => 0, }; let end_idx = match range.end_bound() { ops::Bound::Included(idx) if idx.checked_add(1).map_or(true, |idx| idx > size) => { return Err(glib::bool_error!("Invalid range end")); } ops::Bound::Included(idx) => *idx + 1, ops::Bound::Excluded(idx) if *idx > size => { return Err(glib::bool_error!("Invalid range end")); } ops::Bound::Excluded(idx) => *idx, ops::Bound::Unbounded => size, }; Ok((start_idx, end_idx - start_idx)) } #[doc(alias = "gst_buffer_copy_region")] pub fn copy_region( &self, flags: crate::BufferCopyFlags, range: impl RangeBounds, ) -> Result { let (offset, size) = self.byte_range_into_offset_len(range)?; unsafe { Option::<_>::from_glib_full(ffi::gst_buffer_copy_region( self.as_mut_ptr(), flags.into_glib(), offset, size, )) .ok_or_else(|| glib::bool_error!("Failed to copy region of buffer")) } } #[doc(alias = "gst_buffer_copy_into")] pub fn copy_into( &self, dest: &mut BufferRef, flags: crate::BufferCopyFlags, range: impl RangeBounds, ) -> Result<(), glib::BoolError> { let (offset, size) = self.byte_range_into_offset_len(range)?; unsafe { glib::result_from_gboolean!( ffi::gst_buffer_copy_into( dest.as_mut_ptr(), self.as_mut_ptr(), flags.into_glib(), offset, size, ), "Failed to copy into destination buffer", ) } } #[doc(alias = "gst_buffer_fill")] pub fn copy_from_slice(&mut self, offset: usize, slice: &[u8]) -> Result<(), usize> { let maxsize = self.maxsize(); let size = slice.len(); assert!(maxsize >= offset && maxsize - offset >= size); let copied = unsafe { let src = slice.as_ptr(); ffi::gst_buffer_fill( self.as_mut_ptr(), offset, src as glib::ffi::gconstpointer, size, ) }; if copied == size { Ok(()) } else { Err(copied) } } #[doc(alias = "gst_buffer_extract")] pub fn copy_to_slice(&self, offset: usize, slice: &mut [u8]) -> Result<(), usize> { let maxsize = self.size(); let size = slice.len(); assert!(maxsize >= offset && maxsize - offset >= size); let copied = unsafe { let dest = slice.as_mut_ptr(); ffi::gst_buffer_extract(self.as_mut_ptr(), offset, dest as glib::ffi::gpointer, size) }; if copied == size { Ok(()) } else { Err(copied) } } #[doc(alias = "gst_buffer_copy_deep")] pub fn copy_deep(&self) -> Result { unsafe { Option::<_>::from_glib_full(ffi::gst_buffer_copy_deep(self.as_ptr())) .ok_or_else(|| glib::bool_error!("Failed to deep copy buffer")) } } #[doc(alias = "get_size")] #[doc(alias = "gst_buffer_get_size")] pub fn size(&self) -> usize { unsafe { ffi::gst_buffer_get_size(self.as_mut_ptr()) } } #[doc(alias = "get_maxsize")] pub fn maxsize(&self) -> usize { unsafe { let mut maxsize = mem::MaybeUninit::uninit(); ffi::gst_buffer_get_sizes_range( self.as_mut_ptr(), 0, -1, ptr::null_mut(), maxsize.as_mut_ptr(), ); maxsize.assume_init() } } #[doc(alias = "gst_buffer_set_size")] pub fn set_size(&mut self, size: usize) { assert!(self.maxsize() >= size); unsafe { ffi::gst_buffer_set_size(self.as_mut_ptr(), size as isize); } } #[doc(alias = "get_offset")] #[doc(alias = "GST_BUFFER_OFFSET")] #[inline] pub fn offset(&self) -> u64 { self.0.offset } #[inline] pub fn set_offset(&mut self, offset: u64) { self.0.offset = offset; } #[doc(alias = "get_offset_end")] #[doc(alias = "GST_BUFFER_OFFSET_END")] #[inline] pub fn offset_end(&self) -> u64 { self.0.offset_end } #[inline] pub fn set_offset_end(&mut self, offset_end: u64) { self.0.offset_end = offset_end; } #[doc(alias = "get_pts")] #[doc(alias = "GST_BUFFER_PTS")] #[inline] pub fn pts(&self) -> Option { unsafe { from_glib(self.0.pts) } } #[inline] pub fn set_pts(&mut self, pts: impl Into>) { self.0.pts = pts.into().into_glib(); } #[doc(alias = "get_dts")] #[doc(alias = "GST_BUFFER_DTS")] #[inline] pub fn dts(&self) -> Option { unsafe { from_glib(self.0.dts) } } #[inline] pub fn set_dts(&mut self, dts: impl Into>) { self.0.dts = dts.into().into_glib(); } #[doc(alias = "get_dts_or_pts")] #[doc(alias = "GST_BUFFER_DTS_OR_PTS")] #[inline] pub fn dts_or_pts(&self) -> Option { let val = self.dts(); if val.is_none() { self.pts() } else { val } } #[doc(alias = "get_duration")] #[doc(alias = "GST_BUFFER_DURATION")] #[inline] pub fn duration(&self) -> Option { unsafe { from_glib(self.0.duration) } } #[inline] pub fn set_duration(&mut self, duration: impl Into>) { self.0.duration = duration.into().into_glib(); } #[doc(alias = "get_flags")] #[doc(alias = "GST_BUFFER_FLAGS")] #[inline] pub fn flags(&self) -> BufferFlags { BufferFlags::from_bits_truncate(self.0.mini_object.flags) } #[doc(alias = "GST_BUFFER_FLAG_SET")] #[inline] pub fn set_flags(&mut self, flags: BufferFlags) { self.0.mini_object.flags |= flags.bits(); } #[doc(alias = "GST_BUFFER_FLAG_UNSET")] #[inline] pub fn unset_flags(&mut self, flags: BufferFlags) { self.0.mini_object.flags &= !flags.bits(); } #[doc(alias = "get_meta")] #[doc(alias = "gst_buffer_get_meta")] #[inline] pub fn meta(&self) -> Option> { unsafe { let meta = ffi::gst_buffer_get_meta(self.as_mut_ptr(), T::meta_api().into_glib()); if meta.is_null() { None } else { Some(T::from_ptr(self, meta as *const ::GstType)) } } } #[doc(alias = "get_meta_mut")] #[inline] pub fn meta_mut(&mut self) -> Option> { unsafe { let meta = ffi::gst_buffer_get_meta(self.as_mut_ptr(), T::meta_api().into_glib()); if meta.is_null() { None } else { Some(T::from_mut_ptr(self, meta as *mut ::GstType)) } } } pub fn iter_meta(&self) -> MetaIter { MetaIter::new(self) } pub fn iter_meta_mut(&mut self) -> MetaIterMut { MetaIterMut::new(self) } #[doc(alias = "gst_buffer_foreach_meta")] pub fn foreach_meta) -> ControlFlow<(), ()>>(&self, func: F) -> bool { unsafe extern "C" fn trampoline) -> ControlFlow<(), ()>>( buffer: *mut ffi::GstBuffer, meta: *mut *mut ffi::GstMeta, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let func = user_data as *mut F; let res = (*func)(Meta::from_ptr(BufferRef::from_ptr(buffer), *meta)); matches!(res, ControlFlow::Continue(_)).into_glib() } unsafe { let mut func = func; let func_ptr: &mut F = &mut func; from_glib(ffi::gst_buffer_foreach_meta( mut_override(self.as_ptr()), Some(trampoline::), func_ptr as *mut _ as *mut _, )) } } #[doc(alias = "gst_buffer_foreach_meta")] pub fn foreach_meta_mut< F: FnMut( MetaRefMut, ) -> ControlFlow, >( &mut self, func: F, ) -> bool { unsafe extern "C" fn trampoline< F: FnMut( MetaRefMut, ) -> ControlFlow, >( buffer: *mut ffi::GstBuffer, meta: *mut *mut ffi::GstMeta, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let func = user_data as *mut F; let res = (*func)(Meta::from_mut_ptr(BufferRef::from_mut_ptr(buffer), *meta)); let (cont, action) = match res { ControlFlow::Continue(action) => (true, action), ControlFlow::Break(action) => (false, action), }; if action == BufferMetaForeachAction::Remove { *meta = ptr::null_mut(); } cont.into_glib() } unsafe { let mut func = func; let func_ptr: &mut F = &mut func; from_glib(ffi::gst_buffer_foreach_meta( mut_override(self.as_ptr()), Some(trampoline::), func_ptr as *mut _ as *mut _, )) } } #[doc(alias = "gst_buffer_append_memory")] pub fn append_memory(&mut self, mem: Memory) { unsafe { ffi::gst_buffer_append_memory(self.as_mut_ptr(), mem.into_glib_ptr()) } } #[doc(alias = "gst_buffer_find_memory")] pub fn find_memory(&self, range: impl RangeBounds) -> Option<(Range, usize)> { let (offset, size) = self.byte_range_into_offset_len(range).ok()?; unsafe { let mut idx = mem::MaybeUninit::uninit(); let mut length = mem::MaybeUninit::uninit(); let mut skip = mem::MaybeUninit::uninit(); let res = from_glib(ffi::gst_buffer_find_memory( self.as_mut_ptr(), offset, size, idx.as_mut_ptr(), length.as_mut_ptr(), skip.as_mut_ptr(), )); if res { let idx = idx.assume_init() as usize; let length = length.assume_init() as usize; let skip = skip.assume_init(); Some((idx..(idx + length), skip)) } else { None } } } #[doc(alias = "get_all_memory")] #[doc(alias = "gst_buffer_get_all_memory")] pub fn all_memory(&self) -> Option { unsafe { from_glib_full(ffi::gst_buffer_get_all_memory(self.as_mut_ptr())) } } #[doc(alias = "get_max_memory")] #[doc(alias = "gst_buffer_get_max_memory")] pub fn max_memory() -> usize { unsafe { ffi::gst_buffer_get_max_memory() as usize } } #[doc(alias = "get_memory")] #[doc(alias = "gst_buffer_get_memory")] pub fn memory(&self, idx: usize) -> Option { if idx >= self.n_memory() { return None; } unsafe { let res = ffi::gst_buffer_get_memory(self.as_mut_ptr(), idx as u32); Some(from_glib_full(res)) } } #[doc(alias = "get_memory_range")] #[doc(alias = "gst_buffer_get_memory_range")] pub fn memory_range(&self, range: impl RangeBounds) -> Option { let (idx, len) = self.memory_range_into_idx_len(range).ok()?; unsafe { let res = ffi::gst_buffer_get_memory_range(self.as_mut_ptr(), idx, len); from_glib_full(res) } } #[doc(alias = "gst_buffer_insert_memory")] pub fn insert_memory(&mut self, idx: impl Into>, mem: Memory) { let n_memory = self.n_memory(); let idx = idx.into(); let idx = idx.unwrap_or(n_memory); assert!(idx <= self.n_memory()); unsafe { ffi::gst_buffer_insert_memory(self.as_mut_ptr(), idx as i32, mem.into_glib_ptr()) } } #[doc(alias = "gst_buffer_is_all_memory_writable")] pub fn is_all_memory_writable(&self) -> bool { unsafe { from_glib(ffi::gst_buffer_is_all_memory_writable(self.as_mut_ptr())) } } #[doc(alias = "gst_buffer_is_memory_range_writable")] pub fn is_memory_range_writable(&self, range: impl RangeBounds) -> bool { let Some((idx, len)) = self.memory_range_into_idx_len(range).ok() else { return false; }; unsafe { from_glib(ffi::gst_buffer_is_memory_range_writable( self.as_mut_ptr(), idx, len, )) } } #[doc(alias = "gst_buffer_n_memory")] pub fn n_memory(&self) -> usize { unsafe { ffi::gst_buffer_n_memory(self.as_ptr() as *mut _) as usize } } #[doc(alias = "gst_buffer_peek_memory")] pub fn peek_memory(&self, idx: usize) -> &MemoryRef { assert!(idx < self.n_memory()); unsafe { MemoryRef::from_ptr(ffi::gst_buffer_peek_memory(self.as_mut_ptr(), idx as u32)) } } #[doc(alias = "gst_buffer_peek_memory")] pub fn peek_memory_mut(&mut self, idx: usize) -> Result<&mut MemoryRef, glib::BoolError> { assert!(idx < self.n_memory()); unsafe { let mem = ffi::gst_buffer_peek_memory(self.as_mut_ptr(), idx as u32); if ffi::gst_mini_object_is_writable(mem as *mut _) == glib::ffi::GFALSE { Err(glib::bool_error!("Memory not writable")) } else { Ok(MemoryRef::from_mut_ptr(mem)) } } } #[doc(alias = "gst_buffer_prepend_memory")] pub fn prepend_memory(&mut self, mem: Memory) { unsafe { ffi::gst_buffer_prepend_memory(self.as_mut_ptr(), mem.into_glib_ptr()) } } #[doc(alias = "gst_buffer_remove_all_memory")] pub fn remove_all_memory(&mut self) { unsafe { ffi::gst_buffer_remove_all_memory(self.as_mut_ptr()) } } #[doc(alias = "gst_buffer_remove_memory")] pub fn remove_memory(&mut self, idx: usize) { assert!(idx < self.n_memory()); unsafe { ffi::gst_buffer_remove_memory(self.as_mut_ptr(), idx as u32) } } #[doc(alias = "gst_buffer_remove_memory_range")] pub fn remove_memory_range(&mut self, range: impl RangeBounds) { let (idx, len) = self .memory_range_into_idx_len(range) .expect("Invalid memory range"); unsafe { ffi::gst_buffer_remove_memory_range(self.as_mut_ptr(), idx, len) } } #[doc(alias = "gst_buffer_replace_all_memory")] pub fn replace_all_memory(&mut self, mem: Memory) { unsafe { ffi::gst_buffer_replace_all_memory(self.as_mut_ptr(), mem.into_glib_ptr()) } } #[doc(alias = "gst_buffer_replace_memory")] pub fn replace_memory(&mut self, idx: usize, mem: Memory) { assert!(idx < self.n_memory()); unsafe { ffi::gst_buffer_replace_memory(self.as_mut_ptr(), idx as u32, mem.into_glib_ptr()) } } #[doc(alias = "gst_buffer_replace_memory_range")] pub fn replace_memory_range(&mut self, range: impl RangeBounds, mem: Memory) { let (idx, len) = self .memory_range_into_idx_len(range) .expect("Invalid memory range"); unsafe { ffi::gst_buffer_replace_memory_range(self.as_mut_ptr(), idx, len, mem.into_glib_ptr()) } } pub fn iter_memories(&self) -> Iter { Iter::new(self) } pub fn iter_memories_mut(&mut self) -> Result { if !self.is_all_memory_writable() { Err(glib::bool_error!("Not all memory are writable")) } else { Ok(IterMut::new(self)) } } pub fn iter_memories_owned(&self) -> IterOwned { IterOwned::new(self) } pub fn as_cursor_readable(&self) -> BufferRefCursor<&BufferRef> { BufferRefCursor::new_readable(self) } pub fn as_cursor_writable( &mut self, ) -> Result, glib::BoolError> { BufferRefCursor::new_writable(self) } #[doc(alias = "gst_util_dump_buffer")] pub fn dump(&self) -> Dump { Dump { buffer: self, start: Bound::Unbounded, end: Bound::Unbounded, } } #[doc(alias = "gst_util_dump_buffer")] pub fn dump_range(&self, range: impl RangeBounds) -> Dump { Dump { buffer: self, start: range.start_bound().cloned(), end: range.end_bound().cloned(), } } } macro_rules! define_meta_iter( ($name:ident, $typ:ty, $mtyp:ty, $prepare_buffer:expr, $from_ptr:expr) => { pub struct $name<'a, T: MetaAPI + 'a> { buffer: $typ, state: glib::ffi::gpointer, meta_api: glib::Type, items: PhantomData<$mtyp>, } unsafe impl<'a, T: MetaAPI> Send for $name<'a, T> { } unsafe impl<'a, T: MetaAPI> Sync for $name<'a, T> { } impl<'a, T: MetaAPI> fmt::Debug for $name<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct(stringify!($name)) .field("buffer", &self.buffer) .field("state", &self.state) .field("meta_api", &self.meta_api) .field("items", &self.items) .finish() } } impl<'a, T: MetaAPI> $name<'a, T> { fn new(buffer: $typ) -> $name<'a, T> { skip_assert_initialized!(); $name { buffer, state: ptr::null_mut(), meta_api: T::meta_api(), items: PhantomData, } } } #[allow(clippy::redundant_closure_call)] impl<'a, T: MetaAPI> Iterator for $name<'a, T> { type Item = $mtyp; fn next(&mut self) -> Option { loop { unsafe { let meta = ffi::gst_buffer_iterate_meta(self.buffer.as_mut_ptr(), &mut self.state); if meta.is_null() { return None; } else if self.meta_api == glib::Type::INVALID || glib::Type::from_glib((*(*meta).info).api) == self.meta_api { // FIXME: Workaround for a lifetime issue with the mutable iterator only let buffer = $prepare_buffer(self.buffer.as_mut_ptr()); let item = $from_ptr(buffer, meta); return Some(item); } } } } } impl<'a, T: MetaAPI> std::iter::FusedIterator for $name<'a, T> { } } ); define_meta_iter!( MetaIter, &'a BufferRef, MetaRef<'a, T>, |buffer: *const ffi::GstBuffer| BufferRef::from_ptr(buffer), |buffer, meta| T::from_ptr(buffer, meta as *const ::GstType) ); define_meta_iter!( MetaIterMut, &'a mut BufferRef, MetaRefMut<'a, T, crate::meta::Iterated>, |buffer: *mut ffi::GstBuffer| BufferRef::from_mut_ptr(buffer), |buffer: &'a mut BufferRef, meta| T::from_mut_ptr(buffer, meta as *mut ::GstType) ); macro_rules! define_iter( ($name:ident, $typ:ty, $mtyp:ty, $get_item:expr) => { pub struct $name<'a> { buffer: $typ, idx: usize, n_memory: usize, } impl<'a> fmt::Debug for $name<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct(stringify!($name)) .field("buffer", &self.buffer) .field("idx", &self.idx) .field("n_memory", &self.n_memory) .finish() } } impl<'a> $name<'a> { fn new(buffer: $typ) -> $name<'a> { skip_assert_initialized!(); let n_memory = buffer.n_memory(); $name { buffer, idx: 0, n_memory, } } } #[allow(clippy::redundant_closure_call)] impl<'a> Iterator for $name<'a> { type Item = $mtyp; fn next(&mut self) -> Option { if self.idx >= self.n_memory { return None; } #[allow(unused_unsafe)] unsafe { let item = $get_item(self.buffer, self.idx).unwrap(); self.idx += 1; Some(item) } } fn size_hint(&self) -> (usize, Option) { let remaining = self.n_memory - self.idx; (remaining, Some(remaining)) } fn count(self) -> usize { self.n_memory - self.idx } fn nth(&mut self, n: usize) -> Option { let (end, overflow) = self.idx.overflowing_add(n); if end >= self.n_memory || overflow { self.idx = self.n_memory; None } else { #[allow(unused_unsafe)] unsafe { self.idx = end + 1; Some($get_item(self.buffer, end).unwrap()) } } } fn last(self) -> Option { if self.idx == self.n_memory { None } else { #[allow(unused_unsafe)] unsafe { Some($get_item(self.buffer, self.n_memory - 1).unwrap()) } } } } #[allow(clippy::redundant_closure_call)] impl<'a> DoubleEndedIterator for $name<'a> { fn next_back(&mut self) -> Option { if self.idx == self.n_memory { return None; } #[allow(unused_unsafe)] unsafe { self.n_memory -= 1; Some($get_item(self.buffer, self.n_memory).unwrap()) } } fn nth_back(&mut self, n: usize) -> Option { let (end, overflow) = self.n_memory.overflowing_sub(n); if end <= self.idx || overflow { self.idx = self.n_memory; None } else { #[allow(unused_unsafe)] unsafe { self.n_memory = end - 1; Some($get_item(self.buffer, self.n_memory).unwrap()) } } } } impl<'a> ExactSizeIterator for $name<'a> {} impl<'a> std::iter::FusedIterator for $name<'a> {} } ); define_iter!( Iter, &'a BufferRef, &'a MemoryRef, |buffer: &BufferRef, idx| { let ptr = ffi::gst_buffer_peek_memory(buffer.as_mut_ptr(), idx as u32); if ptr.is_null() { None } else { Some(MemoryRef::from_ptr(ptr as *const ffi::GstMemory)) } } ); define_iter!( IterMut, &'a mut BufferRef, &'a mut MemoryRef, |buffer: &mut BufferRef, idx| { let ptr = ffi::gst_buffer_peek_memory(buffer.as_mut_ptr(), idx as u32); if ptr.is_null() { None } else { Some(MemoryRef::from_mut_ptr(ptr)) } } ); impl<'a> IntoIterator for &'a BufferRef { type IntoIter = Iter<'a>; type Item = &'a MemoryRef; fn into_iter(self) -> Self::IntoIter { self.iter_memories() } } impl From for Buffer { fn from(value: Memory) -> Self { skip_assert_initialized!(); let mut buffer = Buffer::new(); { let buffer = buffer.get_mut().unwrap(); buffer.append_memory(value); } buffer } } impl From<[Memory; N]> for Buffer { fn from(value: [Memory; N]) -> Self { skip_assert_initialized!(); let mut buffer = Buffer::new(); { let buffer = buffer.get_mut().unwrap(); value.into_iter().for_each(|b| buffer.append_memory(b)); } buffer } } impl std::iter::FromIterator for Buffer { fn from_iter>(iter: T) -> Self { skip_assert_initialized!(); let iter = iter.into_iter(); let mut buffer = Buffer::new(); { let buffer = buffer.get_mut().unwrap(); iter.for_each(|m| buffer.append_memory(m)); } buffer } } impl std::iter::Extend for BufferRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|m| self.append_memory(m)); } } define_iter!( IterOwned, &'a BufferRef, Memory, |buffer: &BufferRef, idx| { buffer.memory(idx) } ); impl fmt::Debug for Buffer { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { BufferRef::fmt(self, f) } } impl PartialEq for Buffer { fn eq(&self, other: &Buffer) -> bool { BufferRef::eq(self, other) } } impl Eq for Buffer {} impl PartialEq for Buffer { fn eq(&self, other: &BufferRef) -> bool { BufferRef::eq(self, other) } } impl PartialEq for BufferRef { fn eq(&self, other: &Buffer) -> bool { BufferRef::eq(other, self) } } impl fmt::Debug for BufferRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use std::cell::RefCell; use crate::utils::Displayable; struct DebugIter(RefCell); impl fmt::Debug for DebugIter where I::Item: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_list().entries(&mut *self.0.borrow_mut()).finish() } } f.debug_struct("Buffer") .field("ptr", &self.as_ptr()) .field("pts", &self.pts().display()) .field("dts", &self.dts().display()) .field("duration", &self.duration().display()) .field("size", &self.size()) .field("offset", &self.offset()) .field("offset_end", &self.offset_end()) .field("flags", &self.flags()) .field( "metas", &DebugIter(RefCell::new( self.iter_meta::().map(|m| m.api()), )), ) .finish() } } impl PartialEq for BufferRef { fn eq(&self, other: &BufferRef) -> bool { if self.size() != other.size() { return false; } let self_map = self.map_readable(); let other_map = other.map_readable(); match (self_map, other_map) { (Ok(self_map), Ok(other_map)) => self_map.as_slice().eq(other_map.as_slice()), _ => false, } } } impl Eq for BufferRef {} impl BufferMap<'_, T> { #[doc(alias = "get_size")] #[inline] pub fn size(&self) -> usize { self.map_info.size } #[doc(alias = "get_buffer")] #[inline] pub fn buffer(&self) -> &BufferRef { self.buffer } #[inline] pub fn as_slice(&self) -> &[u8] { if self.map_info.size == 0 { return &[]; } unsafe { slice::from_raw_parts(self.map_info.data, self.map_info.size) } } } impl BufferMap<'_, Writable> { #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { if self.map_info.size == 0 { return &mut []; } unsafe { slice::from_raw_parts_mut(self.map_info.data, self.map_info.size) } } } impl AsRef<[u8]> for BufferMap<'_, T> { #[inline] fn as_ref(&self) -> &[u8] { self.as_slice() } } impl AsMut<[u8]> for BufferMap<'_, Writable> { #[inline] fn as_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl ops::Deref for BufferMap<'_, T> { type Target = [u8]; #[inline] fn deref(&self) -> &[u8] { self.as_slice() } } impl ops::DerefMut for BufferMap<'_, Writable> { #[inline] fn deref_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl fmt::Debug for BufferMap<'_, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("BufferMap").field(&self.buffer()).finish() } } impl<'a, T> PartialEq for BufferMap<'a, T> { fn eq(&self, other: &BufferMap<'a, T>) -> bool { self.as_slice().eq(other.as_slice()) } } impl Eq for BufferMap<'_, T> {} impl Drop for BufferMap<'_, T> { #[inline] fn drop(&mut self) { unsafe { ffi::gst_buffer_unmap(self.buffer.as_mut_ptr(), &mut self.map_info); } } } unsafe impl Send for BufferMap<'_, T> {} unsafe impl Sync for BufferMap<'_, T> {} impl MappedBuffer { #[inline] pub fn as_slice(&self) -> &[u8] { if self.map_info.size == 0 { return &[]; } unsafe { slice::from_raw_parts(self.map_info.data, self.map_info.size) } } #[doc(alias = "get_size")] #[inline] pub fn size(&self) -> usize { self.map_info.size } #[doc(alias = "get_buffer")] #[inline] pub fn buffer(&self) -> &BufferRef { self.buffer.as_ref() } #[inline] pub fn into_buffer(self) -> Buffer { let mut s = mem::ManuallyDrop::new(self); let buffer = unsafe { ptr::read(&s.buffer) }; unsafe { ffi::gst_buffer_unmap(buffer.as_mut_ptr(), &mut s.map_info); } buffer } } impl MappedBuffer { #[doc(alias = "get_buffer")] #[inline] pub fn buffer_owned(&self) -> Buffer { self.buffer.clone() } } impl MappedBuffer { #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { if self.map_info.size == 0 { return &mut []; } unsafe { slice::from_raw_parts_mut(self.map_info.data, self.map_info.size) } } } impl AsRef<[u8]> for MappedBuffer { #[inline] fn as_ref(&self) -> &[u8] { self.as_slice() } } impl AsMut<[u8]> for MappedBuffer { #[inline] fn as_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl ops::Deref for MappedBuffer { type Target = [u8]; #[inline] fn deref(&self) -> &[u8] { self.as_slice() } } impl ops::DerefMut for MappedBuffer { #[inline] fn deref_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl Drop for MappedBuffer { #[inline] fn drop(&mut self) { unsafe { ffi::gst_buffer_unmap(self.buffer.as_mut_ptr(), &mut self.map_info); } } } impl fmt::Debug for MappedBuffer { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("MappedBuffer").field(&self.buffer()).finish() } } impl PartialEq for MappedBuffer { fn eq(&self, other: &MappedBuffer) -> bool { self.as_slice().eq(other.as_slice()) } } impl Eq for MappedBuffer {} unsafe impl Send for MappedBuffer {} unsafe impl Sync for MappedBuffer {} #[doc(alias = "GST_BUFFER_COPY_METADATA")] pub const BUFFER_COPY_METADATA: crate::BufferCopyFlags = crate::BufferCopyFlags::from_bits_truncate(ffi::GST_BUFFER_COPY_METADATA); #[doc(alias = "GST_BUFFER_COPY_ALL")] pub const BUFFER_COPY_ALL: crate::BufferCopyFlags = crate::BufferCopyFlags::from_bits_truncate(ffi::GST_BUFFER_COPY_ALL); pub struct Dump<'a> { buffer: &'a BufferRef, start: Bound, end: Bound, } struct BufferChunked16Iter<'a> { buffer: &'a BufferRef, mem_idx: usize, mem_len: usize, map: Option>, map_offset: usize, len: usize, } impl Iterator for BufferChunked16Iter<'_> { // FIXME: Return a `&'self [u8]` once there's some GAT iterator trait type Item = ([u8; 16], usize); fn next(&mut self) -> Option { if self.mem_idx == self.mem_len || self.len == 0 { return None; } let mut item = [0u8; 16]; let mut data = item.as_mut_slice(); while !data.is_empty() && self.mem_idx < self.mem_len && self.len > 0 { if self.map.is_none() { let mem = self.buffer.peek_memory(self.mem_idx); self.map = Some(mem.map_readable().expect("failed to map memory")); } let map = self.map.as_ref().unwrap(); debug_assert!(self.map_offset < map.len()); let copy = cmp::min(cmp::min(map.len() - self.map_offset, data.len()), self.len); data[..copy].copy_from_slice(&map[self.map_offset..][..copy]); self.map_offset += copy; self.len -= copy; data = &mut data[copy..]; if self.map_offset == map.len() { self.map = None; self.map_offset = 0; self.mem_idx += 1; } } let copied = 16 - data.len(); Some((item, copied)) } } impl Dump<'_> { fn fmt(&self, f: &mut fmt::Formatter, debug: bool) -> fmt::Result { let n_memory = self.buffer.n_memory(); if n_memory == 0 { write!(f, "")?; return Ok(()); } use std::fmt::Write; let len = self.buffer.size(); // Kind of re-implementation of slice indexing to allow handling out of range values better // with specific output strings let mut start_idx = match self.start { Bound::Included(idx) if idx >= len => { write!(f, "")?; return Ok(()); } Bound::Excluded(idx) if idx.checked_add(1).map_or(true, |idx| idx >= len) => { write!(f, "")?; return Ok(()); } Bound::Included(idx) => idx, Bound::Excluded(idx) => idx + 1, Bound::Unbounded => 0, }; let end_idx = match self.end { Bound::Included(idx) if idx.checked_add(1).map_or(true, |idx| idx > len) => { write!(f, "")?; return Ok(()); } Bound::Excluded(idx) if idx > len => { write!(f, "")?; return Ok(()); } Bound::Included(idx) => idx + 1, Bound::Excluded(idx) => idx, Bound::Unbounded => len, }; if start_idx >= end_idx { write!(f, "")?; return Ok(()); } // This can't really fail because of the above let (memory_range, skip) = self .buffer .find_memory(start_idx..) .expect("can't find memory"); let chunks = BufferChunked16Iter { buffer: self.buffer, mem_idx: memory_range.start, mem_len: n_memory, map: None, map_offset: skip, len: end_idx - start_idx, }; if debug { for (line, line_len) in chunks { let line = &line[..line_len]; match end_idx { 0x00_00..=0xff_ff => write!(f, "{:04x}: ", start_idx)?, 0x01_00_00..=0xff_ff_ff => write!(f, "{:06x}: ", start_idx)?, 0x01_00_00_00..=0xff_ff_ff_ff => write!(f, "{:08x}: ", start_idx)?, _ => write!(f, "{:016x}: ", start_idx)?, } for (i, v) in line.iter().enumerate() { if i > 0 { write!(f, " {:02x}", v)?; } else { write!(f, "{:02x}", v)?; } } for _ in line.len()..16 { write!(f, " ")?; } write!(f, " ")?; for v in line { if v.is_ascii() && !v.is_ascii_control() { f.write_char((*v).into())?; } else { f.write_char('.')?; } } start_idx = start_idx.saturating_add(16); if start_idx < end_idx { writeln!(f)?; } } Ok(()) } else { for (line, line_len) in chunks { let line = &line[..line_len]; for (i, v) in line.iter().enumerate() { if i > 0 { write!(f, " {:02x}", v)?; } else { write!(f, "{:02x}", v)?; } } start_idx = start_idx.saturating_add(16); if start_idx < end_idx { writeln!(f)?; } } Ok(()) } } } impl fmt::Display for Dump<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.fmt(f, false) } } impl fmt::Debug for Dump<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt(f, true) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_fields() { crate::init().unwrap(); let mut buffer = Buffer::new(); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(ClockTime::NSECOND); buffer.set_dts(2 * ClockTime::NSECOND); buffer.set_offset(3); buffer.set_offset_end(4); buffer.set_duration(Some(5 * ClockTime::NSECOND)); } assert_eq!(buffer.pts(), Some(ClockTime::NSECOND)); assert_eq!(buffer.dts(), Some(2 * ClockTime::NSECOND)); assert_eq!(buffer.offset(), 3); assert_eq!(buffer.offset_end(), 4); assert_eq!(buffer.duration(), Some(5 * ClockTime::NSECOND)); } #[test] fn test_writability() { crate::init().unwrap(); let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); } assert_ne!(buffer.get_mut(), None); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(Some(ClockTime::NSECOND)); } let mut buffer2 = buffer.clone(); assert_eq!(buffer.get_mut(), None); assert_eq!(buffer2.as_ptr(), buffer.as_ptr()); { let buffer2 = buffer2.make_mut(); assert_ne!(buffer2.as_ptr(), buffer.as_ptr()); buffer2.set_pts(Some(2 * ClockTime::NSECOND)); let mut data = buffer2.map_writable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); data.as_mut_slice()[0] = 0; } assert_eq!(buffer.pts(), Some(ClockTime::NSECOND)); assert_eq!(buffer2.pts(), Some(2 * ClockTime::NSECOND)); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); let data = buffer2.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![0, 2, 3, 4].as_slice()); } } #[test] #[allow(clippy::cognitive_complexity)] fn test_memories() { crate::init().unwrap(); let mut buffer = Buffer::new(); { let buffer = buffer.get_mut().unwrap(); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 10])); } assert!(buffer.is_all_memory_writable()); assert_eq!(buffer.n_memory(), 5); assert_eq!(buffer.size(), 30); for i in 0..5 { { let mem = buffer.memory(i).unwrap(); assert_eq!(mem.size(), if i < 4 { 5 } else { 10 }); let map = mem.map_readable().unwrap(); assert_eq!(map.size(), if i < 4 { 5 } else { 10 }); } { let mem = buffer.peek_memory(i); assert_eq!(mem.size(), if i < 4 { 5 } else { 10 }); let map = mem.map_readable().unwrap(); assert_eq!(map.size(), if i < 4 { 5 } else { 10 }); } { let buffer = buffer.get_mut().unwrap(); let mem = buffer.peek_memory_mut(i).unwrap(); assert_eq!(mem.size(), if i < 4 { 5 } else { 10 }); let map = mem.map_writable().unwrap(); assert_eq!(map.size(), if i < 4 { 5 } else { 10 }); } } { let buffer = buffer.get_mut().unwrap(); let mut last = 0; for (i, mem) in buffer.iter_memories_mut().unwrap().enumerate() { { assert_eq!(mem.size(), if i < 4 { 5 } else { 10 }); let map = mem.map_readable().unwrap(); assert_eq!(map.size(), if i < 4 { 5 } else { 10 }); } { assert_eq!(mem.size(), if i < 4 { 5 } else { 10 }); let map = mem.map_readable().unwrap(); assert_eq!(map.size(), if i < 4 { 5 } else { 10 }); } { assert_eq!(mem.size(), if i < 4 { 5 } else { 10 }); let map = mem.map_writable().unwrap(); assert_eq!(map.size(), if i < 4 { 5 } else { 10 }); } last = i; } assert_eq!(last, 4); } let mut last = 0; for (i, mem) in buffer.iter_memories().enumerate() { { assert_eq!(mem.size(), if i < 4 { 5 } else { 10 }); let map = mem.map_readable().unwrap(); assert_eq!(map.size(), if i < 4 { 5 } else { 10 }); } { assert_eq!(mem.size(), if i < 4 { 5 } else { 10 }); let map = mem.map_readable().unwrap(); assert_eq!(map.size(), if i < 4 { 5 } else { 10 }); } last = i; } assert_eq!(last, 4); let mut last = 0; for (i, mem) in buffer.iter_memories_owned().enumerate() { { assert_eq!(mem.size(), if i < 4 { 5 } else { 10 }); let map = mem.map_readable().unwrap(); assert_eq!(map.size(), if i < 4 { 5 } else { 10 }); } { assert_eq!(mem.size(), if i < 4 { 5 } else { 10 }); let map = mem.map_readable().unwrap(); assert_eq!(map.size(), if i < 4 { 5 } else { 10 }); } last = i; } assert_eq!(last, 4); } #[test] fn test_meta_foreach() { crate::init().unwrap(); let mut buffer = Buffer::new(); { let buffer = buffer.get_mut().unwrap(); crate::ReferenceTimestampMeta::add( buffer, &crate::Caps::builder("foo/bar").build(), ClockTime::ZERO, ClockTime::NONE, ); crate::ReferenceTimestampMeta::add( buffer, &crate::Caps::builder("foo/bar").build(), ClockTime::SECOND, ClockTime::NONE, ); } let mut res = vec![]; buffer.foreach_meta(|meta| { let meta = meta .downcast_ref::() .unwrap(); res.push(meta.timestamp()); ControlFlow::Continue(()) }); assert_eq!(&[ClockTime::ZERO, ClockTime::SECOND][..], &res[..]); } #[test] fn test_meta_foreach_mut() { crate::init().unwrap(); let mut buffer = Buffer::new(); { let buffer = buffer.get_mut().unwrap(); crate::ReferenceTimestampMeta::add( buffer, &crate::Caps::builder("foo/bar").build(), ClockTime::ZERO, ClockTime::NONE, ); crate::ReferenceTimestampMeta::add( buffer, &crate::Caps::builder("foo/bar").build(), ClockTime::SECOND, ClockTime::NONE, ); } let mut res = vec![]; buffer.get_mut().unwrap().foreach_meta_mut(|mut meta| { let meta = meta .downcast_ref::() .unwrap(); res.push(meta.timestamp()); if meta.timestamp() == ClockTime::SECOND { ControlFlow::Continue(BufferMetaForeachAction::Remove) } else { ControlFlow::Continue(BufferMetaForeachAction::Keep) } }); assert_eq!(&[ClockTime::ZERO, ClockTime::SECOND][..], &res[..]); let mut res = vec![]; buffer.foreach_meta(|meta| { let meta = meta .downcast_ref::() .unwrap(); res.push(meta.timestamp()); ControlFlow::Continue(()) }); assert_eq!(&[ClockTime::ZERO][..], &res[..]); } #[test] fn test_ptr_eq() { crate::init().unwrap(); let buffer1 = Buffer::new(); assert!(BufferRef::ptr_eq(&buffer1, &buffer1)); let buffer2 = Buffer::new(); assert!(!BufferRef::ptr_eq(&buffer1, &buffer2)); } #[test] fn test_copy_region() { crate::init().unwrap(); let buffer1 = Buffer::from_mut_slice(vec![0, 1, 2, 3, 4, 5, 6, 7]); let buffer2 = buffer1.copy_region(BUFFER_COPY_ALL, ..).unwrap(); assert_eq!( buffer2.map_readable().unwrap().as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7] ); let buffer2 = buffer1.copy_region(BUFFER_COPY_ALL, 0..8).unwrap(); assert_eq!( buffer2.map_readable().unwrap().as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7] ); let buffer2 = buffer1.copy_region(BUFFER_COPY_ALL, 0..=7).unwrap(); assert_eq!( buffer2.map_readable().unwrap().as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7] ); let buffer2 = buffer1.copy_region(BUFFER_COPY_ALL, ..=7).unwrap(); assert_eq!( buffer2.map_readable().unwrap().as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7] ); let buffer2 = buffer1.copy_region(BUFFER_COPY_ALL, ..8).unwrap(); assert_eq!( buffer2.map_readable().unwrap().as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7] ); let buffer2 = buffer1.copy_region(BUFFER_COPY_ALL, 0..).unwrap(); assert_eq!( buffer2.map_readable().unwrap().as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7] ); assert!(buffer1.copy_region(BUFFER_COPY_ALL, 0..=8).is_err()); assert!(buffer1.copy_region(BUFFER_COPY_ALL, 0..=10).is_err()); assert!(buffer1.copy_region(BUFFER_COPY_ALL, 8..=10).is_err()); assert!(buffer1.copy_region(BUFFER_COPY_ALL, 8..=8).is_err()); assert!(buffer1.copy_region(BUFFER_COPY_ALL, 10..).is_err()); assert!(buffer1.copy_region(BUFFER_COPY_ALL, 10..100).is_err()); let buffer2 = buffer1.copy_region(BUFFER_COPY_ALL, 2..4).unwrap(); assert_eq!(buffer2.map_readable().unwrap().as_slice(), &[2, 3]); let buffer2 = buffer1.copy_region(BUFFER_COPY_ALL, 2..=4).unwrap(); assert_eq!(buffer2.map_readable().unwrap().as_slice(), &[2, 3, 4]); let buffer2 = buffer1.copy_region(BUFFER_COPY_ALL, 2..).unwrap(); assert_eq!( buffer2.map_readable().unwrap().as_slice(), &[2, 3, 4, 5, 6, 7] ); let buffer2 = buffer1.copy_region(BUFFER_COPY_ALL, ..2).unwrap(); assert_eq!(buffer2.map_readable().unwrap().as_slice(), &[0, 1]); let buffer2 = buffer1.copy_region(BUFFER_COPY_ALL, ..=2).unwrap(); assert_eq!(buffer2.map_readable().unwrap().as_slice(), &[0, 1, 2]); } #[test] fn test_dump() { use std::fmt::Write; crate::init().unwrap(); let mut s = String::new(); let buffer = crate::Buffer::from_slice(vec![1, 2, 3, 4]); write!(&mut s, "{:?}", buffer.dump()).unwrap(); assert_eq!( s, "0000: 01 02 03 04 ...." ); s.clear(); write!(&mut s, "{}", buffer.dump()).unwrap(); assert_eq!(s, "01 02 03 04"); s.clear(); let buffer = crate::Buffer::from_slice(vec![1, 2, 3, 4]); write!(&mut s, "{:?}", buffer.dump_range(..)).unwrap(); assert_eq!( s, "0000: 01 02 03 04 ...." ); s.clear(); write!(&mut s, "{:?}", buffer.dump_range(..2)).unwrap(); assert_eq!( s, "0000: 01 02 .." ); s.clear(); write!(&mut s, "{:?}", buffer.dump_range(2..=3)).unwrap(); assert_eq!( s, "0002: 03 04 .." ); s.clear(); write!(&mut s, "{:?}", buffer.dump_range(..100)).unwrap(); assert_eq!(s, "",); s.clear(); write!(&mut s, "{:?}", buffer.dump_range(90..100)).unwrap(); assert_eq!(s, "",); s.clear(); let buffer = crate::Buffer::from_slice(vec![0; 19]); write!(&mut s, "{:?}", buffer.dump()).unwrap(); assert_eq!( s, "0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\n\ 0010: 00 00 00 ..." ); s.clear(); } #[test] fn test_dump_multi_memories() { use std::fmt::Write; crate::init().unwrap(); let mut buffer = crate::Buffer::new(); { let buffer = buffer.get_mut().unwrap(); let mem = crate::Memory::from_slice(vec![1, 2, 3, 4]); buffer.append_memory(mem); let mem = crate::Memory::from_slice(vec![5, 6, 7, 8]); buffer.append_memory(mem); let mem = crate::Memory::from_slice(vec![9, 10, 11, 12]); buffer.append_memory(mem); let mem = crate::Memory::from_slice(vec![13, 14, 15, 16]); buffer.append_memory(mem); let mem = crate::Memory::from_slice(vec![17, 18, 19]); buffer.append_memory(mem); } let mut s = String::new(); write!(&mut s, "{:?}", buffer.dump()).unwrap(); assert_eq!( s, "0000: 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 ................\n\ 0010: 11 12 13 ..." ); s.clear(); write!(&mut s, "{}", buffer.dump()).unwrap(); assert_eq!( s, "01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10\n11 12 13" ); s.clear(); write!(&mut s, "{:?}", buffer.dump_range(2..)).unwrap(); assert_eq!( s, "0002: 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 ................\n\ 0012: 13 ." ); s.clear(); write!(&mut s, "{:?}", buffer.dump_range(14..17)).unwrap(); assert_eq!( s, "000e: 0f 10 11 ..." ); s.clear(); write!(&mut s, "{:?}", buffer.dump_range(14..20)).unwrap(); assert_eq!(s, ""); s.clear(); #[allow(clippy::reversed_empty_ranges)] { write!(&mut s, "{:?}", buffer.dump_range(23..20)).unwrap(); assert_eq!(s, ""); s.clear(); } } } gstreamer-0.23.5/src/buffer_cursor.rs000064400000000000000000000520171046102023000157140ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{fmt, io, marker::PhantomData, mem, ptr}; use crate::{ buffer::{Readable, Writable}, ffi, Buffer, BufferRef, }; pub struct BufferCursor { buffer: Option, size: u64, num_mem: usize, cur_mem_idx: usize, cur_offset: u64, cur_mem_offset: usize, map_info: ffi::GstMapInfo, phantom: PhantomData, } pub struct BufferRefCursor { buffer: T, size: u64, num_mem: usize, cur_mem_idx: usize, cur_offset: u64, cur_mem_offset: usize, map_info: ffi::GstMapInfo, } macro_rules! define_seek_impl( ($get_buffer_ref:expr) => { fn seek(&mut self, pos: io::SeekFrom) -> Result { match pos { io::SeekFrom::Start(off) => { self.cur_offset = std::cmp::min(self.size, off); } io::SeekFrom::End(off) if off <= 0 => { self.cur_offset = self.size; } io::SeekFrom::End(off) => { self.cur_offset = self.size.checked_sub(off as u64).ok_or_else(|| { io::Error::new(io::ErrorKind::InvalidInput, "Seek before start of buffer") })?; } io::SeekFrom::Current(std::i64::MIN) => { return Err(io::Error::new( io::ErrorKind::InvalidInput, "Seek before start of buffer", )); } io::SeekFrom::Current(off) => { if off <= 0 { self.cur_offset = self.cur_offset.checked_sub((-off) as u64).ok_or_else(|| { io::Error::new( io::ErrorKind::InvalidInput, "Seek before start of buffer", ) })?; } else { self.cur_offset = std::cmp::min( self.size, self.cur_offset.checked_add(off as u64).unwrap_or(self.size), ); } } } // Work around lifetime annotation issues with closures let buffer_ref: fn(&Self) -> &BufferRef = $get_buffer_ref; let (range, skip) = buffer_ref(self) .find_memory(self.cur_offset as usize..) .expect("Failed to find memory"); if range.start != self.cur_mem_idx && !self.map_info.memory.is_null() { unsafe { ffi::gst_memory_unmap(self.map_info.memory, &mut self.map_info); self.map_info.memory = ptr::null_mut(); } } self.cur_mem_idx = range.start; self.cur_mem_offset = skip; Ok(self.cur_offset) } // Once stabilized // fn stream_len(&mut self) -> Result { // Ok(self.size) // } // // fn stream_position(&mut self) -> Result { // Ok(self.current_offset) // } } ); macro_rules! define_read_write_fn_impl( ($self:ident, $data:ident, $data_type:ty, $get_buffer_ref:expr, $map_flags:path, $copy:expr, $split:expr) => { #[allow(clippy::redundant_closure_call)] { let mut copied = 0; while !$data.is_empty() && $self.cur_mem_idx < $self.num_mem { // Map memory if needed. cur_mem_idx, cur_mem_offset and cur_offset are required to be // set correctly here already (from constructor, seek and the bottom of the loop) if $self.map_info.memory.is_null() { unsafe { // Work around lifetime annotation issues with closures let buffer_ref: fn(&Self) -> &BufferRef = $get_buffer_ref; let memory = ffi::gst_buffer_peek_memory( buffer_ref($self).as_mut_ptr(), $self.cur_mem_idx as u32, ); debug_assert!(!memory.is_null()); if ffi::gst_memory_map(memory, &mut $self.map_info, $map_flags) == glib::ffi::GFALSE { return Err(io::Error::new( io::ErrorKind::InvalidData, "Failed to map memory readable", )); } } debug_assert!($self.cur_mem_offset < $self.map_info.size); } debug_assert!(!$self.map_info.memory.is_null()); // Copy all data we can currently copy let data_left = $self.map_info.size - $self.cur_mem_offset; let to_copy = std::cmp::min($data.len(), data_left); $copy(&$self.map_info, $self.cur_mem_offset, $data, to_copy); copied += to_copy; $self.cur_offset += to_copy as u64; $self.cur_mem_offset += to_copy; // Work around lifetime annotation issues with closures let split: fn($data_type, usize) -> $data_type = $split; #[allow(clippy::redundant_closure_call)] { $data = split($data, to_copy); } // If we're at the end of the current memory, unmap and advance to the next memory if $self.cur_mem_offset == $self.map_info.size { unsafe { ffi::gst_memory_unmap($self.map_info.memory, &mut $self.map_info); } $self.map_info.memory = ptr::null_mut(); $self.cur_mem_idx += 1; $self.cur_mem_offset = 0; } } Ok(copied) }} ); macro_rules! define_read_impl( ($get_buffer_ref:expr) => { fn read(&mut self, mut data: &mut [u8]) -> Result { define_read_write_fn_impl!( self, data, &mut [u8], $get_buffer_ref, ffi::GST_MAP_READ, |map_info: &ffi::GstMapInfo, off, data: &mut [u8], to_copy| unsafe { ptr::copy_nonoverlapping( (map_info.data as *const u8).add(off), data.as_mut_ptr(), to_copy, ); }, |data, to_copy| &mut data[to_copy..] ) } } ); macro_rules! define_write_impl( ($get_buffer_ref:expr) => { fn write(&mut self, mut data: &[u8]) -> Result { define_read_write_fn_impl!( self, data, &[u8], $get_buffer_ref, ffi::GST_MAP_WRITE, |map_info: &ffi::GstMapInfo, off, data: &[u8], to_copy| unsafe { ptr::copy_nonoverlapping( data.as_ptr(), (map_info.data as *mut u8).add(off), to_copy, ); }, |data, to_copy| &data[to_copy..] ) } fn flush(&mut self) -> Result<(), io::Error> { if !self.map_info.memory.is_null() { unsafe { ffi::gst_memory_unmap(self.map_info.memory, &mut self.map_info); self.map_info.memory = ptr::null_mut(); } } Ok(()) } } ); impl fmt::Debug for BufferCursor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("BufferCursor") .field("buffer", &self.buffer) .field("size", &self.size) .field("num_mem", &self.num_mem) .field("cur_mem_idx", &self.cur_mem_idx) .field("cur_offset", &self.cur_offset) .field("cur_mem_offset", &self.cur_mem_offset) .field("map_info", &self.map_info) .finish() } } impl Drop for BufferCursor { fn drop(&mut self) { if !self.map_info.memory.is_null() { unsafe { ffi::gst_memory_unmap(self.map_info.memory, &mut self.map_info); } } } } impl io::Read for BufferCursor { define_read_impl!(|s| s.buffer.as_ref().unwrap()); } impl io::Write for BufferCursor { define_write_impl!(|s| s.buffer.as_ref().unwrap()); } impl io::Seek for BufferCursor { define_seek_impl!(|s| s.buffer.as_ref().unwrap()); } impl BufferCursor { pub fn stream_len(&mut self) -> Result { Ok(self.size) } pub fn stream_position(&mut self) -> Result { Ok(self.cur_offset) } #[doc(alias = "get_buffer")] pub fn buffer(&self) -> &BufferRef { self.buffer.as_ref().unwrap().as_ref() } pub fn into_buffer(mut self) -> Buffer { self.buffer.take().unwrap() } } impl BufferCursor { pub(crate) fn new_readable(buffer: Buffer) -> BufferCursor { skip_assert_initialized!(); let size = buffer.size() as u64; let num_mem = buffer.n_memory(); BufferCursor { buffer: Some(buffer), size, num_mem, cur_mem_idx: 0, cur_offset: 0, cur_mem_offset: 0, map_info: unsafe { mem::zeroed() }, phantom: PhantomData, } } pub fn buffer_owned(&self) -> Buffer { self.buffer.as_ref().unwrap().clone() } } impl BufferCursor { pub(crate) fn new_writable(buffer: Buffer) -> Result, glib::BoolError> { skip_assert_initialized!(); if !buffer.is_writable() || !buffer.is_all_memory_writable() { return Err(glib::bool_error!("Not all memories are writable")); } let size = buffer.size() as u64; let num_mem = buffer.n_memory(); Ok(BufferCursor { buffer: Some(buffer), size, num_mem, cur_mem_idx: 0, cur_offset: 0, cur_mem_offset: 0, map_info: unsafe { mem::zeroed() }, phantom: PhantomData, }) } } unsafe impl Send for BufferCursor {} unsafe impl Sync for BufferCursor {} impl fmt::Debug for BufferRefCursor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("BufferRefCursor") .field("buffer", &self.buffer) .field("size", &self.size) .field("num_mem", &self.num_mem) .field("cur_mem_idx", &self.cur_mem_idx) .field("cur_offset", &self.cur_offset) .field("cur_mem_offset", &self.cur_mem_offset) .field("map_info", &self.map_info) .finish() } } impl Drop for BufferRefCursor { fn drop(&mut self) { if !self.map_info.memory.is_null() { unsafe { ffi::gst_memory_unmap(self.map_info.memory, &mut self.map_info); } } } } impl io::Read for BufferRefCursor<&BufferRef> { define_read_impl!(|s| s.buffer); } impl io::Write for BufferRefCursor<&mut BufferRef> { define_write_impl!(|s| s.buffer); } impl io::Seek for BufferRefCursor<&BufferRef> { define_seek_impl!(|s| s.buffer); } impl io::Seek for BufferRefCursor<&mut BufferRef> { define_seek_impl!(|s| s.buffer); } impl BufferRefCursor { pub fn stream_len(&mut self) -> Result { Ok(self.size) } pub fn stream_position(&mut self) -> Result { Ok(self.cur_offset) } } impl<'a> BufferRefCursor<&'a BufferRef> { #[doc(alias = "get_buffer")] pub fn buffer(&self) -> &BufferRef { self.buffer } pub(crate) fn new_readable(buffer: &'a BufferRef) -> BufferRefCursor<&'a BufferRef> { skip_assert_initialized!(); let size = buffer.size() as u64; let num_mem = buffer.n_memory(); BufferRefCursor { buffer, size, num_mem, cur_mem_idx: 0, cur_offset: 0, cur_mem_offset: 0, map_info: unsafe { mem::zeroed() }, } } } impl<'a> BufferRefCursor<&'a mut BufferRef> { #[doc(alias = "get_buffer")] pub fn buffer(&self) -> &BufferRef { self.buffer } pub(crate) fn new_writable( buffer: &'a mut BufferRef, ) -> Result, glib::BoolError> { skip_assert_initialized!(); if !buffer.is_all_memory_writable() { return Err(glib::bool_error!("Not all memories are writable")); } let size = buffer.size() as u64; let num_mem = buffer.n_memory(); Ok(BufferRefCursor { buffer, size, num_mem, cur_mem_idx: 0, cur_offset: 0, cur_mem_offset: 0, map_info: unsafe { mem::zeroed() }, }) } } unsafe impl Send for BufferRefCursor {} unsafe impl Sync for BufferRefCursor {} #[cfg(test)] mod tests { use super::*; #[test] #[allow(clippy::cognitive_complexity)] fn test_buffer_cursor() { use std::io::{self, Read, Seek, Write}; crate::init().unwrap(); let mut buffer = Buffer::new(); { let buffer = buffer.get_mut().unwrap(); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 10])); } assert!(buffer.is_all_memory_writable()); assert_eq!(buffer.n_memory(), 5); assert_eq!(buffer.size(), 30); let mut cursor = buffer.into_cursor_writable().unwrap(); assert_eq!(cursor.stream_position().unwrap(), 0); cursor.write_all(b"01234567").unwrap(); assert_eq!(cursor.stream_position().unwrap(), 8); cursor.write_all(b"890123").unwrap(); assert_eq!(cursor.stream_position().unwrap(), 14); cursor.write_all(b"456").unwrap(); assert_eq!(cursor.stream_position().unwrap(), 17); cursor.write_all(b"78901234567").unwrap(); assert_eq!(cursor.stream_position().unwrap(), 28); cursor.write_all(b"89").unwrap(); assert_eq!(cursor.stream_position().unwrap(), 30); assert!(cursor.write_all(b"0").is_err()); assert_eq!(cursor.seek(io::SeekFrom::Start(5)).unwrap(), 5); assert_eq!(cursor.stream_position().unwrap(), 5); cursor.write_all(b"A").unwrap(); assert_eq!(cursor.seek(io::SeekFrom::End(5)).unwrap(), 25); assert_eq!(cursor.stream_position().unwrap(), 25); cursor.write_all(b"B").unwrap(); assert_eq!(cursor.seek(io::SeekFrom::Current(-1)).unwrap(), 25); assert_eq!(cursor.stream_position().unwrap(), 25); cursor.write_all(b"C").unwrap(); assert_eq!(cursor.seek(io::SeekFrom::Current(1)).unwrap(), 27); assert_eq!(cursor.stream_position().unwrap(), 27); cursor.write_all(b"D").unwrap(); let buffer = cursor.into_buffer(); let mut cursor = buffer.into_cursor_readable(); let mut data = [0; 30]; assert_eq!(cursor.stream_position().unwrap(), 0); cursor.read_exact(&mut data[0..7]).unwrap(); assert_eq!(cursor.stream_position().unwrap(), 7); assert_eq!(&data[0..7], b"01234A6"); cursor.read_exact(&mut data[0..5]).unwrap(); assert_eq!(cursor.stream_position().unwrap(), 12); assert_eq!(&data[0..5], b"78901"); cursor.read_exact(&mut data[0..10]).unwrap(); assert_eq!(cursor.stream_position().unwrap(), 22); assert_eq!(&data[0..10], b"2345678901"); cursor.read_exact(&mut data[0..8]).unwrap(); assert_eq!(cursor.stream_position().unwrap(), 30); assert_eq!(&data[0..8], b"234C6D89"); assert!(cursor.read_exact(&mut data[0..1]).is_err()); assert_eq!(cursor.seek(io::SeekFrom::Start(5)).unwrap(), 5); assert_eq!(cursor.stream_position().unwrap(), 5); cursor.read_exact(&mut data[0..1]).unwrap(); assert_eq!(&data[0..1], b"A"); assert_eq!(cursor.seek(io::SeekFrom::End(5)).unwrap(), 25); assert_eq!(cursor.stream_position().unwrap(), 25); cursor.read_exact(&mut data[0..1]).unwrap(); assert_eq!(&data[0..1], b"C"); assert_eq!(cursor.seek(io::SeekFrom::Current(-1)).unwrap(), 25); assert_eq!(cursor.stream_position().unwrap(), 25); cursor.read_exact(&mut data[0..1]).unwrap(); assert_eq!(&data[0..1], b"C"); assert_eq!(cursor.seek(io::SeekFrom::Current(1)).unwrap(), 27); assert_eq!(cursor.stream_position().unwrap(), 27); cursor.read_exact(&mut data[0..1]).unwrap(); assert_eq!(&data[0..1], b"D"); } #[test] #[allow(clippy::cognitive_complexity)] fn test_buffer_cursor_ref() { use std::io::{self, Read, Seek, Write}; crate::init().unwrap(); let mut buffer = Buffer::new(); { let buffer = buffer.get_mut().unwrap(); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5])); buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 10])); } assert!(buffer.is_all_memory_writable()); assert_eq!(buffer.n_memory(), 5); assert_eq!(buffer.size(), 30); { let buffer = buffer.get_mut().unwrap(); let mut cursor = buffer.as_cursor_writable().unwrap(); assert_eq!(cursor.stream_position().unwrap(), 0); cursor.write_all(b"01234567").unwrap(); assert_eq!(cursor.stream_position().unwrap(), 8); cursor.write_all(b"890123").unwrap(); assert_eq!(cursor.stream_position().unwrap(), 14); cursor.write_all(b"456").unwrap(); assert_eq!(cursor.stream_position().unwrap(), 17); cursor.write_all(b"78901234567").unwrap(); assert_eq!(cursor.stream_position().unwrap(), 28); cursor.write_all(b"89").unwrap(); assert_eq!(cursor.stream_position().unwrap(), 30); assert!(cursor.write_all(b"0").is_err()); assert_eq!(cursor.seek(io::SeekFrom::Start(5)).unwrap(), 5); assert_eq!(cursor.stream_position().unwrap(), 5); cursor.write_all(b"A").unwrap(); assert_eq!(cursor.seek(io::SeekFrom::End(5)).unwrap(), 25); assert_eq!(cursor.stream_position().unwrap(), 25); cursor.write_all(b"B").unwrap(); assert_eq!(cursor.seek(io::SeekFrom::Current(-1)).unwrap(), 25); assert_eq!(cursor.stream_position().unwrap(), 25); cursor.write_all(b"C").unwrap(); assert_eq!(cursor.seek(io::SeekFrom::Current(1)).unwrap(), 27); assert_eq!(cursor.stream_position().unwrap(), 27); cursor.write_all(b"D").unwrap(); } let mut cursor = buffer.as_cursor_readable(); let mut data = [0; 30]; assert_eq!(cursor.stream_position().unwrap(), 0); cursor.read_exact(&mut data[0..7]).unwrap(); assert_eq!(cursor.stream_position().unwrap(), 7); assert_eq!(&data[0..7], b"01234A6"); cursor.read_exact(&mut data[0..5]).unwrap(); assert_eq!(cursor.stream_position().unwrap(), 12); assert_eq!(&data[0..5], b"78901"); cursor.read_exact(&mut data[0..10]).unwrap(); assert_eq!(cursor.stream_position().unwrap(), 22); assert_eq!(&data[0..10], b"2345678901"); cursor.read_exact(&mut data[0..8]).unwrap(); assert_eq!(cursor.stream_position().unwrap(), 30); assert_eq!(&data[0..8], b"234C6D89"); assert!(cursor.read_exact(&mut data[0..1]).is_err()); assert_eq!(cursor.seek(io::SeekFrom::Start(5)).unwrap(), 5); assert_eq!(cursor.stream_position().unwrap(), 5); cursor.read_exact(&mut data[0..1]).unwrap(); assert_eq!(&data[0..1], b"A"); assert_eq!(cursor.seek(io::SeekFrom::End(5)).unwrap(), 25); assert_eq!(cursor.stream_position().unwrap(), 25); cursor.read_exact(&mut data[0..1]).unwrap(); assert_eq!(&data[0..1], b"C"); assert_eq!(cursor.seek(io::SeekFrom::Current(-1)).unwrap(), 25); assert_eq!(cursor.stream_position().unwrap(), 25); cursor.read_exact(&mut data[0..1]).unwrap(); assert_eq!(&data[0..1], b"C"); assert_eq!(cursor.seek(io::SeekFrom::Current(1)).unwrap(), 27); assert_eq!(cursor.stream_position().unwrap(), 27); cursor.read_exact(&mut data[0..1]).unwrap(); assert_eq!(&data[0..1], b"D"); } } gstreamer-0.23.5/src/buffer_pool.rs000064400000000000000000000313331046102023000153460ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ marker::PhantomData, mem, ops, ops::{Deref, DerefMut}, ptr, }; use glib::{prelude::*, translate::*}; use crate::{ffi, AllocationParams, Allocator, BufferPool, Structure, StructureRef}; #[derive(Debug, Clone, PartialEq, Eq)] #[repr(transparent)] pub struct BufferPoolConfig(Structure); impl Deref for BufferPoolConfig { type Target = BufferPoolConfigRef; #[inline] fn deref(&self) -> &BufferPoolConfigRef { unsafe { &*(self.0.as_ptr() as *const StructureRef as *const BufferPoolConfigRef) } } } impl DerefMut for BufferPoolConfig { #[inline] fn deref_mut(&mut self) -> &mut BufferPoolConfigRef { unsafe { &mut *(self.0.as_ptr() as *mut StructureRef as *mut BufferPoolConfigRef) } } } impl AsRef for BufferPoolConfig { #[inline] fn as_ref(&self) -> &BufferPoolConfigRef { self.deref() } } impl AsMut for BufferPoolConfig { #[inline] fn as_mut(&mut self) -> &mut BufferPoolConfigRef { self.deref_mut() } } #[derive(Debug)] #[repr(transparent)] pub struct BufferPoolConfigRef(StructureRef); impl BufferPoolConfigRef { #[inline] pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstStructure) -> &'a BufferPoolConfigRef { debug_assert!(!ptr.is_null()); &*(ptr as *mut StructureRef as *mut BufferPoolConfigRef) } #[inline] pub unsafe fn from_glib_borrow_mut<'a>( ptr: *mut ffi::GstStructure, ) -> &'a mut BufferPoolConfigRef { debug_assert!(!ptr.is_null()); &mut *(ptr as *mut StructureRef as *mut BufferPoolConfigRef) } #[inline] pub fn as_ptr(&self) -> *const ffi::GstStructure { self as *const Self as *const ffi::GstStructure } #[inline] pub fn as_mut_ptr(&self) -> *mut ffi::GstStructure { self as *const Self as *mut ffi::GstStructure } } impl ops::Deref for BufferPoolConfigRef { type Target = crate::StructureRef; #[inline] fn deref(&self) -> &crate::StructureRef { &self.0 } } impl ops::DerefMut for BufferPoolConfigRef { #[inline] fn deref_mut(&mut self) -> &mut crate::StructureRef { &mut self.0 } } impl AsRef for BufferPoolConfigRef { #[inline] fn as_ref(&self) -> &crate::StructureRef { &self.0 } } impl AsMut for BufferPoolConfigRef { #[inline] fn as_mut(&mut self) -> &mut crate::StructureRef { &mut self.0 } } impl BufferPoolConfigRef { #[doc(alias = "gst_buffer_pool_config_add_option")] pub fn add_option(&mut self, option: &str) { unsafe { ffi::gst_buffer_pool_config_add_option(self.0.as_mut_ptr(), option.to_glib_none().0); } } #[doc(alias = "gst_buffer_pool_config_has_option")] pub fn has_option(&self, option: &str) -> bool { unsafe { from_glib(ffi::gst_buffer_pool_config_has_option( self.0.as_mut_ptr(), option.to_glib_none().0, )) } } #[doc(alias = "get_options")] #[doc(alias = "gst_buffer_pool_config_n_options")] #[doc(alias = "gst_buffer_pool_config_get_option")] pub fn options(&self) -> Vec { unsafe { let n = ffi::gst_buffer_pool_config_n_options(self.0.as_mut_ptr()) as usize; let mut options = Vec::with_capacity(n); for i in 0..n { options.push(from_glib_none(ffi::gst_buffer_pool_config_get_option( self.0.as_mut_ptr(), i as u32, ))); } options } } #[doc(alias = "gst_buffer_pool_config_set_params")] pub fn set_params( &mut self, caps: Option<&crate::Caps>, size: u32, min_buffers: u32, max_buffers: u32, ) { unsafe { ffi::gst_buffer_pool_config_set_params( self.0.as_mut_ptr(), caps.to_glib_none().0, size, min_buffers, max_buffers, ); } } #[doc(alias = "get_params")] #[doc(alias = "gst_buffer_pool_config_get_params")] pub fn params(&self) -> Option<(Option, u32, u32, u32)> { unsafe { let mut caps = ptr::null_mut(); let mut size = mem::MaybeUninit::uninit(); let mut min_buffers = mem::MaybeUninit::uninit(); let mut max_buffers = mem::MaybeUninit::uninit(); let ret: bool = from_glib(ffi::gst_buffer_pool_config_get_params( self.0.as_mut_ptr(), &mut caps, size.as_mut_ptr(), min_buffers.as_mut_ptr(), max_buffers.as_mut_ptr(), )); if !ret { return None; } Some(( from_glib_none(caps), size.assume_init(), min_buffers.assume_init(), max_buffers.assume_init(), )) } } #[doc(alias = "gst_buffer_pool_config_validate_params")] pub fn validate_params( &self, caps: Option<&crate::Caps>, size: u32, min_buffers: u32, max_buffers: u32, ) -> Result<(), glib::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_buffer_pool_config_validate_params( self.0.as_mut_ptr(), caps.to_glib_none().0, size, min_buffers, max_buffers, ), "Parameters are not valid in this context" ) } } #[doc(alias = "get_allocator")] #[doc(alias = "gst_buffer_pool_config_get_allocator")] pub fn allocator(&self) -> Option<(Option, AllocationParams)> { unsafe { let mut allocator = ptr::null_mut(); let mut params = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_buffer_pool_config_get_allocator( self.0.as_mut_ptr(), &mut allocator, params.as_mut_ptr(), )); if ret { Some((from_glib_none(allocator), params.assume_init().into())) } else { None } } } #[doc(alias = "gst_buffer_pool_config_set_allocator")] pub fn set_allocator(&self, allocator: Option<&Allocator>, params: Option<&AllocationParams>) { assert!(allocator.is_some() || params.is_some()); unsafe { ffi::gst_buffer_pool_config_set_allocator( self.0.as_mut_ptr(), allocator.to_glib_none().0, match params { Some(val) => val.as_ptr(), None => ptr::null(), }, ) } } // TODO: options iterator } #[derive(Debug)] #[doc(alias = "GstBufferPoolAcquireParams")] pub struct BufferPoolAcquireParams(ffi::GstBufferPoolAcquireParams); unsafe impl Send for BufferPoolAcquireParams {} unsafe impl Sync for BufferPoolAcquireParams {} impl BufferPoolAcquireParams { pub fn with_flags(flags: crate::BufferPoolAcquireFlags) -> Self { skip_assert_initialized!(); BufferPoolAcquireParams(ffi::GstBufferPoolAcquireParams { format: ffi::GST_FORMAT_UNDEFINED, start: -1, stop: -1, flags: flags.into_glib(), _gst_reserved: [ptr::null_mut(); 4], }) } pub fn with_start_stop( start: T, stop: T, flags: crate::BufferPoolAcquireFlags, ) -> Self { skip_assert_initialized!(); unsafe { BufferPoolAcquireParams(ffi::GstBufferPoolAcquireParams { format: start.format().into_glib(), start: start.into_raw_value(), stop: stop.into_raw_value(), flags: flags.into_glib(), _gst_reserved: [ptr::null_mut(); 4], }) } } pub fn flags(&self) -> crate::BufferPoolAcquireFlags { unsafe { from_glib(self.0.flags) } } pub fn format(&self) -> crate::Format { unsafe { from_glib(self.0.format) } } pub fn start(&self) -> crate::GenericFormattedValue { unsafe { crate::GenericFormattedValue::new(from_glib(self.0.format), self.0.start) } } pub fn stop(&self) -> crate::GenericFormattedValue { unsafe { crate::GenericFormattedValue::new(from_glib(self.0.format), self.0.stop) } } } impl PartialEq for BufferPoolAcquireParams { fn eq(&self, other: &Self) -> bool { self.format() == other.format() && self.start() == other.start() && self.stop() == other.stop() } } impl Eq for BufferPoolAcquireParams {} #[doc(hidden)] impl<'a> ToGlibPtr<'a, *const ffi::GstBufferPoolAcquireParams> for BufferPoolAcquireParams { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none( &'a self, ) -> glib::translate::Stash<'a, *const ffi::GstBufferPoolAcquireParams, Self> { glib::translate::Stash(&self.0, PhantomData) } } #[doc(hidden)] impl<'a> ToGlibPtrMut<'a, *mut ffi::GstBufferPoolAcquireParams> for BufferPoolAcquireParams { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut( &'a mut self, ) -> glib::translate::StashMut<'a, *mut ffi::GstBufferPoolAcquireParams, Self> { glib::translate::StashMut(&mut self.0, PhantomData) } } #[doc(hidden)] impl FromGlibPtrNone<*mut ffi::GstBufferPoolAcquireParams> for BufferPoolAcquireParams { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::GstBufferPoolAcquireParams) -> Self { Self(*ptr) } } mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait BufferPoolExtManual: sealed::Sealed + IsA + 'static { #[doc(alias = "get_config")] #[doc(alias = "gst_buffer_pool_get_config")] fn config(&self) -> BufferPoolConfig { unsafe { let ptr = ffi::gst_buffer_pool_get_config(self.as_ref().to_glib_none().0); BufferPoolConfig(from_glib_full(ptr)) } } #[doc(alias = "gst_buffer_pool_set_config")] fn set_config(&self, config: BufferPoolConfig) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_buffer_pool_set_config( self.as_ref().to_glib_none().0, config.0.into_glib_ptr() ), "Failed to set config", ) } } fn is_flushing(&self) -> bool { unsafe { let stash = self.as_ref().to_glib_none(); let ptr: *mut ffi::GstBufferPool = stash.0; from_glib((*ptr).flushing) } } #[doc(alias = "gst_buffer_pool_acquire_buffer")] fn acquire_buffer( &self, params: Option<&BufferPoolAcquireParams>, ) -> Result { let params_ptr = params.to_glib_none().0 as *mut _; unsafe { let mut buffer = ptr::null_mut(); crate::FlowSuccess::try_from_glib(ffi::gst_buffer_pool_acquire_buffer( self.as_ref().to_glib_none().0, &mut buffer, params_ptr, )) .map(|_| from_glib_full(buffer)) } } } impl> BufferPoolExtManual for O {} #[cfg(test)] mod tests { use super::*; use crate::prelude::*; #[test] fn pool_with_params() { crate::init().unwrap(); let pool = crate::BufferPool::new(); let mut config = pool.config(); config.set_params(Some(&crate::Caps::builder("foo/bar").build()), 1024, 0, 2); pool.set_config(config).unwrap(); pool.set_active(true).unwrap(); let params = crate::BufferPoolAcquireParams::with_flags(crate::BufferPoolAcquireFlags::DONTWAIT); let _buf1 = pool.acquire_buffer(Some(¶ms)).unwrap(); let buf2 = pool.acquire_buffer(Some(¶ms)).unwrap(); assert!(pool.acquire_buffer(Some(¶ms)).is_err()); drop(buf2); let _buf2 = pool.acquire_buffer(Some(¶ms)).unwrap(); pool.set_active(false).unwrap(); } #[test] fn pool_no_params() { crate::init().unwrap(); let pool = crate::BufferPool::new(); let mut config = pool.config(); config.set_params(None, 1024, 0, 2); pool.set_config(config).unwrap(); pool.set_active(true).unwrap(); let _buf1 = pool.acquire_buffer(None).unwrap(); pool.set_active(false).unwrap(); } } gstreamer-0.23.5/src/buffer_serde.rs000064400000000000000000000154011046102023000154750ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use serde::{ de::{Deserialize, Deserializer}, ser, ser::{Serialize, SerializeStruct, Serializer}, }; use serde_bytes::{ByteBuf, Bytes}; use crate::{Buffer, BufferFlags, BufferRef, ClockTime}; // TODO: try `Either` to merge the base representations for ser and de // while avoiding unneeded copy impl Serialize for BufferRef { fn serialize(&self, serializer: S) -> Result { let mut buffer = serializer.serialize_struct("Buffer", 7)?; buffer.serialize_field("pts", &self.pts())?; buffer.serialize_field("dts", &self.dts())?; buffer.serialize_field("duration", &self.duration())?; buffer.serialize_field("offset", &self.offset())?; buffer.serialize_field("offset_end", &self.offset_end())?; buffer.serialize_field("flags", &self.flags())?; { let data = self .map_readable() .map_err(|_| ser::Error::custom("Couldn't map `buffer` as readable"))?; buffer.serialize_field("buffer", &Bytes::new(data.as_slice()))?; } buffer.end() } } impl Serialize for Buffer { fn serialize(&self, serializer: S) -> Result { self.as_ref().serialize(serializer) } } #[derive(serde::Deserialize)] struct BufferDe { pts: Option, dts: Option, duration: Option, offset: u64, offset_end: u64, flags: BufferFlags, buffer: ByteBuf, } impl From for Buffer { fn from(buf_de: BufferDe) -> Self { skip_assert_initialized!(); let mut buffer = Buffer::from_mut_slice(buf_de.buffer.to_vec()); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(buf_de.pts); buffer.set_dts(buf_de.dts); buffer.set_duration(buf_de.duration); buffer.set_offset(buf_de.offset); buffer.set_offset_end(buf_de.offset_end); buffer.set_flags(buf_de.flags); } buffer } } impl<'de> Deserialize<'de> for Buffer { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); BufferDe::deserialize(deserializer).map(|buffer_de| buffer_de.into()) } } #[cfg(test)] mod tests { use crate::{Buffer, BufferFlags, ClockTime}; #[test] fn test_serialize() { crate::init().unwrap(); let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(Some(ClockTime::NSECOND)); buffer.set_offset(3); buffer.set_offset_end(4); buffer.set_duration(5 * ClockTime::NSECOND); buffer.set_flags(BufferFlags::LIVE | BufferFlags::DISCONT); } let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string()); let res = ron::ser::to_string_pretty(&buffer, pretty_config); assert_eq!( Ok(concat!( "(", " pts: Some(1),", " dts: None,", " duration: Some(5),", " offset: 3,", " offset_end: 4,", " flags: \"live+discont\",", " buffer: \"AQIDBA==\",", ")" ) .to_owned()), res ); let res = serde_json::to_string(&buffer).unwrap(); assert_eq!( concat!( "{", "\"pts\":1,", "\"dts\":null,", "\"duration\":5,", "\"offset\":3,", "\"offset_end\":4,", "\"flags\":\"live+discont\",", "\"buffer\":[1,2,3,4]", "}" ) .to_owned(), res ); } #[test] fn test_deserialize() { crate::init().unwrap(); let buffer_ron = r#" ( pts: Some(1), dts: None, duration: Some(5), offset: 3, offset_end: 4, flags: "live+discont", buffer: "AQIDBA==", ) "#; let buffer: Buffer = ron::de::from_str(buffer_ron).unwrap(); assert_eq!(buffer.pts(), Some(ClockTime::NSECOND)); assert_eq!(buffer.dts(), crate::ClockTime::NONE); assert_eq!(buffer.offset(), 3); assert_eq!(buffer.offset_end(), 4); assert_eq!(buffer.duration(), Some(5 * ClockTime::NSECOND)); assert_eq!(buffer.flags(), BufferFlags::LIVE | BufferFlags::DISCONT); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); } let buffer_json = r#" { "pts":1, "dts":null, "duration":5, "offset":3, "offset_end":4, "flags":"live+discont", "buffer":[1,2,3,4] } "#; let buffer: Buffer = serde_json::from_str(buffer_json).unwrap(); assert_eq!(buffer.pts(), Some(ClockTime::NSECOND)); assert_eq!(buffer.dts(), crate::ClockTime::NONE); assert_eq!(buffer.offset(), 3); assert_eq!(buffer.offset_end(), 4); assert_eq!(buffer.duration(), Some(5 * ClockTime::NSECOND)); assert_eq!(buffer.flags(), BufferFlags::LIVE | BufferFlags::DISCONT); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); } } #[test] fn test_serde_roundtrip() { crate::init().unwrap(); let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(Some(ClockTime::NSECOND)); buffer.set_offset(3); buffer.set_offset_end(4); buffer.set_duration(5 * ClockTime::NSECOND); buffer.set_flags(BufferFlags::LIVE | BufferFlags::DISCONT); } // Ron let buffer_ser = ron::ser::to_string(&buffer).unwrap(); let buffer_de: Buffer = ron::de::from_str(buffer_ser.as_str()).unwrap(); assert_eq!(buffer_de.pts(), buffer.pts()); assert_eq!(buffer_de.dts(), buffer.dts()); assert_eq!(buffer_de.offset(), buffer.offset()); assert_eq!(buffer_de.offset_end(), buffer.offset_end()); assert_eq!(buffer_de.duration(), buffer.duration()); assert_eq!(buffer_de.flags(), buffer.flags()); { let data = buffer_de.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); } } } gstreamer-0.23.5/src/bufferlist.rs000064400000000000000000000363201046102023000152120ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ cmp, fmt, ops::{ControlFlow, RangeBounds}, ptr, }; use glib::translate::*; use crate::{ffi, Buffer, BufferRef}; mini_object_wrapper!(BufferList, BufferListRef, ffi::GstBufferList, || { ffi::gst_buffer_list_get_type() }); impl BufferList { #[doc(alias = "gst_buffer_list_new")] pub fn new() -> Self { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_buffer_list_new()) } } #[doc(alias = "gst_buffer_list_new_sized")] pub fn new_sized(size: usize) -> Self { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_buffer_list_new_sized(u32::try_from(size).unwrap())) } } } impl BufferListRef { #[doc(alias = "gst_buffer_list_insert")] pub fn insert(&mut self, idx: impl Into>, buffer: Buffer) { unsafe { let len = self.len(); debug_assert!(len <= u32::MAX as usize); let idx = idx.into(); let idx = cmp::min(idx.unwrap_or(len), len) as i32; ffi::gst_buffer_list_insert(self.as_mut_ptr(), idx, buffer.into_glib_ptr()); } } #[doc(alias = "gst_buffer_list_add")] pub fn add(&mut self, buffer: Buffer) { self.insert(None, buffer); } #[doc(alias = "gst_buffer_list_copy_deep")] pub fn copy_deep(&self) -> BufferList { unsafe { from_glib_full(ffi::gst_buffer_list_copy_deep(self.as_ptr())) } } #[doc(alias = "gst_buffer_list_remove")] pub fn remove(&mut self, range: impl RangeBounds) { let n = self.len(); debug_assert!(n <= u32::MAX as usize); let start_idx = match range.start_bound() { std::ops::Bound::Included(idx) => *idx, std::ops::Bound::Excluded(idx) => idx.checked_add(1).unwrap(), std::ops::Bound::Unbounded => 0, }; assert!(start_idx < n); let end_idx = match range.end_bound() { std::ops::Bound::Included(idx) => idx.checked_add(1).unwrap(), std::ops::Bound::Excluded(idx) => *idx, std::ops::Bound::Unbounded => n, }; assert!(end_idx <= n); unsafe { ffi::gst_buffer_list_remove( self.as_mut_ptr(), start_idx as u32, (end_idx - start_idx) as u32, ) } } #[doc(alias = "gst_buffer_list_get")] pub fn get(&self, idx: usize) -> Option<&BufferRef> { unsafe { if idx >= self.len() { return None; } let ptr = ffi::gst_buffer_list_get(self.as_mut_ptr(), idx as u32); Some(BufferRef::from_ptr(ptr)) } } #[doc(alias = "gst_buffer_list_get")] pub fn get_owned(&self, idx: usize) -> Option { unsafe { if idx >= self.len() { return None; } let ptr = ffi::gst_buffer_list_get(self.as_mut_ptr(), idx as u32); Some(from_glib_none(ptr)) } } #[doc(alias = "gst_buffer_list_get_writable")] #[doc(alias = "get_writable")] pub fn get_mut(&mut self, idx: usize) -> Option<&mut BufferRef> { unsafe { if idx >= self.len() { return None; } let ptr = ffi::gst_buffer_list_get_writable(self.as_mut_ptr(), idx as u32); Some(BufferRef::from_mut_ptr(ptr)) } } #[doc(alias = "gst_buffer_list_length")] pub fn len(&self) -> usize { unsafe { ffi::gst_buffer_list_length(self.as_mut_ptr()) as usize } } #[doc(alias = "gst_buffer_list_calculate_size")] pub fn calculate_size(&self) -> usize { unsafe { ffi::gst_buffer_list_calculate_size(self.as_mut_ptr()) } } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn iter(&self) -> Iter { Iter::new(self) } pub fn iter_owned(&self) -> IterOwned { IterOwned::new(self) } #[doc(alias = "gst_buffer_list_foreach")] pub fn foreach ControlFlow<(), ()>>(&self, func: F) -> bool { unsafe extern "C" fn trampoline ControlFlow<(), ()>>( buffer: *mut *mut ffi::GstBuffer, idx: u32, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let func = user_data as *mut F; let res = (*func)(&Buffer::from_glib_borrow(*buffer), idx as usize); matches!(res, ControlFlow::Continue(_)).into_glib() } unsafe { let mut func = func; let func_ptr: &mut F = &mut func; from_glib(ffi::gst_buffer_list_foreach( self.as_ptr() as *mut _, Some(trampoline::), func_ptr as *mut _ as *mut _, )) } } #[doc(alias = "gst_buffer_list_foreach")] pub fn foreach_mut ControlFlow, Option>>( &mut self, func: F, ) -> bool { unsafe extern "C" fn trampoline< F: FnMut(Buffer, usize) -> ControlFlow, Option>, >( buffer: *mut *mut ffi::GstBuffer, idx: u32, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let func = user_data as *mut F; let res = (*func)( Buffer::from_glib_full(ptr::replace( buffer as *mut *const ffi::GstBuffer, ptr::null_mut::(), )), idx as usize, ); let (cont, res_buffer) = match res { ControlFlow::Continue(res_buffer) => (true, res_buffer), ControlFlow::Break(res_buffer) => (false, res_buffer), }; match res_buffer { None => { *buffer = ptr::null_mut(); } Some(new_buffer) => { *buffer = new_buffer.into_glib_ptr(); } } cont.into_glib() } unsafe { let mut func = func; let func_ptr: &mut F = &mut func; from_glib(ffi::gst_buffer_list_foreach( self.as_ptr() as *mut _, Some(trampoline::), func_ptr as *mut _ as *mut _, )) } } } impl Default for BufferList { fn default() -> Self { Self::new() } } impl fmt::Debug for BufferList { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { BufferListRef::fmt(self, f) } } impl fmt::Debug for BufferListRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use crate::{utils::Displayable, ClockTime}; let size = self.iter().map(|b| b.size()).sum::(); let (pts, dts) = self .get(0) .map(|b| (b.pts(), b.dts())) .unwrap_or((ClockTime::NONE, ClockTime::NONE)); f.debug_struct("BufferList") .field("ptr", &self.as_ptr()) .field("buffers", &self.len()) .field("pts", &pts.display()) .field("dts", &dts.display()) .field("size", &size) .finish() } } macro_rules! define_iter( ($name:ident, $styp:ty, $get_item:expr) => { #[derive(Debug)] pub struct $name<'a> { list: &'a BufferListRef, idx: usize, size: usize, } impl<'a> $name<'a> { fn new(list: &'a BufferListRef) -> $name<'a> { skip_assert_initialized!(); $name { list, idx: 0, size: list.len(), } } } #[allow(clippy::redundant_closure_call)] impl<'a> Iterator for $name<'a> { type Item = $styp; fn next(&mut self) -> Option { if self.idx >= self.size { return None; } let item = $get_item(self.list, self.idx).unwrap(); self.idx += 1; Some(item) } fn size_hint(&self) -> (usize, Option) { let remaining = self.size - self.idx; (remaining, Some(remaining)) } fn count(self) -> usize { self.size - self.idx } fn nth(&mut self, n: usize) -> Option { let (end, overflow) = self.idx.overflowing_add(n); if end >= self.size || overflow { self.idx = self.size; None } else { self.idx = end + 1; Some($get_item(self.list, end).unwrap()) } } fn last(self) -> Option { if self.idx == self.size { None } else { Some($get_item(self.list, self.size - 1).unwrap()) } } } #[allow(clippy::redundant_closure_call)] impl<'a> DoubleEndedIterator for $name<'a> { fn next_back(&mut self) -> Option { if self.idx == self.size { return None; } self.size -= 1; Some($get_item(self.list, self.size).unwrap()) } fn nth_back(&mut self, n: usize) -> Option { let (end, overflow) = self.size.overflowing_sub(n); if end <= self.idx || overflow { self.idx = self.size; None } else { self.size = end - 1; Some($get_item(self.list, self.size).unwrap()) } } } impl<'a> ExactSizeIterator for $name<'a> {} impl<'a> std::iter::FusedIterator for $name<'a> {} } ); define_iter!(Iter, &'a BufferRef, |list: &'a BufferListRef, idx| { list.get(idx) }); define_iter!(IterOwned, Buffer, |list: &BufferListRef, idx| { list.get_owned(idx) }); impl<'a> IntoIterator for &'a BufferListRef { type IntoIter = Iter<'a>; type Item = &'a BufferRef; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl From for BufferList { fn from(value: Buffer) -> Self { skip_assert_initialized!(); let mut list = BufferList::new_sized(1); { let list = list.get_mut().unwrap(); list.add(value); } list } } impl From<[Buffer; N]> for BufferList { fn from(value: [Buffer; N]) -> Self { skip_assert_initialized!(); let mut list = BufferList::new_sized(N); { let list = list.get_mut().unwrap(); value.into_iter().for_each(|b| list.add(b)); } list } } impl std::iter::FromIterator for BufferList { fn from_iter>(iter: T) -> Self { assert_initialized_main_thread!(); let iter = iter.into_iter(); let mut list = BufferList::new_sized(iter.size_hint().0); { let list = list.get_mut().unwrap(); iter.for_each(|b| list.add(b)); } list } } impl std::iter::Extend for BufferListRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|b| self.add(b)); } } #[cfg(test)] mod tests { use super::*; use crate::ClockTime; fn make_buffer_list(size: usize) -> BufferList { skip_assert_initialized!(); let mut buffer_list = BufferList::new(); { let buffer_list = buffer_list.get_mut().unwrap(); for i in 0..size { let mut buffer = Buffer::new(); buffer .get_mut() .unwrap() .set_pts(ClockTime::SECOND * i as u64); buffer_list.add(buffer); } } buffer_list } #[test] fn test_foreach() { crate::init().unwrap(); let buffer_list = make_buffer_list(2); let mut res = vec![]; buffer_list.foreach(|buffer, idx| { res.push((buffer.pts(), idx)); ControlFlow::Continue(()) }); assert_eq!( res, &[(Some(ClockTime::ZERO), 0), (Some(ClockTime::SECOND), 1)] ); } #[test] fn test_foreach_mut() { crate::init().unwrap(); let mut buffer_list = make_buffer_list(3); let mut res = vec![]; buffer_list.get_mut().unwrap().foreach_mut(|buffer, idx| { res.push((buffer.pts(), idx)); if let Some(ClockTime::ZERO) = buffer.pts() { ControlFlow::Continue(Some(buffer)) } else if let Some(ClockTime::SECOND) = buffer.pts() { ControlFlow::Continue(None) } else { let mut new_buffer = Buffer::new(); new_buffer.get_mut().unwrap().set_pts(3 * ClockTime::SECOND); ControlFlow::Continue(Some(new_buffer)) } }); assert_eq!( res, &[ (Some(ClockTime::ZERO), 0), (Some(ClockTime::SECOND), 1), (Some(2 * ClockTime::SECOND), 1) ] ); let mut res = vec![]; buffer_list.foreach(|buffer, idx| { res.push((buffer.pts(), idx)); ControlFlow::Continue(()) }); assert_eq!( res, &[(Some(ClockTime::ZERO), 0), (Some(3 * ClockTime::SECOND), 1)] ); // Try removing buffers from inside foreach_mut let mut buffer_list = BufferList::new(); for i in 0..10 { let buffer_list = buffer_list.get_mut().unwrap(); let mut buffer = Buffer::new(); buffer.get_mut().unwrap().set_pts(i * ClockTime::SECOND); buffer_list.add(buffer); } assert_eq!(buffer_list.len(), 10); let buffer_list_ref = buffer_list.make_mut(); buffer_list_ref.foreach_mut(|buf, _n| { let keep_packet = (buf.pts().unwrap() / ClockTime::SECOND) % 3 != 0; ControlFlow::Continue(keep_packet.then_some(buf)) }); assert_eq!(buffer_list.len(), 6); let res = buffer_list .iter() .map(|buf| buf.pts().unwrap() / ClockTime::SECOND) .collect::>(); assert_eq!(res, &[1, 2, 4, 5, 7, 8]); } #[test] fn test_remove() { crate::init().unwrap(); let mut buffer_list = make_buffer_list(10); buffer_list.make_mut().remove(0..2); let buffers_left = buffer_list .iter() .map(|buf| buf.pts().unwrap() / ClockTime::SECOND) .collect::>(); assert_eq!(buffers_left, &[2, 3, 4, 5, 6, 7, 8, 9]); buffer_list.make_mut().remove(0..=2); let buffers_left = buffer_list .iter() .map(|buf| buf.pts().unwrap() / ClockTime::SECOND) .collect::>(); assert_eq!(buffers_left, &[5, 6, 7, 8, 9]); buffer_list.make_mut().remove(2..); let buffers_left = buffer_list .iter() .map(|buf| buf.pts().unwrap() / ClockTime::SECOND) .collect::>(); assert_eq!(buffers_left, &[5, 6]); buffer_list.make_mut().remove(..); assert!(buffer_list.is_empty()); } } gstreamer-0.23.5/src/bufferlist_serde.rs000064400000000000000000000155131046102023000163750ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::fmt; use serde::{ de::{Deserialize, Deserializer, SeqAccess, Visitor}, ser::{Serialize, SerializeSeq, Serializer}, }; use crate::{Buffer, BufferList, BufferListRef}; impl Serialize for BufferListRef { fn serialize(&self, serializer: S) -> Result { let iter = self.iter(); let (remaining, _) = iter.size_hint(); if remaining > 0 { let mut seq = serializer.serialize_seq(Some(remaining))?; for buffer in iter { seq.serialize_element(buffer)?; } seq.end() } else { let seq = serializer.serialize_seq(None)?; seq.end() } } } impl Serialize for BufferList { fn serialize(&self, serializer: S) -> Result { self.as_ref().serialize(serializer) } } struct BufferListVisitor; impl<'de> Visitor<'de> for BufferListVisitor { type Value = BufferList; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence of Buffers") } fn visit_seq>(self, mut seq: A) -> Result { let mut buffer_list = BufferList::new(); { let buffer_list = buffer_list.get_mut().unwrap(); while let Some(buffer) = seq.next_element::()? { buffer_list.add(buffer); } } Ok(buffer_list) } } impl<'de> Deserialize<'de> for BufferList { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); deserializer.deserialize_seq(BufferListVisitor) } } #[cfg(test)] mod tests { use crate::{BufferList, ClockTime}; #[test] fn test_serialize() { use crate::Buffer; crate::init().unwrap(); let mut buffer_list = BufferList::new(); { let buffer_list = buffer_list.get_mut().unwrap(); let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(ClockTime::NSECOND); buffer.set_offset(0); buffer.set_offset_end(4); buffer.set_duration(4 * ClockTime::NSECOND); } buffer_list.add(buffer); let mut buffer = Buffer::from_slice(vec![5, 6]); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(5 * ClockTime::NSECOND); buffer.set_offset(4); buffer.set_offset_end(6); buffer.set_duration(2 * ClockTime::NSECOND); } buffer_list.add(buffer); } let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string()); let res = ron::ser::to_string_pretty(&buffer_list, pretty_config); assert_eq!( Ok(concat!( "[", " (", " pts: Some(1),", " dts: None,", " duration: Some(4),", " offset: 0,", " offset_end: 4,", " flags: \"\",", " buffer: \"AQIDBA==\",", " ),", " (", " pts: Some(5),", " dts: None,", " duration: Some(2),", " offset: 4,", " offset_end: 6,", " flags: \"\",", " buffer: \"BQY=\",", " ),", "]" ) .to_owned()), res, ); } #[test] fn test_deserialize() { crate::init().unwrap(); let buffer_list_ron = r#" [ ( pts: Some(1), dts: None, duration: Some(4), offset: 0, offset_end: 4, flags: "", buffer: "AQIDBA==", ), ( pts: Some(5), dts: None, duration: Some(2), offset: 4, offset_end: 6, flags: "", buffer: "BQY=", ), ] "#; let buffer_list: BufferList = ron::de::from_str(buffer_list_ron).unwrap(); let mut iter = buffer_list.iter(); let buffer = iter.next().unwrap(); assert_eq!(buffer.pts(), Some(ClockTime::NSECOND)); assert_eq!(buffer.dts(), None); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); } let buffer = iter.next().unwrap(); assert_eq!(buffer.pts(), Some(5 * ClockTime::NSECOND)); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![5, 6].as_slice()); } } #[test] fn test_serde_roundtrip() { use crate::Buffer; crate::init().unwrap(); let mut buffer_list = BufferList::new(); { let buffer_list = buffer_list.get_mut().unwrap(); let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(ClockTime::NSECOND); buffer.set_offset(0); buffer.set_offset_end(4); buffer.set_duration(4 * ClockTime::NSECOND); } buffer_list.add(buffer); let mut buffer = Buffer::from_slice(vec![5, 6]); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(5 * ClockTime::NSECOND); buffer.set_offset(4); buffer.set_offset_end(6); buffer.set_duration(2 * ClockTime::NSECOND); } buffer_list.add(buffer); } let buffer_list_ser = ron::ser::to_string(&buffer_list).unwrap(); let buffer_list: BufferList = ron::de::from_str(buffer_list_ser.as_str()).unwrap(); let mut iter = buffer_list.iter(); let buffer = iter.next().unwrap(); assert_eq!(buffer.pts(), Some(ClockTime::NSECOND)); assert_eq!(buffer.dts(), None); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); } let buffer = iter.next().unwrap(); assert_eq!(buffer.pts(), Some(5 * ClockTime::NSECOND)); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![5, 6].as_slice()); } } } gstreamer-0.23.5/src/bus.rs000064400000000000000000000314661046102023000136440ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ future, mem::transmute, pin::Pin, task::{Context, Poll}, }; use futures_channel::mpsc::{self, UnboundedReceiver}; use futures_core::Stream; use futures_util::{stream::FusedStream, StreamExt}; use glib::{ ffi::{gboolean, gpointer}, prelude::*, source::Priority, translate::*, ControlFlow, }; use crate::{ffi, Bus, BusSyncReply, Message, MessageType}; unsafe extern "C" fn trampoline_watch ControlFlow + Send + 'static>( bus: *mut ffi::GstBus, msg: *mut ffi::GstMessage, func: gpointer, ) -> gboolean { let func: &mut F = &mut *(func as *mut F); func(&from_glib_borrow(bus), &Message::from_glib_borrow(msg)).into_glib() } unsafe extern "C" fn destroy_closure_watch< F: FnMut(&Bus, &Message) -> ControlFlow + Send + 'static, >( ptr: gpointer, ) { let _ = Box::::from_raw(ptr as *mut _); } fn into_raw_watch ControlFlow + Send + 'static>(func: F) -> gpointer { #[allow(clippy::type_complexity)] let func: Box = Box::new(func); Box::into_raw(func) as gpointer } unsafe extern "C" fn trampoline_watch_local ControlFlow + 'static>( bus: *mut ffi::GstBus, msg: *mut ffi::GstMessage, func: gpointer, ) -> gboolean { let func: &mut glib::thread_guard::ThreadGuard = &mut *(func as *mut glib::thread_guard::ThreadGuard); (func.get_mut())(&from_glib_borrow(bus), &Message::from_glib_borrow(msg)).into_glib() } unsafe extern "C" fn destroy_closure_watch_local< F: FnMut(&Bus, &Message) -> ControlFlow + 'static, >( ptr: gpointer, ) { let _ = Box::>::from_raw(ptr as *mut _); } fn into_raw_watch_local ControlFlow + 'static>(func: F) -> gpointer { #[allow(clippy::type_complexity)] let func: Box> = Box::new(glib::thread_guard::ThreadGuard::new(func)); Box::into_raw(func) as gpointer } unsafe extern "C" fn trampoline_sync< F: Fn(&Bus, &Message) -> BusSyncReply + Send + Sync + 'static, >( bus: *mut ffi::GstBus, msg: *mut ffi::GstMessage, func: gpointer, ) -> ffi::GstBusSyncReply { let f: &F = &*(func as *const F); let res = f(&from_glib_borrow(bus), &Message::from_glib_borrow(msg)).into_glib(); if res == ffi::GST_BUS_DROP { ffi::gst_mini_object_unref(msg as *mut _); } res } unsafe extern "C" fn destroy_closure_sync< F: Fn(&Bus, &Message) -> BusSyncReply + Send + Sync + 'static, >( ptr: gpointer, ) { let _ = Box::::from_raw(ptr as *mut _); } fn into_raw_sync BusSyncReply + Send + Sync + 'static>( func: F, ) -> gpointer { let func: Box = Box::new(func); Box::into_raw(func) as gpointer } impl Bus { #[doc(alias = "gst_bus_add_signal_watch")] #[doc(alias = "gst_bus_add_signal_watch_full")] pub fn add_signal_watch_full(&self, priority: Priority) { unsafe { ffi::gst_bus_add_signal_watch_full(self.to_glib_none().0, priority.into_glib()); } } #[doc(alias = "gst_bus_create_watch")] pub fn create_watch(&self, name: Option<&str>, priority: Priority, func: F) -> glib::Source where F: FnMut(&Bus, &Message) -> ControlFlow + Send + 'static, { skip_assert_initialized!(); unsafe { let source = ffi::gst_bus_create_watch(self.to_glib_none().0); glib::ffi::g_source_set_callback( source, Some(transmute::< *mut (), unsafe extern "C" fn(glib::ffi::gpointer) -> i32, >(trampoline_watch:: as *mut ())), into_raw_watch(func), Some(destroy_closure_watch::), ); glib::ffi::g_source_set_priority(source, priority.into_glib()); if let Some(name) = name { glib::ffi::g_source_set_name(source, name.to_glib_none().0); } from_glib_full(source) } } #[doc(alias = "gst_bus_add_watch")] #[doc(alias = "gst_bus_add_watch_full")] pub fn add_watch(&self, func: F) -> Result where F: FnMut(&Bus, &Message) -> ControlFlow + Send + 'static, { unsafe { let res = ffi::gst_bus_add_watch_full( self.to_glib_none().0, glib::ffi::G_PRIORITY_DEFAULT, Some(trampoline_watch::), into_raw_watch(func), Some(destroy_closure_watch::), ); if res == 0 { Err(glib::bool_error!("Bus already has a watch")) } else { Ok(BusWatchGuard { bus: self.clone() }) } } } #[doc(alias = "gst_bus_add_watch")] #[doc(alias = "gst_bus_add_watch_full")] pub fn add_watch_local(&self, func: F) -> Result where F: FnMut(&Bus, &Message) -> ControlFlow + 'static, { unsafe { let ctx = glib::MainContext::ref_thread_default(); let _acquire = ctx .acquire() .expect("thread default main context already acquired by another thread"); let res = ffi::gst_bus_add_watch_full( self.to_glib_none().0, glib::ffi::G_PRIORITY_DEFAULT, Some(trampoline_watch_local::), into_raw_watch_local(func), Some(destroy_closure_watch_local::), ); if res == 0 { Err(glib::bool_error!("Bus already has a watch")) } else { Ok(BusWatchGuard { bus: self.clone() }) } } } #[doc(alias = "gst_bus_set_sync_handler")] pub fn set_sync_handler(&self, func: F) where F: Fn(&Bus, &Message) -> BusSyncReply + Send + Sync + 'static, { unsafe { let bus = self.to_glib_none().0; #[cfg(not(feature = "v1_18"))] { static SET_ONCE_QUARK: std::sync::OnceLock = std::sync::OnceLock::new(); let set_once_quark = SET_ONCE_QUARK .get_or_init(|| glib::Quark::from_str("gstreamer-rs-sync-handler")); // This is not thread-safe before 1.16.3, see // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/merge_requests/416 if crate::version() < (1, 16, 3, 0) { if !glib::gobject_ffi::g_object_get_qdata( bus as *mut _, set_once_quark.into_glib(), ) .is_null() { panic!("Bus sync handler can only be set once"); } glib::gobject_ffi::g_object_set_qdata( bus as *mut _, set_once_quark.into_glib(), 1 as *mut _, ); } } ffi::gst_bus_set_sync_handler( bus, Some(trampoline_sync::), into_raw_sync(func), Some(destroy_closure_sync::), ) } } pub fn unset_sync_handler(&self) { #[cfg(not(feature = "v1_18"))] { // This is not thread-safe before 1.16.3, see // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/merge_requests/416 if crate::version() < (1, 16, 3, 0) { return; } } unsafe { use std::ptr; ffi::gst_bus_set_sync_handler(self.to_glib_none().0, None, ptr::null_mut(), None) } } #[doc(alias = "gst_bus_pop")] pub fn iter(&self) -> Iter { self.iter_timed(Some(crate::ClockTime::ZERO)) } #[doc(alias = "gst_bus_timed_pop")] pub fn iter_timed(&self, timeout: impl Into>) -> Iter { Iter { bus: self, timeout: timeout.into(), } } #[doc(alias = "gst_bus_pop_filtered")] pub fn iter_filtered<'a>( &'a self, msg_types: &'a [MessageType], ) -> impl Iterator + 'a { self.iter_timed_filtered(Some(crate::ClockTime::ZERO), msg_types) } #[doc(alias = "gst_bus_timed_pop_filtered")] pub fn iter_timed_filtered<'a>( &'a self, timeout: impl Into>, msg_types: &'a [MessageType], ) -> impl Iterator + 'a { self.iter_timed(timeout) .filter(move |msg| msg_types.contains(&msg.type_())) } #[doc(alias = "gst_bus_timed_pop_filtered")] pub fn timed_pop_filtered( &self, timeout: impl Into> + Clone, msg_types: &[MessageType], ) -> Option { loop { let msg = self.timed_pop(timeout.clone())?; if msg_types.contains(&msg.type_()) { return Some(msg); } } } #[doc(alias = "gst_bus_pop_filtered")] pub fn pop_filtered(&self, msg_types: &[MessageType]) -> Option { loop { let msg = self.pop()?; if msg_types.contains(&msg.type_()) { return Some(msg); } } } pub fn stream(&self) -> BusStream { BusStream::new(self) } pub fn stream_filtered<'a>( &self, message_types: &'a [MessageType], ) -> impl FusedStream + Unpin + Send + 'a { self.stream().filter(move |message| { let message_type = message.type_(); future::ready(message_types.contains(&message_type)) }) } } #[derive(Debug)] pub struct Iter<'a> { bus: &'a Bus, timeout: Option, } impl Iterator for Iter<'_> { type Item = Message; fn next(&mut self) -> Option { self.bus.timed_pop(self.timeout) } } #[derive(Debug)] pub struct BusStream { bus: glib::WeakRef, receiver: UnboundedReceiver, } impl BusStream { fn new(bus: &Bus) -> Self { skip_assert_initialized!(); let (sender, receiver) = mpsc::unbounded(); bus.set_sync_handler(move |bus, message| { // First pop all messages that might've been previously queued before creating // the bus stream. while let Some(message) = bus.pop() { let _ = sender.unbounded_send(message); } let _ = sender.unbounded_send(message.to_owned()); BusSyncReply::Drop }); Self { bus: bus.downgrade(), receiver, } } } impl Drop for BusStream { fn drop(&mut self) { if let Some(bus) = self.bus.upgrade() { bus.unset_sync_handler(); } } } impl Stream for BusStream { type Item = Message; fn poll_next(mut self: Pin<&mut Self>, context: &mut Context) -> Poll> { self.receiver.poll_next_unpin(context) } } impl FusedStream for BusStream { fn is_terminated(&self) -> bool { self.receiver.is_terminated() } } // rustdoc-stripper-ignore-next /// Manages ownership of the bus watch added to a bus with [`Bus::add_watch`] or [`Bus::add_watch_local`] /// /// When dropped the bus watch is removed from the bus. #[derive(Debug)] #[must_use = "if unused the bus watch will immediately be removed"] pub struct BusWatchGuard { bus: Bus, } impl Drop for BusWatchGuard { fn drop(&mut self) { let _ = self.bus.remove_watch(); } } #[cfg(test)] mod tests { use std::sync::{Arc, Mutex}; use super::*; #[test] fn test_sync_handler() { crate::init().unwrap(); let bus = Bus::new(); let msgs = Arc::new(Mutex::new(Vec::new())); let msgs_clone = msgs.clone(); bus.set_sync_handler(move |_, msg| { msgs_clone.lock().unwrap().push(msg.clone()); BusSyncReply::Pass }); bus.post(crate::message::Eos::new()).unwrap(); let msgs = msgs.lock().unwrap(); assert_eq!(msgs.len(), 1); match msgs[0].view() { crate::MessageView::Eos(_) => (), _ => unreachable!(), } } #[test] fn test_bus_stream() { crate::init().unwrap(); let bus = Bus::new(); let bus_stream = bus.stream(); let eos_message = crate::message::Eos::new(); bus.post(eos_message).unwrap(); let bus_future = bus_stream.into_future(); let (message, _) = futures_executor::block_on(bus_future); match message.unwrap().view() { crate::MessageView::Eos(_) => (), _ => unreachable!(), } } } gstreamer-0.23.5/src/bus_unix.rs000064400000000000000000000017541046102023000147040ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. cfg_if::cfg_if! { if #[cfg(unix)] { use glib::translate::ToGlibPtr; use std::mem; use std::os::unix; } else if #[cfg(docsrs)] { // Declare a fake RawFd for doc generation on windows pub mod unix { pub mod io { pub struct RawFd{} } } } } use super::Bus; pub trait UnixBusExtManual: 'static { #[doc(alias = "get_pollfd")] #[doc(alias = "gst_bus_get_pollfd")] fn pollfd(&self) -> unix::io::RawFd; } impl UnixBusExtManual for Bus { fn pollfd(&self) -> unix::io::RawFd { #[cfg(unix)] unsafe { let mut pollfd = mem::MaybeUninit::uninit(); crate::ffi::gst_bus_get_pollfd(self.to_glib_none().0, pollfd.as_mut_ptr()); let pollfd = pollfd.assume_init(); pollfd.fd } #[cfg(all(not(unix), docsrs))] unix::io::RawFd {} } } gstreamer-0.23.5/src/bus_windows.rs000064400000000000000000000020451046102023000154050ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. cfg_if::cfg_if! { if #[cfg(windows)] { use glib::translate::ToGlibPtr; use std::mem; use std::os::windows; } else if #[cfg(docsrs)] { // Declare a fake RawHandle for doc generation on unix pub mod windows { pub mod io { pub struct RawHandle{} } } } } use super::Bus; pub trait WindowsBusExtManual: 'static { #[doc(alias = "get_pollfd")] #[doc(alias = "gst_bus_get_pollfd")] fn pollfd(&self) -> windows::io::RawHandle; } impl WindowsBusExtManual for Bus { fn pollfd(&self) -> windows::io::RawHandle { #[cfg(windows)] unsafe { let mut pollfd = mem::MaybeUninit::uninit(); crate::ffi::gst_bus_get_pollfd(self.to_glib_none().0, pollfd.as_mut_ptr()); let pollfd = pollfd.assume_init(); pollfd.fd as *mut _ } #[cfg(all(not(windows), docsrs))] windows::io::RawHandle {} } } gstreamer-0.23.5/src/caps.rs000064400000000000000000001307651046102023000140030ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{fmt, marker::PhantomData, ptr, str}; use glib::{ prelude::*, translate::*, value::{SendValue, ToSendValue}, }; use crate::{caps_features::*, ffi, structure::*, CapsIntersectMode}; mini_object_wrapper!(Caps, CapsRef, ffi::GstCaps, || { ffi::gst_caps_get_type() }); impl Caps { #[doc(alias = "gst_caps_new_simple")] pub fn builder(name: impl IntoGStr) -> Builder { assert_initialized_main_thread!(); Builder::new(name) } #[doc(alias = "gst_caps_new_full")] pub fn builder_full() -> BuilderFull { assert_initialized_main_thread!(); BuilderFull::new() } #[doc(alias = "gst_caps_new_full")] pub fn builder_full_with_features(features: CapsFeatures) -> BuilderFull { assert_initialized_main_thread!(); BuilderFull::with_features(features) } #[doc(alias = "gst_caps_new_full")] pub fn builder_full_with_any_features() -> BuilderFull { assert_initialized_main_thread!(); BuilderFull::with_any_features() } #[doc(alias = "gst_caps_new_empty")] pub fn new_empty() -> Self { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_caps_new_empty()) } } #[doc(alias = "gst_caps_new_any")] pub fn new_any() -> Self { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_caps_new_any()) } } #[doc(alias = "gst_caps_new_empty_simple")] pub fn new_empty_simple(name: impl IntoGStr) -> Self { skip_assert_initialized!(); let mut caps = Caps::new_empty(); let structure = Structure::new_empty(name); caps.get_mut().unwrap().append_structure(structure); caps } #[doc(alias = "gst_caps_fixate")] pub fn fixate(&mut self) { unsafe { // See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/388 assert!(!self.is_any()); let ptr = if self.is_empty() { ffi::gst_caps_new_empty() } else { ffi::gst_caps_fixate(self.as_mut_ptr()) }; self.replace_ptr(ptr); } } #[doc(alias = "gst_caps_merge")] pub fn merge(&mut self, other: Self) { unsafe { let ptr = ffi::gst_caps_merge(self.as_mut_ptr(), other.into_glib_ptr()); self.replace_ptr(ptr); } } #[doc(alias = "gst_caps_merge_structure")] pub fn merge_structure(&mut self, structure: Structure) { unsafe { let ptr = ffi::gst_caps_merge_structure(self.as_mut_ptr(), structure.into_glib_ptr()); self.replace_ptr(ptr); } } #[doc(alias = "gst_caps_merge_structure_full")] pub fn merge_structure_full(&mut self, structure: Structure, features: Option) { unsafe { let ptr = ffi::gst_caps_merge_structure_full( self.as_mut_ptr(), structure.into_glib_ptr(), features .map(|f| f.into_glib_ptr()) .unwrap_or(ptr::null_mut()), ); self.replace_ptr(ptr); } } #[doc(alias = "gst_caps_normalize")] pub fn normalize(&mut self) { unsafe { let ptr = ffi::gst_caps_normalize(self.as_mut_ptr()); self.replace_ptr(ptr); } } #[doc(alias = "gst_caps_simplify")] pub fn simplify(&mut self) { unsafe { let ptr = ffi::gst_caps_simplify(self.as_mut_ptr()); self.replace_ptr(ptr); } } #[doc(alias = "gst_caps_truncate")] pub fn truncate(&mut self) { unsafe { let ptr = ffi::gst_caps_truncate(self.as_mut_ptr()); self.replace_ptr(ptr); } } } impl str::FromStr for Caps { type Err = glib::BoolError; #[doc(alias = "gst_caps_from_string")] fn from_str(s: &str) -> Result { assert_initialized_main_thread!(); unsafe { s.run_with_gstr(|s| { Option::<_>::from_glib_full(ffi::gst_caps_from_string(s.as_ptr())) .ok_or_else(|| glib::bool_error!("Failed to parse caps from string")) }) } } } impl From for Caps { fn from(v: Structure) -> Caps { skip_assert_initialized!(); let mut caps = Caps::new_empty(); { let caps = caps.get_mut().unwrap(); caps.append_structure(v); } caps } } impl From<[Structure; N]> for Caps { fn from(v: [Structure; N]) -> Caps { skip_assert_initialized!(); let mut caps = Caps::new_empty(); { let caps = caps.get_mut().unwrap(); v.into_iter().for_each(|s| caps.append_structure(s)); } caps } } impl From<(Structure, CapsFeatures)> for Caps { fn from(v: (Structure, CapsFeatures)) -> Caps { skip_assert_initialized!(); let mut caps = Caps::new_empty(); { let caps = caps.get_mut().unwrap(); caps.append_structure_full(v.0, Some(v.1)); } caps } } impl From<[(Structure, CapsFeatures); N]> for Caps { fn from(v: [(Structure, CapsFeatures); N]) -> Caps { skip_assert_initialized!(); let mut caps = Caps::new_empty(); { let caps = caps.get_mut().unwrap(); v.into_iter() .for_each(|s| caps.append_structure_full(s.0, Some(s.1))); } caps } } impl From<[(Structure, Option); N]> for Caps { fn from(v: [(Structure, Option); N]) -> Caps { skip_assert_initialized!(); let mut caps = Caps::new_empty(); { let caps = caps.get_mut().unwrap(); v.into_iter() .for_each(|s| caps.append_structure_full(s.0, s.1)); } caps } } impl std::iter::FromIterator for Caps { fn from_iter>(iter: T) -> Self { skip_assert_initialized!(); let mut caps = Caps::new_empty(); { let caps = caps.get_mut().unwrap(); iter.into_iter().for_each(|s| caps.append_structure(s)); } caps } } impl std::iter::FromIterator<(Structure, CapsFeatures)> for Caps { fn from_iter>(iter: T) -> Self { skip_assert_initialized!(); let mut caps = Caps::new_empty(); { let caps = caps.get_mut().unwrap(); iter.into_iter() .for_each(|(s, f)| caps.append_structure_full(s, Some(f))); } caps } } impl std::iter::FromIterator<(Structure, Option)> for Caps { fn from_iter)>>(iter: T) -> Self { skip_assert_initialized!(); let mut caps = Caps::new_empty(); { let caps = caps.get_mut().unwrap(); iter.into_iter() .for_each(|(s, f)| caps.append_structure_full(s, f)); } caps } } impl std::iter::FromIterator for Caps { fn from_iter>(iter: T) -> Self { skip_assert_initialized!(); let mut caps = Caps::new_empty(); { let caps = caps.get_mut().unwrap(); iter.into_iter() .for_each(|other_caps| caps.append(other_caps)); } caps } } impl std::iter::Extend for CapsRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|s| self.append_structure(s)); } } impl std::iter::Extend<(Structure, CapsFeatures)> for CapsRef { fn extend>(&mut self, iter: T) { iter.into_iter() .for_each(|(s, f)| self.append_structure_full(s, Some(f))); } } impl std::iter::Extend<(Structure, Option)> for CapsRef { fn extend)>>(&mut self, iter: T) { iter.into_iter() .for_each(|(s, f)| self.append_structure_full(s, f)); } } impl std::iter::Extend for CapsRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|caps| self.append(caps)); } } impl CapsRef { // rustdoc-stripper-ignore-next /// Sets field `name` to the given value `value`. /// /// Overrides any default or previously defined value for `name`. #[doc(alias = "gst_caps_set_value")] #[doc(alias = "gst_caps_set_simple")] pub fn set(&mut self, name: impl IntoGStr, value: impl ToSendValue + Sync) { let value = value.to_send_value(); self.set_value(name, value); } // rustdoc-stripper-ignore-next /// Sets field `name` to the given value if the `predicate` evaluates to `true`. /// /// This has no effect if the `predicate` evaluates to `false`, /// i.e. default or previous value for `name` is kept. #[doc(alias = "gst_caps_set_value")] #[doc(alias = "gst_caps_set_simple")] pub fn set_if(&mut self, name: impl IntoGStr, value: impl ToSendValue + Sync, predicate: bool) { if predicate { self.set(name, value); } } // rustdoc-stripper-ignore-next /// Sets field `name` to the given inner value if `value` is `Some`. /// /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept. #[doc(alias = "gst_caps_set_value")] #[doc(alias = "gst_caps_set_simple")] pub fn set_if_some(&mut self, name: impl IntoGStr, value: Option) { if let Some(value) = value { self.set(name, value); } } // rustdoc-stripper-ignore-next /// Sets field `name` using the given `ValueType` `V` built from `iter`'s the `Item`s. /// /// Overrides any default or previously defined value for `name`. #[inline] pub fn set_from_iter + Sync>( &mut self, name: impl IntoGStr, iter: impl IntoIterator, ) { let iter = iter.into_iter().map(|item| item.to_send_value()); self.set(name, V::from_iter(iter)); } // rustdoc-stripper-ignore-next /// Sets field `name` using the given `ValueType` `V` built from `iter`'s Item`s, /// if `iter` is not empty. /// /// This has no effect if `iter` is empty, i.e. previous value for `name` is unchanged. #[inline] pub fn set_if_not_empty + Sync>( &mut self, name: impl IntoGStr, iter: impl IntoIterator, ) { let mut iter = iter.into_iter().peekable(); if iter.peek().is_some() { let iter = iter.map(|item| item.to_send_value()); self.set(name, V::from_iter(iter)); } } // rustdoc-stripper-ignore-next /// Sets field `name` to the given value `value`. /// /// Overrides any default or previously defined value for `name`. #[doc(alias = "gst_caps_set_value")] pub fn set_value(&mut self, name: impl IntoGStr, value: glib::SendValue) { unsafe { name.run_with_gstr(|name| { ffi::gst_caps_set_value(self.as_mut_ptr(), name.as_ptr(), value.to_glib_none().0) }); } } // rustdoc-stripper-ignore-next /// Sets field `name` to the given `value` if the `predicate` evaluates to `true`. /// /// This has no effect if the `predicate` evaluates to `false`, /// i.e. default or previous value for `name` is kept. #[doc(alias = "gst_caps_set_value")] pub fn set_value_if(&mut self, name: impl IntoGStr, value: SendValue, predicate: bool) { if predicate { self.set_value(name, value); } } // rustdoc-stripper-ignore-next /// Sets field `name` to the given inner value if `value` is `Some`. /// /// This has no effect if the value is `None`, i.e. default or previous value for `name` is kept. #[doc(alias = "gst_caps_set_value")] pub fn set_value_if_some(&mut self, name: impl IntoGStr, value: Option) { if let Some(value) = value { self.set_value(name, value); } } #[doc(alias = "get_structure")] #[doc(alias = "gst_caps_get_structure")] pub fn structure(&self, idx: usize) -> Option<&StructureRef> { if idx >= self.size() { return None; } unsafe { let structure = ffi::gst_caps_get_structure(self.as_ptr(), idx as u32); if structure.is_null() { return None; } Some(StructureRef::from_glib_borrow(structure)) } } #[doc(alias = "get_mut_structure")] #[doc(alias = "gst_caps_get_structure")] pub fn structure_mut(&mut self, idx: usize) -> Option<&mut StructureRef> { if idx >= self.size() { return None; } unsafe { let structure = ffi::gst_caps_get_structure(self.as_ptr(), idx as u32); if structure.is_null() { return None; } Some(StructureRef::from_glib_borrow_mut(structure)) } } #[doc(alias = "get_features")] #[doc(alias = "gst_caps_get_features")] pub fn features(&self, idx: usize) -> Option<&CapsFeaturesRef> { if idx >= self.size() { return None; } unsafe { let features = ffi::gst_caps_get_features(self.as_ptr(), idx as u32); Some(CapsFeaturesRef::from_glib_borrow(features)) } } #[doc(alias = "get_mut_features")] #[doc(alias = "gst_caps_get_features")] pub fn features_mut(&mut self, idx: usize) -> Option<&mut CapsFeaturesRef> { if idx >= self.size() { return None; } unsafe { let features = ffi::gst_caps_get_features(self.as_ptr(), idx as u32); Some(CapsFeaturesRef::from_glib_borrow_mut(features)) } } #[doc(alias = "gst_caps_set_features")] pub fn set_features(&mut self, idx: usize, features: Option) { assert!(idx < self.size()); unsafe { ffi::gst_caps_set_features( self.as_mut_ptr(), idx as u32, features .map(|f| f.into_glib_ptr()) .unwrap_or(ptr::null_mut()), ) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "gst_caps_set_features_simple")] pub fn set_features_simple(&mut self, features: Option) { unsafe { ffi::gst_caps_set_features_simple( self.as_mut_ptr(), features .map(|f| f.into_glib_ptr()) .unwrap_or(ptr::null_mut()), ) } } #[doc(alias = "get_size")] #[doc(alias = "gst_caps_get_size")] pub fn size(&self) -> usize { unsafe { ffi::gst_caps_get_size(self.as_ptr()) as usize } } pub fn len(&self) -> usize { self.size() } pub fn iter(&self) -> Iter { Iter::new(self) } pub fn iter_mut(&mut self) -> IterMut { IterMut::new(self) } pub fn iter_with_features(&self) -> IterFeatures { IterFeatures::new(self) } pub fn iter_with_features_mut(&mut self) -> IterFeaturesMut { IterFeaturesMut::new(self) } #[doc(alias = "gst_caps_append_structure")] pub fn append_structure(&mut self, structure: Structure) { unsafe { ffi::gst_caps_append_structure(self.as_mut_ptr(), structure.into_glib_ptr()) } } #[doc(alias = "gst_caps_append_structure_full")] pub fn append_structure_full(&mut self, structure: Structure, features: Option) { unsafe { ffi::gst_caps_append_structure_full( self.as_mut_ptr(), structure.into_glib_ptr(), features .map(|f| f.into_glib_ptr()) .unwrap_or(ptr::null_mut()), ) } } #[doc(alias = "gst_caps_remove_structure")] pub fn remove_structure(&mut self, idx: usize) { assert!(idx < self.size()); unsafe { ffi::gst_caps_remove_structure(self.as_mut_ptr(), idx as u32) } } #[doc(alias = "gst_caps_append")] pub fn append(&mut self, other: Caps) { unsafe { ffi::gst_caps_append(self.as_mut_ptr(), other.into_glib_ptr()) } } #[doc(alias = "gst_caps_can_intersect")] pub fn can_intersect(&self, other: &Self) -> bool { unsafe { from_glib(ffi::gst_caps_can_intersect(self.as_ptr(), other.as_ptr())) } } #[doc(alias = "gst_caps_intersect")] pub fn intersect(&self, other: &Self) -> Caps { unsafe { from_glib_full(ffi::gst_caps_intersect( self.as_mut_ptr(), other.as_mut_ptr(), )) } } #[doc(alias = "gst_caps_intersect_full")] pub fn intersect_with_mode(&self, other: &Self, mode: CapsIntersectMode) -> Caps { unsafe { from_glib_full(ffi::gst_caps_intersect_full( self.as_mut_ptr(), other.as_mut_ptr(), mode.into_glib(), )) } } #[doc(alias = "gst_caps_is_always_compatible")] pub fn is_always_compatible(&self, other: &Self) -> bool { unsafe { from_glib(ffi::gst_caps_is_always_compatible( self.as_ptr(), other.as_ptr(), )) } } #[doc(alias = "gst_caps_is_any")] pub fn is_any(&self) -> bool { unsafe { from_glib(ffi::gst_caps_is_any(self.as_ptr())) } } #[doc(alias = "gst_caps_is_empty")] pub fn is_empty(&self) -> bool { unsafe { from_glib(ffi::gst_caps_is_empty(self.as_ptr())) } } #[doc(alias = "gst_caps_is_fixed")] pub fn is_fixed(&self) -> bool { unsafe { from_glib(ffi::gst_caps_is_fixed(self.as_ptr())) } } #[doc(alias = "gst_caps_is_equal_fixed")] pub fn is_equal_fixed(&self, other: &Self) -> bool { unsafe { from_glib(ffi::gst_caps_is_equal_fixed(self.as_ptr(), other.as_ptr())) } } #[doc(alias = "gst_caps_is_strictly_equal")] pub fn is_strictly_equal(&self, other: &Self) -> bool { unsafe { from_glib(ffi::gst_caps_is_strictly_equal( self.as_ptr(), other.as_ptr(), )) } } #[doc(alias = "gst_caps_is_subset")] pub fn is_subset(&self, superset: &Self) -> bool { unsafe { from_glib(ffi::gst_caps_is_subset(self.as_ptr(), superset.as_ptr())) } } #[doc(alias = "gst_caps_is_subset_structure")] pub fn is_subset_structure(&self, structure: &StructureRef) -> bool { unsafe { from_glib(ffi::gst_caps_is_subset_structure( self.as_ptr(), structure.as_ptr(), )) } } #[doc(alias = "gst_caps_is_subset_structure_full")] pub fn is_subset_structure_full( &self, structure: &StructureRef, features: Option<&CapsFeaturesRef>, ) -> bool { unsafe { from_glib(ffi::gst_caps_is_subset_structure_full( self.as_ptr(), structure.as_ptr(), features.map(|f| f.as_ptr()).unwrap_or(ptr::null()), )) } } #[doc(alias = "gst_caps_subtract")] pub fn subtract(&self, other: &Self) -> Caps { unsafe { from_glib_full(ffi::gst_caps_subtract( self.as_mut_ptr(), other.as_mut_ptr(), )) } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[doc(alias = "gst_caps_serialize")] pub fn serialize(&self, flags: crate::SerializeFlags) -> glib::GString { unsafe { from_glib_full(ffi::gst_caps_serialize(&self.0, flags.into_glib())) } } #[doc(alias = "gst_caps_foreach")] pub fn foreach std::ops::ControlFlow<()>>( &self, mut func: F, ) -> bool { unsafe { unsafe extern "C" fn trampoline< F: FnMut(&CapsFeaturesRef, &StructureRef) -> std::ops::ControlFlow<()>, >( features: *mut ffi::GstCapsFeatures, s: *mut ffi::GstStructure, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let func = &mut *(user_data as *mut F); let res = func( CapsFeaturesRef::from_glib_borrow(features), StructureRef::from_glib_borrow(s), ); matches!(res, std::ops::ControlFlow::Continue(_)).into_glib() } let func = &mut func as *mut F; from_glib(ffi::gst_caps_foreach( self.as_ptr(), Some(trampoline::), func as glib::ffi::gpointer, )) } } #[doc(alias = "gst_caps_map_in_place")] pub fn map_in_place< F: FnMut(&mut CapsFeaturesRef, &mut StructureRef) -> std::ops::ControlFlow<()>, >( &mut self, mut func: F, ) -> bool { unsafe { unsafe extern "C" fn trampoline< F: FnMut(&mut CapsFeaturesRef, &mut StructureRef) -> std::ops::ControlFlow<()>, >( features: *mut ffi::GstCapsFeatures, s: *mut ffi::GstStructure, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let func = &mut *(user_data as *mut F); let res = func( CapsFeaturesRef::from_glib_borrow_mut(features), StructureRef::from_glib_borrow_mut(s), ); matches!(res, std::ops::ControlFlow::Continue(_)).into_glib() } let func = &mut func as *mut F; from_glib(ffi::gst_caps_map_in_place( self.as_mut_ptr(), Some(trampoline::), func as glib::ffi::gpointer, )) } } #[doc(alias = "gst_caps_filter_and_map_in_place")] pub fn filter_map_in_place< F: FnMut(&mut CapsFeaturesRef, &mut StructureRef) -> CapsFilterMapAction, >( &mut self, mut func: F, ) { unsafe { unsafe extern "C" fn trampoline< F: FnMut(&mut CapsFeaturesRef, &mut StructureRef) -> CapsFilterMapAction, >( features: *mut ffi::GstCapsFeatures, s: *mut ffi::GstStructure, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let func = &mut *(user_data as *mut F); let res = func( CapsFeaturesRef::from_glib_borrow_mut(features), StructureRef::from_glib_borrow_mut(s), ); match res { CapsFilterMapAction::Keep => glib::ffi::GTRUE, CapsFilterMapAction::Remove => glib::ffi::GFALSE, } } let func = &mut func as *mut F; ffi::gst_caps_filter_and_map_in_place( self.as_mut_ptr(), Some(trampoline::), func as glib::ffi::gpointer, ); } } } #[derive(Debug)] pub enum CapsFilterMapAction { Keep, Remove, } macro_rules! define_iter( ($name:ident, $typ:ty, $styp:ty, $get_item:expr) => { #[derive(Debug)] pub struct $name<'a> { caps: $typ, idx: usize, n_structures: usize, } impl<'a> $name<'a> { fn new(caps: $typ) -> $name<'a> { skip_assert_initialized!(); let n_structures = caps.size(); $name { caps, idx: 0, n_structures: n_structures as usize, } } } #[allow(clippy::redundant_closure_call)] impl<'a> Iterator for $name<'a> { type Item = $styp; fn next(&mut self) -> Option { if self.idx >= self.n_structures { return None; } unsafe { let item = $get_item(self.caps, self.idx).unwrap(); self.idx += 1; Some(item) } } fn size_hint(&self) -> (usize, Option) { let remaining = self.n_structures - self.idx; (remaining, Some(remaining)) } fn count(self) -> usize { self.n_structures - self.idx } fn nth(&mut self, n: usize) -> Option { let (end, overflow) = self.idx.overflowing_add(n); if end >= self.n_structures || overflow { self.idx = self.n_structures; None } else { unsafe { self.idx = end + 1; Some($get_item(self.caps, end).unwrap()) } } } fn last(self) -> Option { if self.idx == self.n_structures { None } else { unsafe { Some($get_item(self.caps, self.n_structures - 1).unwrap()) } } } } #[allow(clippy::redundant_closure_call)] impl<'a> DoubleEndedIterator for $name<'a> { fn next_back(&mut self) -> Option { if self.idx == self.n_structures { return None; } self.n_structures -= 1; unsafe { Some($get_item(self.caps, self.n_structures).unwrap()) } } fn nth_back(&mut self, n: usize) -> Option { let (end, overflow) = self.n_structures.overflowing_sub(n); if end <= self.idx || overflow { self.idx = self.n_structures; None } else { self.n_structures = end - 1; unsafe { Some($get_item(self.caps, self.n_structures).unwrap()) } } } } impl<'a> ExactSizeIterator for $name<'a> {} impl<'a> std::iter::FusedIterator for $name<'a> {} } ); define_iter!( Iter, &'a CapsRef, &'a StructureRef, |caps: &CapsRef, idx| { let ptr = ffi::gst_caps_get_structure(caps.as_ptr(), idx as u32); if ptr.is_null() { None } else { Some(StructureRef::from_glib_borrow( ptr as *const ffi::GstStructure, )) } } ); define_iter!( IterMut, &'a mut CapsRef, &'a mut StructureRef, |caps: &CapsRef, idx| { let ptr = ffi::gst_caps_get_structure(caps.as_ptr(), idx as u32); if ptr.is_null() { None } else { Some(StructureRef::from_glib_borrow_mut(ptr)) } } ); define_iter!( IterFeatures, &'a CapsRef, (&'a StructureRef, &'a CapsFeaturesRef), |caps: &CapsRef, idx| { let ptr1 = ffi::gst_caps_get_structure(caps.as_ptr(), idx as u32); let ptr2 = ffi::gst_caps_get_features(caps.as_ptr(), idx as u32); if ptr1.is_null() || ptr2.is_null() { None } else { Some(( StructureRef::from_glib_borrow(ptr1), CapsFeaturesRef::from_glib_borrow(ptr2), )) } } ); define_iter!( IterFeaturesMut, &'a mut CapsRef, (&'a mut StructureRef, &'a mut CapsFeaturesRef), |caps: &CapsRef, idx| { let ptr1 = ffi::gst_caps_get_structure(caps.as_ptr(), idx as u32); let ptr2 = ffi::gst_caps_get_features(caps.as_ptr(), idx as u32); if ptr1.is_null() || ptr2.is_null() { None } else { Some(( StructureRef::from_glib_borrow_mut(ptr1), CapsFeaturesRef::from_glib_borrow_mut(ptr2), )) } } ); impl<'a> IntoIterator for &'a CapsRef { type IntoIter = IterFeatures<'a>; type Item = (&'a StructureRef, &'a CapsFeaturesRef); fn into_iter(self) -> Self::IntoIter { self.iter_with_features() } } impl<'a> IntoIterator for &'a mut CapsRef { type IntoIter = IterFeaturesMut<'a>; type Item = (&'a mut StructureRef, &'a mut CapsFeaturesRef); fn into_iter(self) -> Self::IntoIter { self.iter_with_features_mut() } } impl fmt::Debug for Caps { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } impl fmt::Display for Caps { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ::fmt(self, f) } } impl PartialEq for Caps { fn eq(&self, other: &Caps) -> bool { CapsRef::eq(self, other) } } impl Eq for Caps {} impl PartialEq for Caps { fn eq(&self, other: &CapsRef) -> bool { CapsRef::eq(self, other) } } impl PartialEq for CapsRef { fn eq(&self, other: &Caps) -> bool { CapsRef::eq(other, self) } } impl fmt::Debug for CapsRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.is_any() { f.debug_tuple("Caps(\"ANY\")").finish() } else if self.is_empty() { f.debug_tuple("Caps(\"EMPTY\")").finish() } else { let mut debug = f.debug_tuple("Caps"); for (structure, features) in self.iter_with_features() { struct WithFeatures<'a> { features: &'a CapsFeaturesRef, structure: &'a StructureRef, } impl fmt::Debug for WithFeatures<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let name = format!("{}({})", self.structure.name(), self.features); let mut debug = f.debug_struct(&name); for (id, field) in self.structure.iter() { if field.type_() == Structure::static_type() { let s = field.get::().unwrap(); debug.field(id, &s); } else if field.type_() == crate::Array::static_type() { let arr = field.get::().unwrap(); debug.field(id, &arr); } else if field.type_() == crate::List::static_type() { let list = field.get::().unwrap(); debug.field(id, &list); } else { debug.field(id, &field); } } debug.finish() } } debug.field(&WithFeatures { structure, features, }); } debug.finish() } } } impl fmt::Display for CapsRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = unsafe { glib::GString::from_glib_full(ffi::gst_caps_to_string(self.as_ptr())) }; f.write_str(&s) } } impl PartialEq for CapsRef { #[doc(alias = "gst_caps_is_equal")] fn eq(&self, other: &CapsRef) -> bool { unsafe { from_glib(ffi::gst_caps_is_equal(self.as_ptr(), other.as_ptr())) } } } impl Eq for CapsRef {} pub enum NoFeature {} pub enum HasFeatures {} #[must_use = "The builder must be built to be used"] pub struct Builder { s: crate::Structure, features: Option, phantom: PhantomData, } impl fmt::Debug for Builder { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Builder") .field("s", &self.s) .field("features", &self.features) .field("phantom", &self.phantom) .finish() } } impl Builder { fn new(name: impl IntoGStr) -> Builder { skip_assert_initialized!(); Builder { s: crate::Structure::new_empty(name), features: None, phantom: PhantomData, } } pub fn features( self, features: impl IntoIterator, ) -> Builder { Builder { s: self.s, features: Some(CapsFeatures::new(features)), phantom: PhantomData, } } pub fn any_features(self) -> Builder { Builder { s: self.s, features: Some(CapsFeatures::new_any()), phantom: PhantomData, } } } impl Builder { // rustdoc-stripper-ignore-next /// Sets field `name` to the given value `value`. /// /// Overrides any default or previously defined value for `name`. #[inline] pub fn field(mut self, name: impl IntoGStr, value: impl Into + Send) -> Self { self.s.set(name, value); self } impl_builder_gvalue_extra_setters!(field); #[must_use = "Building the caps without using them has no effect"] pub fn build(self) -> Caps { let mut caps = Caps::new_empty(); caps.get_mut() .unwrap() .append_structure_full(self.s, self.features); caps } pub fn structure(&self) -> &crate::Structure { &self.s } } pub enum AnyFeatures {} pub enum SomeFeatures {} #[must_use = "The builder must be built to be used"] pub struct BuilderFull { caps: crate::Caps, features: Option, phantom: PhantomData, } impl fmt::Debug for BuilderFull { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Builder") .field("caps", &self.caps) .field("features", &self.features) .field("phantom", &self.phantom) .finish() } } impl BuilderFull { fn new() -> Self { BuilderFull { caps: Caps::new_empty(), features: None, phantom: PhantomData, } } fn with_features(features: CapsFeatures) -> Self { skip_assert_initialized!(); BuilderFull { caps: Caps::new_empty(), features: Some(features), phantom: PhantomData, } } pub fn structure_with_features(self, structure: Structure, features: CapsFeatures) -> Self { self.append_structure(structure, Some(features)) } pub fn structure_with_features_if_some( self, structure: Option, features: CapsFeatures, ) -> Self { if let Some(structure) = structure { self.structure_with_features(structure, features) } else { self } } pub fn structure_with_any_features(self, structure: Structure) -> Self { self.append_structure(structure, Some(CapsFeatures::new_any())) } pub fn structure_with_any_features_if_some(self, structure: Option) -> Self { if let Some(structure) = structure { self.structure_with_any_features(structure) } else { self } } } impl BuilderFull { fn with_any_features() -> Self { BuilderFull { caps: Caps::new_empty(), features: Some(CapsFeatures::new_any()), phantom: PhantomData, } } } impl BuilderFull { fn append_structure(mut self, structure: Structure, features: Option) -> Self { let features = { match self.features { None => features, Some(ref result) => { let mut result = result.clone(); match features { None => Some(result), Some(features) => { features.iter().for_each(|feat| result.add(feat)); Some(result) } } } } }; self.caps .get_mut() .unwrap() .append_structure_full(structure, features); self } pub fn structure(self, structure: Structure) -> Self { self.append_structure(structure, None) } pub fn structure_if_some(self, structure: Option) -> Self { if let Some(structure) = structure { self.structure(structure) } else { self } } #[must_use = "Building the caps without using them has no effect"] pub fn build(self) -> Caps { self.caps } } #[cfg(test)] mod tests { use super::*; use crate::{Array, Fraction}; #[test] fn test_builder() { crate::init().unwrap(); let mut caps = Caps::builder("foo/bar") .field("int", 12) .field("bool", true) .field("string", "bla") .field("fraction", Fraction::new(1, 2)) .field("array", Array::new([1, 2])) .build(); assert_eq!( caps.to_string(), "foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, fraction=(fraction)1/2, array=(int)< 1, 2 >" ); assert!(caps .features(0) .unwrap() .is_equal(crate::CAPS_FEATURES_MEMORY_SYSTEM_MEMORY.as_ref())); { let caps = caps.get_mut().unwrap(); caps.set_features(0, Some(CapsFeatures::new(["foo:bla"]))); } assert!(caps .features(0) .unwrap() .is_equal(CapsFeatures::new(["foo:bla"]).as_ref())); let caps = Caps::builder("foo/bar") .field("int", 12) .any_features() .build(); assert_eq!(caps.to_string(), "foo/bar(ANY), int=(int)12"); let caps = Caps::builder("foo/bar") .field("int", 12) .features(["foo:bla", "foo:baz"]) .build(); assert_eq!(caps.to_string(), "foo/bar(foo:bla, foo:baz), int=(int)12"); let caps = Caps::builder("foo/bar") .field_if_some("int0", Option::::None) .field_if_some("int1", Some(12)) .field_if_some("string0", Option::::None) .field_if_some("string1", Some("bla")) .build(); assert_eq!( caps.to_string(), "foo/bar, int1=(int)12, string1=(string)bla" ); } #[test] fn test_display() { crate::init().unwrap(); let caps = Caps::builder("foo/bar").build(); let _ = format!("{caps}"); } #[test] fn test_builder_full() { crate::init().unwrap(); let caps = Caps::builder_full() .structure(Structure::builder("audio/x-raw").build()) .structure(Structure::builder("video/x-raw").build()) .build(); assert_eq!(caps.to_string(), "audio/x-raw; video/x-raw"); let caps = Caps::builder_full() .structure( Structure::builder("audio/x-raw") .field("format", "S16LE") .build(), ) .structure(Structure::builder("video/x-raw").build()) .build(); assert_eq!( caps.to_string(), "audio/x-raw, format=(string)S16LE; video/x-raw" ); let caps = Caps::builder_full() .structure_with_any_features(Structure::builder("audio/x-raw").build()) .structure_with_features( Structure::builder("video/x-raw").build(), CapsFeatures::new(["foo:bla", "foo:baz"]), ) .build(); assert_eq!( caps.to_string(), "audio/x-raw(ANY); video/x-raw(foo:bla, foo:baz)" ); let caps = Caps::builder_full() .structure_if_some(Option::::None) .build(); assert!(caps.is_empty()); let caps = Caps::builder_full() .structure_if_some(Some(Structure::builder("audio/x-raw").build())) .build(); assert_eq!(caps.to_string(), "audio/x-raw"); let caps = Caps::builder_full() .structure_with_any_features_if_some(Some(Structure::builder("audio/x-raw").build())) .structure_with_features_if_some( Some(Structure::builder("video/x-raw").build()), CapsFeatures::new(["foo:bla", "foo:baz"]), ) .build(); assert_eq!( caps.to_string(), "audio/x-raw(ANY); video/x-raw(foo:bla, foo:baz)" ); let caps = Caps::builder_full() .structure_with_any_features_if_some(Option::::None) .structure_with_features_if_some( Option::::None, CapsFeatures::new(["foo:bla", "foo:baz"]), ) .build(); assert!(caps.is_empty()); } #[test] fn test_builder_full_with_features() { crate::init().unwrap(); let caps = Caps::builder_full_with_features(CapsFeatures::new(["foo:bla"])) .structure(Structure::builder("audio/x-raw").build()) .structure_with_features( Structure::builder("video/x-raw").build(), CapsFeatures::new(["foo:baz"]), ) .build(); assert_eq!( caps.to_string(), "audio/x-raw(foo:bla); video/x-raw(foo:bla, foo:baz)" ); } #[test] fn test_builder_full_with_any_features() { crate::init().unwrap(); let caps = Caps::builder_full_with_any_features() .structure(Structure::builder("audio/x-raw").build()) .structure(Structure::builder("video/x-raw").build()) .build(); assert_eq!(caps.to_string(), "audio/x-raw(ANY); video/x-raw(ANY)"); let caps = Caps::builder_full_with_any_features() .structure(Structure::builder("audio/x-raw").build()) .build(); assert_eq!(caps.to_string(), "audio/x-raw(ANY)"); } #[test] fn test_new_from_iter() { crate::init().unwrap(); let caps = Caps::builder_full_with_any_features() .structure(Structure::builder("audio/x-raw").build()) .structure(Structure::builder("video/x-raw").build()) .build(); let audio = caps .iter() .filter(|s| s.name() == "audio/x-raw") .map(|s| s.to_owned()) .collect::(); assert_eq!(audio.to_string(), "audio/x-raw"); let audio = caps .iter_with_features() .filter(|(s, _)| s.name() == "audio/x-raw") .map(|(s, c)| (s.to_owned(), c.to_owned())) .collect::(); assert_eq!(audio.to_string(), "audio/x-raw(ANY)"); } #[test] fn test_debug() { crate::init().unwrap(); let caps = Caps::new_any(); assert_eq!(format!("{caps:?}"), "Caps(\"ANY\")"); let caps = Caps::new_empty(); assert_eq!(format!("{caps:?}"), "Caps(\"EMPTY\")"); let caps = Caps::builder_full_with_any_features() .structure(Structure::builder("audio/x-raw").build()) .build(); assert_eq!(format!("{caps:?}"), "Caps(audio/x-raw(ANY))"); let caps = Caps::builder_full_with_features(CapsFeatures::new(["foo:bla"])) .structure( Structure::builder("audio/x-raw") .field( "struct", Structure::builder("nested").field("badger", true).build(), ) .build(), ) .structure( Structure::builder("video/x-raw") .field("width", 800u32) .build(), ) .build(); assert_eq!(format!("{caps:?}"), "Caps(audio/x-raw(foo:bla) { struct: Structure(nested { badger: (gboolean) TRUE }) }, video/x-raw(foo:bla) { width: (guint) 800 })"); let caps = Caps::builder_full() .structure( Structure::builder("video/x-raw") .field("array", crate::Array::new(["a", "b", "c"])) .field("list", crate::List::new(["d", "e", "f"])) .build(), ) .build(); assert_eq!(format!("{caps:?}"), "Caps(video/x-raw(memory:SystemMemory) { array: Array([(gchararray) \"a\", (gchararray) \"b\", (gchararray) \"c\"]), list: List([(gchararray) \"d\", (gchararray) \"e\", (gchararray) \"f\"]) })"); } } gstreamer-0.23.5/src/caps_features.rs000064400000000000000000000613241046102023000156730ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ borrow::{Borrow, BorrowMut, ToOwned}, fmt, marker::PhantomData, mem, ops::{Deref, DerefMut}, ptr, str, }; use crate::ffi; use glib::{prelude::*, translate::*}; use once_cell::sync::Lazy; #[doc(alias = "GstCapsFeatures")] #[repr(transparent)] pub struct CapsFeatures(ptr::NonNull); unsafe impl Send for CapsFeatures {} unsafe impl Sync for CapsFeatures {} impl CapsFeatures { #[doc(alias = "gst_caps_features_new")] pub fn new(features: impl IntoIterator) -> Self { skip_assert_initialized!(); let mut f = Self::new_empty(); for feature in features { f.add(feature); } f } #[doc(alias = "gst_caps_features_new_id")] pub fn from_quarks(features: impl IntoIterator) -> Self { skip_assert_initialized!(); let mut f = Self::new_empty(); for feature in features.into_iter() { f.add_from_quark(feature); } f } #[doc(alias = "gst_caps_features_new_empty")] pub fn new_empty() -> Self { assert_initialized_main_thread!(); unsafe { CapsFeatures(ptr::NonNull::new_unchecked( ffi::gst_caps_features_new_empty(), )) } } #[doc(alias = "gst_caps_features_new_any")] pub fn new_any() -> Self { assert_initialized_main_thread!(); unsafe { CapsFeatures(ptr::NonNull::new_unchecked(ffi::gst_caps_features_new_any())) } } } impl IntoGlibPtr<*mut ffi::GstCapsFeatures> for CapsFeatures { #[inline] unsafe fn into_glib_ptr(self) -> *mut ffi::GstCapsFeatures { let s = mem::ManuallyDrop::new(self); s.0.as_ptr() } } impl Deref for CapsFeatures { type Target = CapsFeaturesRef; #[inline] fn deref(&self) -> &CapsFeaturesRef { unsafe { &*(self.0.as_ref() as *const ffi::GstCapsFeatures as *const CapsFeaturesRef) } } } impl DerefMut for CapsFeatures { #[inline] fn deref_mut(&mut self) -> &mut CapsFeaturesRef { unsafe { &mut *(self.0.as_mut() as *mut ffi::GstCapsFeatures as *mut CapsFeaturesRef) } } } impl AsRef for CapsFeatures { #[inline] fn as_ref(&self) -> &CapsFeaturesRef { self.deref() } } impl AsMut for CapsFeatures { #[inline] fn as_mut(&mut self) -> &mut CapsFeaturesRef { self.deref_mut() } } impl Clone for CapsFeatures { #[inline] fn clone(&self) -> Self { unsafe { let ptr = ffi::gst_caps_features_copy(self.0.as_ref()); debug_assert!(!ptr.is_null()); CapsFeatures(ptr::NonNull::new_unchecked(ptr)) } } } impl Drop for CapsFeatures { #[inline] fn drop(&mut self) { unsafe { ffi::gst_caps_features_free(self.0.as_mut()) } } } impl fmt::Debug for CapsFeatures { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("CapsFeatures") .field(&self.to_string()) .finish() } } impl fmt::Display for CapsFeatures { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Need to make sure to not call ToString::to_string() here, which // we have because of the Display impl. We need CapsFeaturesRef::to_string() f.write_str(&CapsFeaturesRef::to_string(self.as_ref())) } } impl str::FromStr for CapsFeatures { type Err = glib::BoolError; #[doc(alias = "gst_caps_features_from_string")] fn from_str(s: &str) -> Result { assert_initialized_main_thread!(); unsafe { let ptr = s.run_with_gstr(|s| ffi::gst_caps_features_from_string(s.as_ptr())); if ptr.is_null() { return Err(glib::bool_error!( "Failed to parse caps features from string" )); } Ok(Self(ptr::NonNull::new_unchecked(ptr))) } } } impl Borrow for CapsFeatures { #[inline] fn borrow(&self) -> &CapsFeaturesRef { self.as_ref() } } impl BorrowMut for CapsFeatures { #[inline] fn borrow_mut(&mut self) -> &mut CapsFeaturesRef { self.as_mut() } } impl glib::types::StaticType for CapsFeatures { #[inline] fn static_type() -> glib::types::Type { unsafe { from_glib(ffi::gst_caps_features_get_type()) } } } impl<'a> ToGlibPtr<'a, *const ffi::GstCapsFeatures> for CapsFeatures { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *const ffi::GstCapsFeatures, Self> { unsafe { Stash(self.0.as_ref(), PhantomData) } } #[inline] fn to_glib_full(&self) -> *const ffi::GstCapsFeatures { unsafe { ffi::gst_caps_features_copy(self.0.as_ref()) } } } impl<'a> ToGlibPtr<'a, *mut ffi::GstCapsFeatures> for CapsFeatures { type Storage = PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::GstCapsFeatures, Self> { unsafe { Stash( self.0.as_ref() as *const ffi::GstCapsFeatures as *mut ffi::GstCapsFeatures, PhantomData, ) } } #[inline] fn to_glib_full(&self) -> *mut ffi::GstCapsFeatures { unsafe { ffi::gst_caps_features_copy(self.0.as_ref()) } } } impl<'a> ToGlibPtrMut<'a, *mut ffi::GstCapsFeatures> for CapsFeatures { type Storage = PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'a mut self) -> StashMut<'a, *mut ffi::GstCapsFeatures, Self> { unsafe { StashMut(self.0.as_mut(), PhantomData) } } } impl FromGlibPtrNone<*const ffi::GstCapsFeatures> for CapsFeatures { #[inline] unsafe fn from_glib_none(ptr: *const ffi::GstCapsFeatures) -> Self { debug_assert!(!ptr.is_null()); let ptr = ffi::gst_caps_features_copy(ptr); debug_assert!(!ptr.is_null()); CapsFeatures(ptr::NonNull::new_unchecked(ptr)) } } impl FromGlibPtrNone<*mut ffi::GstCapsFeatures> for CapsFeatures { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::GstCapsFeatures) -> Self { debug_assert!(!ptr.is_null()); let ptr = ffi::gst_caps_features_copy(ptr); debug_assert!(!ptr.is_null()); CapsFeatures(ptr::NonNull::new_unchecked(ptr)) } } impl FromGlibPtrFull<*const ffi::GstCapsFeatures> for CapsFeatures { #[inline] unsafe fn from_glib_full(ptr: *const ffi::GstCapsFeatures) -> Self { debug_assert!(!ptr.is_null()); CapsFeatures(ptr::NonNull::new_unchecked( ptr as *mut ffi::GstCapsFeatures, )) } } impl FromGlibPtrFull<*mut ffi::GstCapsFeatures> for CapsFeatures { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::GstCapsFeatures) -> Self { debug_assert!(!ptr.is_null()); CapsFeatures(ptr::NonNull::new_unchecked(ptr)) } } impl glib::value::ValueType for CapsFeatures { type Type = Self; } impl glib::value::ValueTypeOptional for CapsFeatures {} unsafe impl<'a> glib::value::FromValue<'a> for CapsFeatures { type Checker = glib::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib_none(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut ffi::GstCapsFeatures) } } impl glib::value::ToValue for CapsFeatures { fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(self).0 as *mut _, ) } value } fn value_type(&self) -> glib::Type { Self::static_type() } } impl glib::value::ToValueOptional for CapsFeatures { fn to_value_optional(s: Option<&Self>) -> glib::Value { skip_assert_initialized!(); let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, ToGlibPtr::<*mut ffi::GstCapsFeatures>::to_glib_none(&s).0 as *mut _, ) } value } } impl From for glib::Value { fn from(v: CapsFeatures) -> glib::Value { skip_assert_initialized!(); let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, IntoGlibPtr::<*mut ffi::GstCapsFeatures>::into_glib_ptr(v) as *mut _, ) } value } } impl GlibPtrDefault for CapsFeatures { type GlibType = *mut ffi::GstCapsFeatures; } unsafe impl TransparentPtrType for CapsFeatures {} #[repr(transparent)] #[doc(alias = "GstCapsFeatures")] pub struct CapsFeaturesRef(ffi::GstCapsFeatures); impl CapsFeaturesRef { #[inline] pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstCapsFeatures) -> &'a CapsFeaturesRef { debug_assert!(!ptr.is_null()); &*(ptr as *mut CapsFeaturesRef) } #[inline] pub unsafe fn from_glib_borrow_mut<'a>( ptr: *mut ffi::GstCapsFeatures, ) -> &'a mut CapsFeaturesRef { debug_assert!(!ptr.is_null()); &mut *(ptr as *mut CapsFeaturesRef) } #[inline] pub fn as_ptr(&self) -> *const ffi::GstCapsFeatures { self as *const Self as *const ffi::GstCapsFeatures } #[inline] pub fn as_mut_ptr(&self) -> *mut ffi::GstCapsFeatures { self as *const Self as *mut ffi::GstCapsFeatures } pub fn is_empty(&self) -> bool { self.size() == 0 && !self.is_any() } #[doc(alias = "gst_caps_features_is_any")] pub fn is_any(&self) -> bool { unsafe { from_glib(ffi::gst_caps_features_is_any(self.as_ptr())) } } #[doc(alias = "gst_caps_features_contains")] pub fn contains(&self, feature: impl IntoGStr) -> bool { unsafe { feature.run_with_gstr(|feature| { from_glib(ffi::gst_caps_features_contains( self.as_ptr(), feature.as_ptr(), )) }) } } #[doc(alias = "gst_caps_features_contains_id")] pub fn contains_quark(&self, feature: glib::Quark) -> bool { unsafe { from_glib(ffi::gst_caps_features_contains_id( self.as_ptr(), feature.into_glib(), )) } } #[doc(alias = "get_size")] #[doc(alias = "gst_caps_features_get_size")] pub fn size(&self) -> usize { unsafe { ffi::gst_caps_features_get_size(self.as_ptr()) as usize } } #[doc(alias = "get_nth")] #[doc(alias = "gst_caps_features_get_nth")] pub fn nth(&self, idx: usize) -> Option<&glib::GStr> { if idx >= self.size() { return None; } unsafe { let feature = ffi::gst_caps_features_get_nth(self.as_ptr(), idx as u32); if feature.is_null() { return None; } // Safety: we can return a GStr based on the feature here because // the lifetime of the returned value is constrained by &self. Some(glib::GStr::from_ptr(feature)) } } #[doc(alias = "gst_caps_features_get_nth_id")] pub fn nth_quark(&self, idx: usize) -> Option { if idx >= self.size() { return None; } unsafe { let feature = ffi::gst_caps_features_get_nth_id(self.as_ptr(), idx as u32); Some(from_glib(feature)) } } #[doc(alias = "gst_caps_features_add")] pub fn add(&mut self, feature: impl IntoGStr) { unsafe { feature.run_with_gstr(|feature| { ffi::gst_caps_features_add(self.as_mut_ptr(), feature.as_ptr()) }) } } #[doc(alias = "gst_caps_features_remove")] pub fn remove(&mut self, feature: impl IntoGStr) { unsafe { feature.run_with_gstr(|feature| { ffi::gst_caps_features_remove(self.as_mut_ptr(), feature.as_ptr()) }) } } #[doc(alias = "gst_caps_features_add_id")] pub fn add_from_quark(&mut self, feature: glib::Quark) { unsafe { ffi::gst_caps_features_add_id(self.as_mut_ptr(), feature.into_glib()) } } #[doc(alias = "gst_caps_features_remove_id")] pub fn remove_by_quark(&mut self, feature: glib::Quark) { unsafe { ffi::gst_caps_features_remove_id(self.as_mut_ptr(), feature.into_glib()) } } pub fn iter(&self) -> Iter { Iter::new(self) } // This is not an equivalence relation with regards to ANY. Everything is equal to ANY #[doc(alias = "gst_caps_features_is_equal")] pub fn is_equal(&self, other: &CapsFeaturesRef) -> bool { unsafe { from_glib(ffi::gst_caps_features_is_equal( self.as_ptr(), other.as_ptr(), )) } } } impl glib::types::StaticType for CapsFeaturesRef { #[inline] fn static_type() -> glib::types::Type { unsafe { from_glib(ffi::gst_structure_get_type()) } } } impl<'a> std::iter::Extend<&'a str> for CapsFeaturesRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|f| self.add(f)); } } impl<'a> std::iter::Extend<&'a glib::GStr> for CapsFeaturesRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|f| self.add(f)); } } impl std::iter::Extend for CapsFeaturesRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|f| self.add(&f)); } } impl std::iter::Extend for CapsFeaturesRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|f| self.add(&f)); } } impl std::iter::Extend for CapsFeaturesRef { fn extend>(&mut self, iter: T) { iter.into_iter().for_each(|f| self.add_from_quark(f)); } } unsafe impl<'a> glib::value::FromValue<'a> for &'a CapsFeaturesRef { type Checker = glib::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); &*(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const CapsFeaturesRef) } } impl glib::value::ToValue for CapsFeaturesRef { fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, self.as_mut_ptr() as *mut _, ) } value } fn value_type(&self) -> glib::Type { Self::static_type() } } impl glib::value::ToValueOptional for CapsFeaturesRef { fn to_value_optional(s: Option<&Self>) -> glib::Value { skip_assert_initialized!(); let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, s.map(|s| s.as_mut_ptr()).unwrap_or(ptr::null_mut()) as *mut _, ) } value } } #[derive(Debug)] pub struct Iter<'a> { caps_features: &'a CapsFeaturesRef, idx: usize, n_features: usize, } impl<'a> Iter<'a> { fn new(caps_features: &'a CapsFeaturesRef) -> Iter<'a> { skip_assert_initialized!(); let n_features = caps_features.size(); Iter { caps_features, idx: 0, n_features, } } } impl<'a> Iterator for Iter<'a> { type Item = &'a glib::GStr; fn next(&mut self) -> Option { if self.idx >= self.n_features { return None; } unsafe { let feature = ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.idx as u32); debug_assert!(!feature.is_null()); self.idx += 1; // Safety: we can return a GStr based on the feature here because the lifetime // of the returned Item is constrained by the underlying CapsFeatureRef. Some(glib::GStr::from_ptr(feature)) } } fn size_hint(&self) -> (usize, Option) { let remaining = self.n_features - self.idx; (remaining, Some(remaining)) } fn count(self) -> usize { self.n_features - self.idx } // checker-ignore-item fn nth(&mut self, n: usize) -> Option { let (end, overflow) = self.idx.overflowing_add(n); if end >= self.n_features || overflow { self.idx = self.n_features; None } else { unsafe { self.idx = end + 1; let feature = ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), end as u32); debug_assert!(!feature.is_null()); // Safety: we can return a GStr based on the feature here because the lifetime // of the returned Item is constrained by the underlying CapsFeatureRef. Some(glib::GStr::from_ptr(feature)) } } } fn last(self) -> Option { if self.idx == self.n_features { None } else { unsafe { let feature = ffi::gst_caps_features_get_nth( self.caps_features.as_ptr(), self.n_features as u32 - 1, ); debug_assert!(!feature.is_null()); // Safety: we can return a GStr based on the feature here because the lifetime // of the returned Item is constrained by the underlying CapsFeatureRef. Some(glib::GStr::from_ptr(feature)) } } } } impl DoubleEndedIterator for Iter<'_> { fn next_back(&mut self) -> Option { if self.idx == self.n_features { return None; } self.n_features -= 1; unsafe { let feature = ffi::gst_caps_features_get_nth(self.caps_features.as_ptr(), self.n_features as u32); debug_assert!(!feature.is_null()); // Safety: we can return a GStr based on the feature here because the lifetime // of the returned Item is constrained by the underlying CapsFeatureRef. Some(glib::GStr::from_ptr(feature)) } } fn nth_back(&mut self, n: usize) -> Option { let (end, overflow) = self.n_features.overflowing_sub(n); if end <= self.idx || overflow { self.idx = self.n_features; None } else { unsafe { self.n_features = end - 1; let feature = ffi::gst_caps_features_get_nth( self.caps_features.as_ptr(), self.n_features as u32, ); debug_assert!(!feature.is_null()); // Safety: we can return a GStr based on the feature here because the lifetime // of the returned Item is constrained by the underlying CapsFeatureRef. Some(glib::GStr::from_ptr(feature)) } } } } impl ExactSizeIterator for Iter<'_> {} impl std::iter::FusedIterator for Iter<'_> {} impl<'a> IntoIterator for &'a CapsFeaturesRef { type IntoIter = Iter<'a>; type Item = &'a glib::GStr; fn into_iter(self) -> Self::IntoIter { self.iter() } } impl<'a> From<&'a str> for CapsFeatures { fn from(value: &'a str) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); features.add(value); features } } impl<'a> From<&'a glib::GStr> for CapsFeatures { fn from(value: &'a glib::GStr) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); features.add(value); features } } impl From for CapsFeatures { fn from(value: glib::Quark) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); features.add_from_quark(value); features } } impl<'a, const N: usize> From<[&'a str; N]> for CapsFeatures { fn from(value: [&'a str; N]) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); value.into_iter().for_each(|f| features.add(f)); features } } impl<'a, const N: usize> From<[&'a glib::GStr; N]> for CapsFeatures { fn from(value: [&'a glib::GStr; N]) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); value.into_iter().for_each(|f| features.add(f)); features } } impl From<[String; N]> for CapsFeatures { fn from(value: [String; N]) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); value.into_iter().for_each(|f| features.add(&f)); features } } impl From<[glib::GString; N]> for CapsFeatures { fn from(value: [glib::GString; N]) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); value.into_iter().for_each(|f| features.add(&f)); features } } impl From<[glib::Quark; N]> for CapsFeatures { fn from(value: [glib::Quark; N]) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); value.into_iter().for_each(|f| features.add_from_quark(f)); features } } impl<'a> std::iter::FromIterator<&'a str> for CapsFeatures { fn from_iter>(iter: T) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); iter.into_iter().for_each(|f| features.add(f)); features } } impl<'a> std::iter::FromIterator<&'a glib::GStr> for CapsFeatures { fn from_iter>(iter: T) -> Self { assert_initialized_main_thread!(); let mut features = CapsFeatures::new_empty(); iter.into_iter().for_each(|f| features.add(f)); features } } impl std::iter::FromIterator for CapsFeatures { fn from_iter>(iter: T) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); iter.into_iter().for_each(|f| features.add(&f)); features } } impl std::iter::FromIterator for CapsFeatures { fn from_iter>(iter: T) -> Self { assert_initialized_main_thread!(); let mut features = CapsFeatures::new_empty(); iter.into_iter().for_each(|f| features.add(&f)); features } } impl std::iter::FromIterator for CapsFeatures { fn from_iter>(iter: T) -> Self { skip_assert_initialized!(); let mut features = CapsFeatures::new_empty(); iter.into_iter().for_each(|f| features.add_from_quark(f)); features } } impl fmt::Debug for CapsFeaturesRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("CapsFeatures") .field(&self.to_string()) .finish() } } impl fmt::Display for CapsFeaturesRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = unsafe { glib::GString::from_glib_full(ffi::gst_caps_features_to_string(self.as_ptr())) }; f.write_str(&s) } } impl ToOwned for CapsFeaturesRef { type Owned = CapsFeatures; #[inline] fn to_owned(&self) -> CapsFeatures { unsafe { from_glib_full(ffi::gst_caps_features_copy(self.as_ptr() as *const _) as *mut _) } } } unsafe impl Sync for CapsFeaturesRef {} unsafe impl Send for CapsFeaturesRef {} pub static CAPS_FEATURE_MEMORY_SYSTEM_MEMORY: &glib::GStr = unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY) }; pub static CAPS_FEATURES_MEMORY_SYSTEM_MEMORY: Lazy = Lazy::new(|| CapsFeatures::new([CAPS_FEATURE_MEMORY_SYSTEM_MEMORY])); #[cfg(test)] mod tests { use super::*; #[test] fn test_from_value_optional() { use glib::value::ToValue; crate::init().unwrap(); let a = None::.to_value(); assert!(a.get::>().unwrap().is_none()); let b = glib::value::Value::from(&CapsFeatures::new_empty()); assert!(b.get::>().unwrap().is_some()); } } gstreamer-0.23.5/src/caps_features_serde.rs000064400000000000000000000122741046102023000170550ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::fmt; use serde::{ de, de::{Deserialize, Deserializer, EnumAccess, SeqAccess, VariantAccess, Visitor}, ser::{Serialize, SerializeSeq, Serializer}, }; use crate::{CapsFeatures, CapsFeaturesRef}; enum CapsFeaturesVariantKinds { Any, Some, } const CAPS_FEATURES_VARIANT_ANY_ID: u32 = 0; const CAPS_FEATURES_VARIANT_ANY_STR: &str = "Any"; const CAPS_FEATURES_VARIANT_SOME_ID: u32 = 1; const CAPS_FEATURES_VARIANT_SOME_STR: &str = "Some"; const CAPS_FEATURES_VARIANT_NAMES: &[&str] = &[ CAPS_FEATURES_VARIANT_ANY_STR, CAPS_FEATURES_VARIANT_SOME_STR, ]; struct CapsFeaturesForIterSe<'a>(&'a CapsFeaturesRef); impl Serialize for CapsFeaturesForIterSe<'_> { fn serialize(&self, serializer: S) -> Result { let iter = self.0.iter(); let size = iter.size_hint().0; if size > 0 { let mut seq = serializer.serialize_seq(Some(size))?; for feature in iter { seq.serialize_element(feature.as_str())?; } seq.end() } else { let seq = serializer.serialize_seq(None)?; seq.end() } } } impl Serialize for CapsFeaturesRef { fn serialize(&self, serializer: S) -> Result { if self.is_any() { serializer.serialize_unit_variant( stringify!(CapsFeatures), CAPS_FEATURES_VARIANT_ANY_ID, CAPS_FEATURES_VARIANT_ANY_STR, ) } else { serializer.serialize_newtype_variant( stringify!(CapsFeatures), CAPS_FEATURES_VARIANT_SOME_ID, CAPS_FEATURES_VARIANT_SOME_STR, &CapsFeaturesForIterSe(self), ) } } } impl Serialize for CapsFeatures { fn serialize(&self, serializer: S) -> Result { self.as_ref().serialize(serializer) } } struct CapsFeaturesSome(CapsFeatures); struct CapsFeaturesSomeVisitor; impl<'de> Visitor<'de> for CapsFeaturesSomeVisitor { type Value = CapsFeaturesSome; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence of `&str`") } fn visit_seq>(self, mut seq: A) -> Result { let mut features = CapsFeatures::new_empty(); while let Some(feature) = seq.next_element::()? { features.add(feature.as_str()); } Ok(CapsFeaturesSome(features)) } } impl<'de> Deserialize<'de> for CapsFeaturesSome { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); deserializer.deserialize_seq(CapsFeaturesSomeVisitor) } } struct CapsFeaturesVariantKindsVisitor; impl Visitor<'_> for CapsFeaturesVariantKindsVisitor { type Value = CapsFeaturesVariantKinds; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a Caps variant kind (`Any` or `Some`)") } fn visit_u32(self, value: u32) -> Result { match value { CAPS_FEATURES_VARIANT_ANY_ID => Ok(CapsFeaturesVariantKinds::Any), CAPS_FEATURES_VARIANT_SOME_ID => Ok(CapsFeaturesVariantKinds::Some), _ => Err(de::Error::invalid_value( de::Unexpected::Unsigned(u64::from(value)), &self, )), } } fn visit_str(self, value: &str) -> Result { match value { CAPS_FEATURES_VARIANT_ANY_STR => Ok(CapsFeaturesVariantKinds::Any), CAPS_FEATURES_VARIANT_SOME_STR => Ok(CapsFeaturesVariantKinds::Some), _ => Err(de::Error::unknown_variant( value, CAPS_FEATURES_VARIANT_NAMES, )), } } } impl<'de> Deserialize<'de> for CapsFeaturesVariantKinds { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); deserializer.deserialize_identifier(CapsFeaturesVariantKindsVisitor) } } struct CapsFeaturesVisitor; impl<'de> Visitor<'de> for CapsFeaturesVisitor { type Value = CapsFeatures; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a CapsFeatures enum (`Any` or `Some()`)") } fn visit_enum>(self, data: A) -> Result { let res = match data.variant()? { (CapsFeaturesVariantKinds::Any, _v) => CapsFeatures::new_any(), (CapsFeaturesVariantKinds::Some, v) => v .newtype_variant::() .map(|caps_features_some| caps_features_some.0)?, }; Ok(res) } } impl<'de> Deserialize<'de> for CapsFeatures { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); deserializer.deserialize_enum( stringify!(Caps), CAPS_FEATURES_VARIANT_NAMES, CapsFeaturesVisitor, ) } } gstreamer-0.23.5/src/caps_serde.rs000064400000000000000000000404731046102023000151610ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::fmt; use serde::{ de, de::{Deserialize, Deserializer, EnumAccess, SeqAccess, VariantAccess, Visitor}, ser::{Serialize, SerializeSeq, SerializeTuple, Serializer}, }; use crate::{Caps, CapsFeatures, CapsFeaturesRef, CapsRef, Structure, StructureRef}; enum CapsVariantKinds { Any, Empty, Some, } const CAPS_VARIANT_ANY_ID: u32 = 0; const CAPS_VARIANT_ANY_STR: &str = "Any"; const CAPS_VARIANT_EMPTY_ID: u32 = 1; const CAPS_VARIANT_EMPTY_STR: &str = "Empty"; const CAPS_VARIANT_SOME_ID: u32 = 2; const CAPS_VARIANT_SOME_STR: &str = "Some"; const CAPS_VARIANT_NAMES: &[&str] = &[ CAPS_VARIANT_ANY_STR, CAPS_VARIANT_EMPTY_STR, CAPS_VARIANT_SOME_STR, ]; struct CapsItemSe<'a>(&'a StructureRef, Option<&'a CapsFeaturesRef>); impl Serialize for CapsItemSe<'_> { fn serialize(&self, serializer: S) -> Result { let mut tup = serializer.serialize_tuple(2)?; tup.serialize_element(self.0)?; tup.serialize_element(&self.1)?; tup.end() } } struct CapsForIterSe<'a>(&'a CapsRef); impl Serialize for CapsForIterSe<'_> { fn serialize(&self, serializer: S) -> Result { let iter = self.0.iter_with_features(); let size = iter.size_hint().0; if size > 0 { let mut seq = serializer.serialize_seq(Some(size))?; for (structure, features) in iter { let features = if !features.is_any() && features.is_equal(crate::CAPS_FEATURES_MEMORY_SYSTEM_MEMORY.as_ref()) { None } else { Some(features) }; seq.serialize_element(&CapsItemSe(structure, features))?; } seq.end() } else { let seq = serializer.serialize_seq(None)?; seq.end() } } } impl Serialize for CapsRef { fn serialize(&self, serializer: S) -> Result { if self.is_any() { serializer.serialize_unit_variant( stringify!(Caps), CAPS_VARIANT_ANY_ID, CAPS_VARIANT_ANY_STR, ) } else if self.is_empty() { serializer.serialize_unit_variant( stringify!(Caps), CAPS_VARIANT_EMPTY_ID, CAPS_VARIANT_EMPTY_STR, ) } else { serializer.serialize_newtype_variant( stringify!(Caps), CAPS_VARIANT_SOME_ID, CAPS_VARIANT_SOME_STR, &CapsForIterSe(self), ) } } } impl Serialize for Caps { fn serialize(&self, serializer: S) -> Result { ::serialize(self.as_ref(), serializer) } } struct CapsItemDe(Structure, Option); struct CapsItemVisitor; impl<'de> Visitor<'de> for CapsItemVisitor { type Value = CapsItemDe; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a tuple `(Structure, Option)`") } fn visit_seq>(self, mut seq: A) -> Result { let structure = seq .next_element::()? .ok_or_else(|| de::Error::custom("Expected a `Structure` for `Caps` item"))?; let features_option = seq.next_element::>()?.ok_or_else(|| { de::Error::custom("Expected an `Option` for `Caps` item") })?; Ok(CapsItemDe(structure, features_option)) } } impl<'de> Deserialize<'de> for CapsItemDe { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); deserializer.deserialize_tuple(2, CapsItemVisitor) } } struct CapsSome(Caps); struct CapsSomeVisitor; impl<'de> Visitor<'de> for CapsSomeVisitor { type Value = CapsSome; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence of `(Structure, Option)`") } fn visit_seq>(self, mut seq: A) -> Result { let mut caps = Caps::new_empty(); { let caps = caps.get_mut().unwrap(); while let Some(caps_item) = seq.next_element::()? { caps.append_structure_full(caps_item.0, caps_item.1); } } Ok(CapsSome(caps)) } } impl<'de> Deserialize<'de> for CapsSome { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); deserializer.deserialize_seq(CapsSomeVisitor) } } struct CapsVariantKindsVisitor; impl Visitor<'_> for CapsVariantKindsVisitor { type Value = CapsVariantKinds; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a Caps variant kind (`Any`, `None` or `Some`)") } fn visit_u32(self, value: u32) -> Result { match value { CAPS_VARIANT_ANY_ID => Ok(CapsVariantKinds::Any), CAPS_VARIANT_EMPTY_ID => Ok(CapsVariantKinds::Empty), CAPS_VARIANT_SOME_ID => Ok(CapsVariantKinds::Some), _ => Err(de::Error::invalid_value( de::Unexpected::Unsigned(u64::from(value)), &self, )), } } fn visit_str(self, value: &str) -> Result { match value { CAPS_VARIANT_ANY_STR => Ok(CapsVariantKinds::Any), CAPS_VARIANT_EMPTY_STR => Ok(CapsVariantKinds::Empty), CAPS_VARIANT_SOME_STR => Ok(CapsVariantKinds::Some), _ => Err(de::Error::unknown_variant(value, CAPS_VARIANT_NAMES)), } } } impl<'de> Deserialize<'de> for CapsVariantKinds { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); deserializer.deserialize_identifier(CapsVariantKindsVisitor) } } struct CapsVisitor; impl<'de> Visitor<'de> for CapsVisitor { type Value = Caps; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a Caps enum (`Any`, `None` or `Some()`)") } fn visit_enum>(self, data: A) -> Result { let res = match data.variant()? { (CapsVariantKinds::Any, _v) => Caps::new_any(), (CapsVariantKinds::Empty, _v) => Caps::new_empty(), (CapsVariantKinds::Some, v) => v .newtype_variant::() .map(|caps_some| caps_some.0)?, }; Ok(res) } } impl<'de> Deserialize<'de> for Caps { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); deserializer.deserialize_enum(stringify!(Caps), CAPS_VARIANT_NAMES, CapsVisitor) } } #[cfg(test)] mod tests { use crate::{Array, Caps, CapsFeatures, Fraction}; #[test] fn test_serialize() { crate::init().unwrap(); let caps = Caps::builder("foo/bar") .field("int", 12) .field("bool", true) .field("string", "bla") .field("fraction", Fraction::new(1, 2)) .field("array", Array::new([1, 2])) .build(); let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string()); let res = ron::ser::to_string_pretty(&caps, pretty_config); assert_eq!( Ok(concat!( "Some([", " ((\"foo/bar\", [", " (\"int\", \"i32\", 12),", " (\"bool\", \"bool\", true),", " (\"string\", \"String\", Some(\"bla\")),", " (\"fraction\", \"Fraction\", (1, 2)),", " (\"array\", \"Array\", [", " (\"i32\", 1),", " (\"i32\", 2),", " ]),", " ]), None),", "])" ) .to_owned()), res, ); let caps = Caps::builder("foo/bar") .field("int", 12) .field("bool", true) .field("string", "bla") .field("fraction", Fraction::new(1, 2)) .field("array", Array::new([1, 2])) .features(["foo:bar", "foo:baz"]) .build(); let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string()); let res = ron::ser::to_string_pretty(&caps, pretty_config); assert_eq!( Ok(concat!( "Some([", " ((\"foo/bar\", [", " (\"int\", \"i32\", 12),", " (\"bool\", \"bool\", true),", " (\"string\", \"String\", Some(\"bla\")),", " (\"fraction\", \"Fraction\", (1, 2)),", " (\"array\", \"Array\", [", " (\"i32\", 1),", " (\"i32\", 2),", " ]),", " ]), Some(Some([", " \"foo:bar\",", " \"foo:baz\",", " ]))),", "])" ) .to_owned()), res, ); let caps = Caps::builder("foo/bar") .field("int", 12) .field("bool", true) .field("string", "bla") .field("fraction", Fraction::new(1, 2)) .field("array", Array::new([1, 2])) .any_features() .build(); let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string()); let res = ron::ser::to_string_pretty(&caps, pretty_config.clone()); assert_eq!( Ok(concat!( "Some([", " ((\"foo/bar\", [", " (\"int\", \"i32\", 12),", " (\"bool\", \"bool\", true),", " (\"string\", \"String\", Some(\"bla\")),", " (\"fraction\", \"Fraction\", (1, 2)),", " (\"array\", \"Array\", [", " (\"i32\", 1),", " (\"i32\", 2),", " ]),", " ]), Some(Any)),", "])" ) .to_owned()), res, ); let caps_any = Caps::new_any(); let res = ron::ser::to_string_pretty(&caps_any, pretty_config.clone()); assert_eq!(Ok("Any".to_owned()), res); let caps_empty = Caps::new_empty(); let res = ron::ser::to_string_pretty(&caps_empty, pretty_config); assert_eq!(Ok("Empty".to_owned()), res); } #[test] fn test_deserialize() { use crate::Structure; crate::init().unwrap(); let caps_ron = "Any"; let caps: Caps = ron::de::from_str(caps_ron).unwrap(); assert!(caps.is_any()); let caps_ron = "Empty"; let caps: Caps = ron::de::from_str(caps_ron).unwrap(); assert!(caps.is_empty()); let caps_ron = r#" Some([ ( ("foo/bar", [ ("int", "i32", 12), ("bool", "bool", true), ("string", "String", Some("bla")), ("fraction", "Fraction", (1, 2)), ("array", "Array", [ ("i32", 1), ("i32", 2), ]), ]), None, ), ])"#; let caps: Caps = ron::de::from_str(caps_ron).unwrap(); let s = caps.structure(0).unwrap(); assert_eq!( s, Structure::builder("foo/bar",) .field("int", 12) .field("bool", true) .field("string", "bla") .field("fraction", Fraction::new(1, 2)) .field("array", Array::new([1, 2])) .build() .as_ref() ); let caps_ron = r#" Some([ ( ("foo/bar", [ ("int", "i32", 12), ("bool", "bool", true), ("string", "String", None), ("fraction", "Fraction", (1, 2)), ("array", "Array", [ ("i32", 1), ("i32", 2), ]), ]), Some(Some(["foo:bar", "foo:baz"])), ), ])"#; let caps: Caps = ron::de::from_str(caps_ron).unwrap(); let s = caps.structure(0).unwrap(); let str_none: Option<&str> = None; assert_eq!( s, Structure::builder("foo/bar",) .field("int", 12) .field("bool", true) .field("string", str_none) .field("fraction", Fraction::new(1, 2)) .field("array", Array::new([1, 2])) .build() .as_ref() ); let f = caps.features(0).unwrap(); assert!(f.is_equal(CapsFeatures::new(["foo:bar", "foo:baz"]).as_ref())); let caps_ron = r#" Some([ ( ("foo/bar", [ ("int", "i32", 12), ("bool", "bool", true), ("string", "String", Some("bla")), ("fraction", "Fraction", (1, 2)), ("array", "Array", [ ("i32", 1), ("i32", 2), ]), ]), Some(Any), ), ])"#; let caps: Caps = ron::de::from_str(caps_ron).unwrap(); let s = caps.structure(0).unwrap(); assert_eq!( s, Structure::builder("foo/bar",) .field("int", 12) .field("bool", true) .field("string", "bla") .field("fraction", Fraction::new(1, 2)) .field("array", Array::new([1, 2])) .build() .as_ref() ); let f = caps.features(0).unwrap(); assert!(f.is_any()); } #[test] fn test_serde_roundtrip() { crate::init().unwrap(); let caps = Caps::new_any(); let caps_ser = ron::ser::to_string(&caps).unwrap(); let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap(); assert!(caps_de.is_any()); let caps = Caps::new_empty(); let caps_ser = ron::ser::to_string(&caps).unwrap(); let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap(); assert!(caps_de.is_empty()); let caps = Caps::builder("foo/bar") .field("int", 12) .field("bool", true) .field("string", "bla") .field("fraction", Fraction::new(1, 2)) .field("array", Array::new([1, 2])) .build(); let caps_ser = ron::ser::to_string(&caps).unwrap(); let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap(); assert!(caps_de.is_strictly_equal(&caps)); let caps = Caps::builder("foo/bar") .field("int", 12) .field("bool", true) .field("string", "bla") .field("fraction", Fraction::new(1, 2)) .field("array", Array::new([1, 2])) .features(["foo:bar", "foo:baz"]) .build(); let caps_ser = ron::ser::to_string(&caps).unwrap(); let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap(); assert!(caps_de.is_strictly_equal(&caps)); let caps = Caps::builder("foo/bar") .field("int", 12) .field("bool", true) .field("string", "bla") .field("fraction", Fraction::new(1, 2)) .field("array", Array::new([1, 2])) .any_features() .build(); let caps_ser = ron::ser::to_string(&caps).unwrap(); let caps_de: Caps = ron::de::from_str(caps_ser.as_str()).unwrap(); assert!(caps_de.is_strictly_equal(&caps)); } } gstreamer-0.23.5/src/child_proxy.rs000064400000000000000000000042141046102023000153660ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ptr; use glib::{prelude::*, translate::*}; use crate::ChildProxy; mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait ChildProxyExtManual: sealed::Sealed + IsA + 'static { #[doc(alias = "gst_child_proxy_lookup")] fn lookup(&self, name: &str) -> Result<(glib::Object, glib::ParamSpec), glib::BoolError> { unsafe { let mut target = ptr::null_mut(); let mut pspec = ptr::null_mut(); let ret = from_glib(crate::ffi::gst_child_proxy_lookup( self.as_ref().to_glib_none().0, name.to_glib_none().0, &mut target, &mut pspec, )); if ret { Ok((from_glib_full(target), from_glib_none(pspec))) } else { Err(glib::bool_error!("Failed to find child property '{name}'")) } } } #[doc(alias = "get_child_property")] #[doc(alias = "gst_child_proxy_get")] #[track_caller] fn child_property glib::value::FromValue<'b> + 'static>(&self, name: &str) -> V { let (child, pspec) = self.lookup(name).unwrap(); child.property(pspec.name()) } #[doc(alias = "get_child_property")] #[doc(alias = "gst_child_proxy_get")] #[track_caller] fn child_property_value(&self, name: &str) -> glib::Value { let (child, pspec) = self.lookup(name).unwrap(); child.property_value(pspec.name()) } #[doc(alias = "gst_child_proxy_set")] #[track_caller] fn set_child_property(&self, name: &str, value: impl Into) { let (child, pspec) = self.lookup(name).unwrap(); child.set_property(pspec.name(), value) } #[doc(alias = "gst_child_proxy_set_property")] #[track_caller] fn set_child_property_from_value(&self, name: &str, value: &glib::Value) { let (child, pspec) = self.lookup(name).unwrap(); child.set_property_from_value(pspec.name(), value) } } impl> ChildProxyExtManual for O {} gstreamer-0.23.5/src/clock.rs000064400000000000000000000434701046102023000141440ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ cmp, marker::Unpin, pin::Pin, ptr, sync::{atomic, atomic::AtomicI32}, }; use futures_core::{Future, Stream}; use glib::{ ffi::{gboolean, gpointer}, prelude::*, translate::*, }; use libc::c_void; use crate::{ ffi, prelude::*, Clock, ClockEntryType, ClockError, ClockFlags, ClockReturn, ClockSuccess, ClockTime, ClockTimeDiff, }; glib::wrapper! { #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct ClockId(Shared); match fn { ref => |ptr| ffi::gst_clock_id_ref(ptr), unref => |ptr| ffi::gst_clock_id_unref(ptr), } } impl ClockId { #[doc(alias = "get_time")] #[doc(alias = "gst_clock_id_get_time")] #[doc(alias = "GST_CLOCK_ENTRY_TIME")] pub fn time(&self) -> ClockTime { unsafe { try_from_glib(ffi::gst_clock_id_get_time(self.to_glib_none().0)) .expect("undefined time") } } #[doc(alias = "gst_clock_id_unschedule")] pub fn unschedule(&self) { unsafe { ffi::gst_clock_id_unschedule(self.to_glib_none().0) } } #[doc(alias = "gst_clock_id_wait")] pub fn wait(&self) -> (Result, ClockTimeDiff) { unsafe { let mut jitter = 0; let res = try_from_glib(ffi::gst_clock_id_wait(self.to_glib_none().0, &mut jitter)); (res, jitter) } } #[doc(alias = "gst_clock_id_compare_func")] pub fn compare_by_time(&self, other: &Self) -> cmp::Ordering { unsafe { let res = ffi::gst_clock_id_compare_func(self.to_glib_none().0, other.to_glib_none().0); res.cmp(&0) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "get_clock")] #[doc(alias = "gst_clock_id_get_clock")] pub fn clock(&self) -> Option { unsafe { from_glib_full(ffi::gst_clock_id_get_clock(self.to_glib_none().0)) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "gst_clock_id_uses_clock")] pub fn uses_clock>(&self, clock: &P) -> bool { unsafe { from_glib(ffi::gst_clock_id_uses_clock( self.to_glib_none().0, clock.as_ref().as_ptr(), )) } } #[doc(alias = "get_type")] #[doc(alias = "GST_CLOCK_ENTRY_TYPE")] pub fn type_(&self) -> ClockEntryType { unsafe { let ptr = self.as_ptr() as *mut ffi::GstClockEntry; from_glib((*ptr).type_) } } #[doc(alias = "get_status")] #[doc(alias = "GST_CLOCK_ENTRY_STATUS")] pub fn status(&self) -> &AtomicClockReturn { unsafe { let ptr = self.as_ptr() as *mut ffi::GstClockEntry; &*((&(*ptr).status) as *const i32 as *const AtomicClockReturn) } } } #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct SingleShotClockId(ClockId); impl std::ops::Deref for SingleShotClockId { type Target = ClockId; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl From for ClockId { #[inline] fn from(id: SingleShotClockId) -> ClockId { skip_assert_initialized!(); id.0 } } impl TryFrom for SingleShotClockId { type Error = glib::BoolError; #[inline] fn try_from(id: ClockId) -> Result { skip_assert_initialized!(); match id.type_() { ClockEntryType::Single => Ok(SingleShotClockId(id)), _ => Err(glib::bool_error!("Not a single-shot clock id")), } } } impl SingleShotClockId { #[doc(alias = "gst_clock_id_compare_func")] #[inline] pub fn compare_by_time(&self, other: &Self) -> cmp::Ordering { self.0.compare_by_time(&other.0) } #[doc(alias = "gst_clock_id_wait_async")] pub fn wait_async(&self, func: F) -> Result where F: FnOnce(&Clock, Option, &ClockId) + Send + 'static, { unsafe extern "C" fn trampoline< F: FnOnce(&Clock, Option, &ClockId) + Send + 'static, >( clock: *mut ffi::GstClock, time: ffi::GstClockTime, id: gpointer, func: gpointer, ) -> gboolean { let f: &mut Option = &mut *(func as *mut Option); let f = f.take().unwrap(); f( &from_glib_borrow(clock), from_glib(time), &from_glib_borrow(id), ); glib::ffi::GTRUE } unsafe extern "C" fn destroy_notify< F: FnOnce(&Clock, Option, &ClockId) + Send + 'static, >( ptr: gpointer, ) { let _ = Box::>::from_raw(ptr as *mut _); } let func: Box> = Box::new(Some(func)); unsafe { try_from_glib(ffi::gst_clock_id_wait_async( self.to_glib_none().0, Some(trampoline::), Box::into_raw(func) as gpointer, Some(destroy_notify::), )) } } #[allow(clippy::type_complexity)] pub fn wait_async_future( &self, ) -> Result< Pin< Box< dyn Future, ClockId), ClockError>> + Send + 'static, >, >, ClockError, > { use futures_channel::oneshot; let (sender, receiver) = oneshot::channel(); self.wait_async(move |_clock, jitter, id| { if sender.send((jitter, id.clone())).is_err() { // Unschedule any future calls if the receiver end is disconnected id.unschedule(); } })?; Ok(Box::pin(async move { receiver.await.map_err(|_| ClockError::Unscheduled) })) } } #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct PeriodicClockId(ClockId); impl std::ops::Deref for PeriodicClockId { type Target = ClockId; #[inline] fn deref(&self) -> &Self::Target { &self.0 } } impl From for ClockId { #[inline] fn from(id: PeriodicClockId) -> ClockId { skip_assert_initialized!(); id.0 } } impl TryFrom for PeriodicClockId { type Error = glib::BoolError; #[inline] fn try_from(id: ClockId) -> Result { skip_assert_initialized!(); match id.type_() { ClockEntryType::Periodic => Ok(PeriodicClockId(id)), _ => Err(glib::bool_error!("Not a periodic clock id")), } } } impl PeriodicClockId { #[doc(alias = "get_interval")] #[doc(alias = "GST_CLOCK_ENTRY_INTERVAL")] #[inline] pub fn interval(&self) -> ClockTime { unsafe { let ptr = self.as_ptr() as *mut ffi::GstClockEntry; try_from_glib((*ptr).interval).expect("undefined interval") } } #[doc(alias = "gst_clock_id_compare_func")] #[inline] pub fn compare_by_time(&self, other: &Self) -> cmp::Ordering { self.0.compare_by_time(&other.0) } #[doc(alias = "gst_clock_id_wait_async")] pub fn wait_async(&self, func: F) -> Result where F: Fn(&Clock, Option, &ClockId) + Send + 'static, { unsafe extern "C" fn trampoline< F: Fn(&Clock, Option, &ClockId) + Send + 'static, >( clock: *mut ffi::GstClock, time: ffi::GstClockTime, id: gpointer, func: gpointer, ) -> gboolean { let f: &F = &*(func as *const F); f( &from_glib_borrow(clock), from_glib(time), &from_glib_borrow(id), ); glib::ffi::GTRUE } unsafe extern "C" fn destroy_notify< F: Fn(&Clock, Option, &ClockId) + Send + 'static, >( ptr: gpointer, ) { let _ = Box::::from_raw(ptr as *mut _); } let func: Box = Box::new(func); unsafe { try_from_glib(ffi::gst_clock_id_wait_async( self.to_glib_none().0, Some(trampoline::), Box::into_raw(func) as gpointer, Some(destroy_notify::), )) } } #[allow(clippy::type_complexity)] pub fn wait_async_stream( &self, ) -> Result< Pin, ClockId)> + Unpin + Send + 'static>>, ClockError, > { use futures_channel::mpsc; let (sender, receiver) = mpsc::unbounded(); self.wait_async(move |_clock, jitter, id| { if sender.unbounded_send((jitter, id.clone())).is_err() { // Unschedule any future calls if the receiver end is disconnected id.unschedule(); } })?; Ok(Box::pin(receiver)) } } #[repr(transparent)] #[derive(Debug)] pub struct AtomicClockReturn(AtomicI32); impl AtomicClockReturn { #[inline] pub fn load(&self) -> ClockReturn { unsafe { from_glib(self.0.load(atomic::Ordering::SeqCst)) } } #[inline] pub fn store(&self, val: ClockReturn) { self.0.store(val.into_glib(), atomic::Ordering::SeqCst) } #[inline] pub fn swap(&self, val: ClockReturn) -> ClockReturn { unsafe { from_glib(self.0.swap(val.into_glib(), atomic::Ordering::SeqCst)) } } #[inline] pub fn compare_exchange( &self, current: ClockReturn, new: ClockReturn, ) -> Result { unsafe { self.0 .compare_exchange( current.into_glib(), new.into_glib(), atomic::Ordering::SeqCst, atomic::Ordering::SeqCst, ) .map(|v| from_glib(v)) .map_err(|v| from_glib(v)) } } } unsafe impl Send for ClockId {} unsafe impl Sync for ClockId {} impl Clock { #[doc(alias = "gst_clock_adjust_with_calibration")] pub fn adjust_with_calibration( internal_target: ClockTime, cinternal: ClockTime, cexternal: ClockTime, cnum: u64, cdenom: u64, ) -> ClockTime { skip_assert_initialized!(); unsafe { try_from_glib(ffi::gst_clock_adjust_with_calibration( ptr::null_mut(), internal_target.into_glib(), cinternal.into_glib(), cexternal.into_glib(), cnum, cdenom, )) .expect("undefined ClockTime") } } #[doc(alias = "gst_clock_unadjust_with_calibration")] pub fn unadjust_with_calibration( external_target: ClockTime, cinternal: ClockTime, cexternal: ClockTime, cnum: u64, cdenom: u64, ) -> ClockTime { skip_assert_initialized!(); unsafe { try_from_glib(ffi::gst_clock_unadjust_with_calibration( ptr::null_mut(), external_target.into_glib(), cinternal.into_glib(), cexternal.into_glib(), cnum, cdenom, )) .expect("undefined ClockTime") } } } mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait ClockExtManual: sealed::Sealed + IsA + 'static { #[doc(alias = "gst_clock_new_periodic_id")] fn new_periodic_id(&self, start_time: ClockTime, interval: ClockTime) -> PeriodicClockId { assert_ne!(interval, ClockTime::ZERO); unsafe { PeriodicClockId(from_glib_full(ffi::gst_clock_new_periodic_id( self.as_ref().to_glib_none().0, start_time.into_glib(), interval.into_glib(), ))) } } #[doc(alias = "gst_clock_periodic_id_reinit")] fn periodic_id_reinit( &self, id: &PeriodicClockId, start_time: ClockTime, interval: ClockTime, ) -> Result<(), glib::BoolError> { unsafe { let res: bool = from_glib(ffi::gst_clock_periodic_id_reinit( self.as_ref().to_glib_none().0, id.to_glib_none().0, start_time.into_glib(), interval.into_glib(), )); if res { Ok(()) } else { Err(glib::bool_error!("Failed to reinit periodic clock id")) } } } #[doc(alias = "gst_clock_new_single_shot_id")] fn new_single_shot_id(&self, time: ClockTime) -> SingleShotClockId { unsafe { SingleShotClockId(from_glib_full(ffi::gst_clock_new_single_shot_id( self.as_ref().to_glib_none().0, time.into_glib(), ))) } } #[doc(alias = "gst_clock_single_shot_id_reinit")] fn single_shot_id_reinit( &self, id: &SingleShotClockId, time: ClockTime, ) -> Result<(), glib::BoolError> { unsafe { let res: bool = from_glib(ffi::gst_clock_single_shot_id_reinit( self.as_ref().to_glib_none().0, id.to_glib_none().0, time.into_glib(), )); if res { Ok(()) } else { Err(glib::bool_error!("Failed to reinit single shot clock id")) } } } fn set_clock_flags(&self, flags: ClockFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags |= flags.into_glib(); } } fn unset_clock_flags(&self, flags: ClockFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags &= !flags.into_glib(); } } #[doc(alias = "get_clock_flags")] fn clock_flags(&self) -> ClockFlags { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); from_glib((*ptr).flags) } } #[doc(alias = "gst_clock_get_calibration")] #[doc(alias = "get_calibration")] fn calibration(&self) -> (ClockTime, ClockTime, u64, u64) { unsafe { let mut internal = std::mem::MaybeUninit::uninit(); let mut external = std::mem::MaybeUninit::uninit(); let mut rate_num = std::mem::MaybeUninit::uninit(); let mut rate_denom = std::mem::MaybeUninit::uninit(); ffi::gst_clock_get_calibration( self.as_ref().to_glib_none().0, internal.as_mut_ptr(), external.as_mut_ptr(), rate_num.as_mut_ptr(), rate_denom.as_mut_ptr(), ); ( try_from_glib(internal.assume_init()).expect("mandatory glib value is None"), try_from_glib(external.assume_init()).expect("mandatory glib value is None"), rate_num.assume_init(), rate_denom.assume_init(), ) } } #[doc(alias = "gst_clock_set_calibration")] fn set_calibration( &self, internal: ClockTime, external: ClockTime, rate_num: u64, rate_denom: u64, ) { unsafe { ffi::gst_clock_set_calibration( self.as_ref().to_glib_none().0, internal.into_glib(), external.into_glib(), rate_num, rate_denom, ); } } } impl> ClockExtManual for O {} #[cfg(test)] mod tests { use std::sync::mpsc::channel; use super::*; use crate::SystemClock; #[test] fn test_wait() { crate::init().unwrap(); let clock = SystemClock::obtain(); let now = clock.time().unwrap(); let id = clock.new_single_shot_id(now + 20 * ClockTime::MSECOND); let (res, _) = id.wait(); assert!(res == Ok(ClockSuccess::Ok) || res == Err(ClockError::Early)); } #[test] fn test_wait_async() { crate::init().unwrap(); let (sender, receiver) = channel(); let clock = SystemClock::obtain(); let now = clock.time().unwrap(); let id = clock.new_single_shot_id(now + 20 * ClockTime::MSECOND); let res = id.wait_async(move |_, _, _| { sender.send(()).unwrap(); }); assert!(res == Ok(ClockSuccess::Ok)); assert_eq!(receiver.recv(), Ok(())); } #[test] fn test_wait_periodic() { crate::init().unwrap(); let clock = SystemClock::obtain(); let now = clock.time().unwrap(); let id = clock.new_periodic_id(now + 20 * ClockTime::MSECOND, 20 * ClockTime::MSECOND); let (res, _) = id.wait(); assert!(res == Ok(ClockSuccess::Ok) || res == Err(ClockError::Early)); let (res, _) = id.wait(); assert!(res == Ok(ClockSuccess::Ok) || res == Err(ClockError::Early)); } #[test] fn test_wait_async_periodic() { crate::init().unwrap(); let (sender, receiver) = channel(); let clock = SystemClock::obtain(); let now = clock.time().unwrap(); let id = clock.new_periodic_id(now + 20 * ClockTime::MSECOND, 20 * ClockTime::MSECOND); let res = id.wait_async(move |_, _, _| { let _ = sender.send(()); }); assert!(res == Ok(ClockSuccess::Ok)); assert_eq!(receiver.recv(), Ok(())); assert_eq!(receiver.recv(), Ok(())); } } gstreamer-0.23.5/src/context.rs000064400000000000000000000044521046102023000145320ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ffi::CStr, fmt}; use glib::translate::{from_glib, from_glib_full, IntoGlib, ToGlibPtr}; use crate::{ffi, StructureRef}; mini_object_wrapper!(Context, ContextRef, ffi::GstContext, || { ffi::gst_context_get_type() }); impl Context { #[doc(alias = "gst_context_new")] pub fn new(context_type: &str, persistent: bool) -> Self { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_context_new( context_type.to_glib_none().0, persistent.into_glib(), )) } } } impl ContextRef { #[doc(alias = "get_context_type")] #[doc(alias = "gst_context_get_context_type")] pub fn context_type(&self) -> &str { unsafe { let raw = ffi::gst_context_get_context_type(self.as_mut_ptr()); CStr::from_ptr(raw).to_str().unwrap() } } #[doc(alias = "gst_context_has_context_type")] pub fn has_context_type(&self, context_type: &str) -> bool { unsafe { from_glib(ffi::gst_context_has_context_type( self.as_mut_ptr(), context_type.to_glib_none().0, )) } } #[doc(alias = "gst_context_is_persistent")] pub fn is_persistent(&self) -> bool { unsafe { from_glib(ffi::gst_context_is_persistent(self.as_mut_ptr())) } } #[doc(alias = "get_structure")] #[doc(alias = "gst_context_get_structure")] pub fn structure(&self) -> &StructureRef { unsafe { StructureRef::from_glib_borrow(ffi::gst_context_get_structure(self.as_mut_ptr())) } } #[doc(alias = "get_mut_structure")] pub fn structure_mut(&mut self) -> &mut StructureRef { unsafe { StructureRef::from_glib_borrow_mut(ffi::gst_context_writable_structure( self.as_mut_ptr(), )) } } } impl fmt::Debug for Context { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ContextRef::fmt(self, f) } } impl fmt::Debug for ContextRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Context") .field("type", &self.context_type()) .field("structure", &self.structure()) .finish() } } gstreamer-0.23.5/src/control_binding.rs000064400000000000000000000022531046102023000162150ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::{prelude::*, translate::*}; use crate::{ClockTime, ControlBinding}; mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait ControlBindingExtManual: sealed::Sealed + IsA + 'static { #[doc(alias = "get_g_value_array")] #[doc(alias = "gst_control_binding_get_g_value_array")] fn g_value_array( &self, timestamp: ClockTime, interval: ClockTime, values: &mut [glib::Value], ) -> Result<(), glib::error::BoolError> { let n_values = values.len() as u32; unsafe { glib::result_from_gboolean!( crate::ffi::gst_control_binding_get_g_value_array( self.as_ref().to_glib_none().0, timestamp.into_glib(), interval.into_glib(), n_values, values.as_mut_ptr() as *mut glib::gobject_ffi::GValue, ), "Failed to get value array" ) } } } impl> ControlBindingExtManual for O {} gstreamer-0.23.5/src/control_source.rs000064400000000000000000000021651046102023000161050ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::{prelude::*, translate::*}; use crate::{ClockTime, ControlSource}; mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait ControlSourceExtManual: sealed::Sealed + IsA + 'static { #[doc(alias = "get_value_array")] #[doc(alias = "gst_control_source_get_value_array")] fn value_array( &self, timestamp: ClockTime, interval: ClockTime, values: &mut [f64], ) -> Result<(), glib::error::BoolError> { let n_values = values.len() as u32; unsafe { glib::result_from_gboolean!( crate::ffi::gst_control_source_get_value_array( self.as_ref().to_glib_none().0, timestamp.into_glib(), interval.into_glib(), n_values, values.to_glib_none().0, ), "Failed to get value array" ) } } } impl> ControlSourceExtManual for O {} gstreamer-0.23.5/src/date_time.rs000064400000000000000000000577711046102023000150150ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{cmp, fmt}; use glib::translate::*; use crate::{ffi, DateTime}; // Validate that the given values result in a valid DateTime fn validate( tzoffset: Option, year: i32, month: Option, day: Option, hour: Option, minute: Option, seconds: Option, ) -> Result<(), glib::BoolError> { skip_assert_initialized!(); // Check for valid ranges if year <= 0 || year > 9999 { return Err(glib::bool_error!( "Can't create DateTime: Year out of range" )); } if let Some(month) = month { if month <= 0 || month > 12 { return Err(glib::bool_error!( "Can't create DateTime: Month out of range" )); } } if let Some(day) = day { if day <= 0 || day > 31 { return Err(glib::bool_error!("Can't create DateTime: Day out of range")); } } if let Some(hour) = hour { if hour < 0 || hour >= 24 { return Err(glib::bool_error!( "Can't create DateTime: Hour out of range" )); } } if let Some(minute) = minute { if minute < 0 || minute >= 60 { return Err(glib::bool_error!( "Can't create DateTime: Minute out of range" )); } } if let Some(seconds) = seconds { if seconds < 0.0 || seconds >= 60.0 { return Err(glib::bool_error!( "Can't create DateTime: Seconds out of range" )); } } if let Some(tzoffset) = tzoffset { if tzoffset < -12.0 || tzoffset > 12.0 { return Err(glib::bool_error!( "Can't create DateTime: Timezone offset out of range" )); } } // If day is provided, month also has to be provided if day.is_some() && month.is_none() { return Err(glib::bool_error!( "Can't create DateTime: Need to provide month if providing day" )); } // If hour is provided, day also has to be provided if hour.is_some() && day.is_none() { return Err(glib::bool_error!( "Can't create DateTime: Need to provide day if providing hour" )); } // If minutes are provided, hours also need to be provided and the other way around if hour.is_none() && minute.is_some() { return Err(glib::bool_error!( "Can't create DateTime: Need to provide both hour and minute or neither" )); } if minute.is_some() && hour.is_none() { return Err(glib::bool_error!( "Can't create DateTime: Need to provide both hour and minute or neither" )); } // If seconds or tzoffset are provided then also hours and minutes must be provided if (seconds.is_some() || tzoffset.is_some()) && (hour.is_none() || minute.is_none()) { return Err(glib::bool_error!("Can't create DateTime: Need to provide hour and minute if providing seconds or timezone offset")); } Ok(()) } impl DateTime { #[doc(alias = "gst_date_time_new")] pub fn new( tzoffset: impl Into>, year: impl Into, month: impl Into>, day: impl Into>, hour: impl Into>, minute: impl Into>, seconds: impl Into>, ) -> Result { assert_initialized_main_thread!(); let tzoffset = tzoffset.into(); let year = year.into(); let month = month.into(); let day = day.into(); let hour = hour.into(); let minute = minute.into(); let seconds = seconds.into(); validate(tzoffset, year, month, day, hour, minute, seconds)?; unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_new( tzoffset.unwrap_or(0.0), year, month.unwrap_or(-1), day.unwrap_or(-1), hour.unwrap_or(-1), minute.unwrap_or(-1), seconds.unwrap_or(-1.0), )) .ok_or_else(|| glib::bool_error!("Can't create DateTime")) } } #[doc(alias = "gst_date_time_new_local_time")] pub fn from_local_time( year: impl Into, month: impl Into>, day: impl Into>, hour: impl Into>, minute: impl Into>, seconds: impl Into>, ) -> Result { assert_initialized_main_thread!(); let year = year.into(); let month = month.into(); let day = day.into(); let hour = hour.into(); let minute = minute.into(); let seconds = seconds.into(); validate(None, year, month, day, hour, minute, seconds)?; unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_new_local_time( year, month.unwrap_or(-1), day.unwrap_or(-1), hour.unwrap_or(-1), minute.unwrap_or(-1), seconds.unwrap_or(-1.0), )) .ok_or_else(|| glib::bool_error!("Can't create DateTime")) } } #[doc(alias = "gst_date_time_new_y")] pub fn from_y(year: i32) -> Result { assert_initialized_main_thread!(); validate(None, year, None, None, None, None, None)?; unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_new_y(year)) .ok_or_else(|| glib::bool_error!("Can't create DateTime")) } } #[doc(alias = "gst_date_time_new_ym")] pub fn from_ym(year: i32, month: i32) -> Result { assert_initialized_main_thread!(); validate(None, year, Some(month), None, None, None, None)?; unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_new_ym(year, month)) .ok_or_else(|| glib::bool_error!("Can't create DateTime")) } } #[doc(alias = "gst_date_time_new_ymd")] pub fn from_ymd(year: i32, month: i32, day: i32) -> Result { assert_initialized_main_thread!(); validate(None, year, Some(month), Some(day), None, None, None)?; unsafe { Option::<_>::from_glib_full(ffi::gst_date_time_new_ymd(year, month, day)) .ok_or_else(|| glib::bool_error!("Can't create DateTime")) } } #[doc(alias = "get_day")] #[doc(alias = "gst_date_time_get_day")] pub fn day(&self) -> Option { if !self.has_day() { return None; } unsafe { Some(ffi::gst_date_time_get_day(self.to_glib_none().0)) } } #[doc(alias = "get_hour")] #[doc(alias = "gst_date_time_get_hour")] pub fn hour(&self) -> Option { if !self.has_time() { return None; } unsafe { Some(ffi::gst_date_time_get_hour(self.to_glib_none().0)) } } #[doc(alias = "get_microsecond")] #[doc(alias = "gst_date_time_get_microsecond")] pub fn microsecond(&self) -> Option { if !self.has_second() { return None; } unsafe { Some(ffi::gst_date_time_get_microsecond(self.to_glib_none().0)) } } #[doc(alias = "get_minute")] #[doc(alias = "gst_date_time_get_minute")] pub fn minute(&self) -> Option { if !self.has_time() { return None; } unsafe { Some(ffi::gst_date_time_get_minute(self.to_glib_none().0)) } } #[doc(alias = "get_month")] #[doc(alias = "gst_date_time_get_month")] pub fn month(&self) -> Option { if !self.has_month() { return None; } unsafe { Some(ffi::gst_date_time_get_month(self.to_glib_none().0)) } } #[doc(alias = "get_second")] #[doc(alias = "gst_date_time_get_second")] pub fn second(&self) -> Option { if !self.has_second() { return None; } unsafe { Some(ffi::gst_date_time_get_second(self.to_glib_none().0)) } } #[doc(alias = "get_time_zone_offset")] #[doc(alias = "gst_date_time_get_time_zone_offset")] pub fn time_zone_offset(&self) -> Option { if !self.has_time() { return None; } unsafe { Some(ffi::gst_date_time_get_time_zone_offset( self.to_glib_none().0, )) } } pub fn to_utc(&self) -> Result { if !self.has_time() { // No time => no TZ offset return Ok(self.clone()); } assert!(self.has_year() && self.has_month() && self.has_day() && self.has_time()); // Can instantiate `gst::DateTime` without seconds using `gst::DateTime::new` // with `-1f64` for the `second` argument // however, the resulting instance can't be translated to `glib::DateTime` if self.has_second() { self.to_g_date_time() .and_then(|d| d.to_utc()) .map(|d| d.into()) } else { // It would be cheaper to build a `glib::DateTime` directly, unfortunetaly // this would require using `glib::TimeZone::new_offset` which is feature-gated // to `glib/v2_58`. So we need to build a new `gst::DateTime` with `0f64` // and then discard seconds again DateTime::new( self.time_zone_offset(), self.year(), self.month(), self.day(), self.hour(), self.minute(), Some(0.0), ) .and_then(|d| d.to_g_date_time()) .and_then(|d| d.to_utc()) .and_then(|d| { DateTime::new( None, // UTC TZ offset d.year(), Some(d.month()), Some(d.day_of_month()), Some(d.hour()), Some(d.minute()), None, // No second ) }) } } } impl cmp::PartialOrd for DateTime { // *NOTE 1:* When comparing a partially defined [`DateTime`](struct.DateTime.html) `d1` // such as *"2019/8/20"* with a [`DateTime`](struct.DateTime.html) with a time part `d2` // such as *"2019/8/20 21:10"*: // // - `d1` includes `d2`, // - neither `d1` < `d2` nor `d1` > `d2`, // - and `d1` != `d2`, // // so we can only return `None`. // // This is the reason why [`DateTime`](struct.DateTime.html) neither implements // [`Ord`](https://doc.rust-lang.org/nightly/std/cmp/trait.Ord.html) // nor [`Eq`](https://doc.rust-lang.org/nightly/std/cmp/trait.Eq.html). // // *NOTE 2:* When comparing a [`DateTime`](struct.DateTime.html) `d1` without a TZ offset // such as *"2019/8/20"* with a [`DateTime`](struct.DateTime.html) `d2` with a TZ offset // such as *"2019/8/20 21:10 +02:00"*, we can't tell in which TZ `d1` is expressed and which // time should be considered for an offset, therefore the two [`DateTime`s](struct.DateTime.html) // are compared in the same TZ. fn partial_cmp(&self, other: &Self) -> Option { #[inline] #[allow(clippy::unnecessary_wraps)] #[doc(alias = "get_cmp")] fn cmp(delta: i32) -> Option { skip_assert_initialized!(); Some(delta.cmp(&0)) } if !(self.has_year() && other.has_year()) { // Can't compare anything return None; } // Normalize to UTC only if both members have time (see note 2). let (self_norm, other_norm) = if self.has_time() && other.has_time() { (self.to_utc().ok()?, other.to_utc().ok()?) } else { (self.clone(), other.clone()) }; let year_delta = self_norm.year() - other_norm.year(); if year_delta != 0 { return cmp(year_delta); } // Same year if !self.has_month() && !other.has_month() { // Nothing left to compare return cmp(year_delta); } if !(self.has_month() && other.has_month()) { // One has month, the other doesn't => can't compare (note 1) return None; } let month_delta = self_norm.month().unwrap() - other_norm.month().unwrap(); if month_delta != 0 { return cmp(month_delta); } // Same year, same month if !self.has_day() && !other.has_day() { // Nothing left to compare return Some(cmp::Ordering::Equal); } if !(self.has_day() && other.has_day()) { // One has day, the other doesn't => can't compare (note 1) return None; } let day_delta = self_norm.day().unwrap() - other_norm.day().unwrap(); if day_delta != 0 { return cmp(day_delta); } // Same year, same month, same day if !self.has_time() && !other.has_time() { // Nothing left to compare return Some(cmp::Ordering::Equal); } if !(self.has_time() && other.has_time()) { // One has time, the other doesn't => can't compare (note 1) return None; } let hour_delta = self_norm.hour().unwrap() - other_norm.hour().unwrap(); if hour_delta != 0 { return cmp(hour_delta); } let minute_delta = self_norm.minute().unwrap() - other_norm.minute().unwrap(); if minute_delta != 0 { return cmp(minute_delta); } // Same year, same month, same day, same time if !self.has_second() && !other.has_second() { // Nothing left to compare return Some(cmp::Ordering::Equal); } if !(self.has_second() && other.has_second()) { // One has second, the other doesn't => can't compare (note 1) return None; } let second_delta = self_norm.second().unwrap() - other_norm.second().unwrap(); if second_delta != 0 { return cmp(second_delta); } cmp(self_norm.microsecond().unwrap() - other_norm.microsecond().unwrap()) } } impl cmp::PartialEq for DateTime { fn eq(&self, other: &Self) -> bool { self.partial_cmp(other) .map_or_else(|| false, |cmp| cmp == cmp::Ordering::Equal) } } impl fmt::Debug for DateTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut debug_struct = f.debug_struct("DateTime"); if self.has_year() { debug_struct.field("year", &self.year()); } if self.has_month() { debug_struct.field("month", &self.month()); } if self.has_day() { debug_struct.field("day", &self.day()); } if self.has_time() { debug_struct.field("hour", &self.hour()); debug_struct.field("minute", &self.minute()); if self.has_second() { debug_struct.field("second", &self.second()); debug_struct.field("microsecond", &self.microsecond()); } debug_struct.field("tz_offset", &self.time_zone_offset()); } debug_struct.finish() } } impl fmt::Display for DateTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str( self.to_iso8601_string() .unwrap_or_else(|_| "None".into()) .as_str(), ) } } impl<'a> From<&'a glib::DateTime> for DateTime { fn from(v: &'a glib::DateTime) -> DateTime { skip_assert_initialized!(); DateTime::from_g_date_time(v.clone()) } } impl From for DateTime { fn from(v: glib::DateTime) -> DateTime { skip_assert_initialized!(); DateTime::from_g_date_time(v) } } impl<'a> TryFrom<&'a DateTime> for glib::DateTime { type Error = glib::BoolError; fn try_from(v: &'a DateTime) -> Result { skip_assert_initialized!(); v.to_g_date_time() } } impl TryFrom for glib::DateTime { type Error = glib::BoolError; fn try_from(v: DateTime) -> Result { skip_assert_initialized!(); v.to_g_date_time() } } #[cfg(test)] mod tests { use super::*; #[allow(clippy::cognitive_complexity)] #[test] fn test_to_utc() { crate::init().unwrap(); // Hour offset let utc_date_time = DateTime::new(2f32, 2019, 8, 20, 20, 9, 42.123_456f64) .unwrap() .to_utc() .unwrap(); assert_eq!(utc_date_time.year(), 2019); assert_eq!(utc_date_time.month().unwrap(), 8); assert_eq!(utc_date_time.day().unwrap(), 20); assert_eq!(utc_date_time.hour().unwrap(), 18); assert_eq!(utc_date_time.minute().unwrap(), 9); assert_eq!(utc_date_time.second().unwrap(), 42); assert_eq!(utc_date_time.microsecond().unwrap(), 123_456); // Year, month, day and hour offset let utc_date_time = DateTime::new(2f32, 2019, 1, 1, 0, 0, 42.123_456f64) .unwrap() .to_utc() .unwrap(); assert_eq!(utc_date_time.year(), 2018); assert_eq!(utc_date_time.month().unwrap(), 12); assert_eq!(utc_date_time.day().unwrap(), 31); assert_eq!(utc_date_time.hour().unwrap(), 22); assert_eq!(utc_date_time.minute().unwrap(), 0); assert_eq!(utc_date_time.second().unwrap(), 42); assert_eq!(utc_date_time.microsecond().unwrap(), 123_456); // Date without an hour (which implies no TZ) let utc_date_time = DateTime::from_ymd(2019, 1, 1).unwrap().to_utc().unwrap(); assert_eq!(utc_date_time.year(), 2019); assert_eq!(utc_date_time.month().unwrap(), 1); assert_eq!(utc_date_time.day().unwrap(), 1); assert!(!utc_date_time.has_time()); assert!(!utc_date_time.has_second()); // Date without seconds let utc_date_time = DateTime::new(2f32, 2018, 5, 28, 16, 6, None) .unwrap() .to_utc() .unwrap(); assert_eq!(utc_date_time.year(), 2018); assert_eq!(utc_date_time.month().unwrap(), 5); assert_eq!(utc_date_time.day().unwrap(), 28); assert_eq!(utc_date_time.hour().unwrap(), 14); assert_eq!(utc_date_time.minute().unwrap(), 6); assert!(!utc_date_time.has_second()); } #[test] fn test_partial_ord() { crate::init().unwrap(); // Different years assert!( DateTime::new(2f32, 2020, 8, 20, 19, 43, 42.123_456f64).unwrap() > DateTime::new(2f32, 2019, 8, 20, 19, 43, 42.123_456f64).unwrap() ); // Different months (order intentionally reversed) assert!( DateTime::new(2f32, 2019, 8, 20, 19, 43, 42.123_456f64).unwrap() < DateTime::new(2f32, 2019, 9, 19, 19, 43, 42.123_456f64).unwrap() ); // Different days assert!( DateTime::new(2f32, 2019, 8, 21, 19, 43, 42.123_456f64).unwrap() > DateTime::new(2f32, 2019, 8, 20, 19, 43, 42.123_456f64).unwrap() ); // Different hours assert!( DateTime::new(2f32, 2019, 8, 20, 19, 44, 42.123_456f64).unwrap() > DateTime::new(2f32, 2019, 8, 20, 19, 43, 42.123_456f64).unwrap() ); // Different minutes assert!( DateTime::new(2f32, 2019, 8, 20, 19, 43, 44.123_456f64).unwrap() > DateTime::new(2f32, 2019, 8, 20, 19, 43, 42.123_456f64).unwrap() ); // Different seconds assert!( DateTime::new(2f32, 2019, 8, 20, 19, 43, 43.123_456f64).unwrap() > DateTime::new(2f32, 2019, 8, 20, 19, 43, 42.123_456f64).unwrap() ); // Different micro-seconds assert!( DateTime::new(2f32, 2019, 8, 20, 19, 43, 42.123_457f64).unwrap() > DateTime::new(2f32, 2019, 8, 20, 19, 43, 42.123_456f64).unwrap() ); // Different TZ offsets assert!( DateTime::new(1f32, 2019, 8, 20, 19, 43, 42.123_456f64).unwrap() > DateTime::new(2f32, 2019, 8, 20, 19, 43, 42.123_456f64).unwrap() ); // TZ offset leading to year, month, day, hour offset assert!( DateTime::new(2f32, 2019, 1, 1, 0, 0, 0f64).unwrap() < DateTime::new(1f32, 2018, 12, 31, 23, 59, 0f64).unwrap() ); // Partially defined `DateTime` assert!( DateTime::from_ymd(2020, 8, 20).unwrap() > DateTime::from_ymd(2019, 8, 20).unwrap() ); assert!( DateTime::from_ymd(2019, 9, 20).unwrap() > DateTime::from_ymd(2019, 8, 20).unwrap() ); assert!( DateTime::from_ymd(2019, 8, 21).unwrap() > DateTime::from_ymd(2019, 8, 20).unwrap() ); assert!(DateTime::from_ym(2020, 8).unwrap() > DateTime::from_ym(2019, 8).unwrap()); assert!(DateTime::from_ym(2019, 9).unwrap() > DateTime::from_ym(2019, 8).unwrap()); assert!(DateTime::from_ym(2019, 9).unwrap() > DateTime::from_ymd(2019, 8, 20).unwrap()); assert!(DateTime::from_y(2020).unwrap() > DateTime::from_y(2019).unwrap()); assert!(DateTime::from_ym(2020, 1).unwrap() > DateTime::from_y(2019).unwrap()); assert!( DateTime::new(2f32, 2019, 8, 20, 19, 43, 44.123_456f64).unwrap() < DateTime::from_ymd(2020, 8, 20).unwrap() ); assert!( DateTime::from_ymd(2020, 8, 20).unwrap() > DateTime::new(2f32, 2019, 8, 20, 19, 43, 44.123_456f64).unwrap() ); // Comparison occurs on the same TZ when the `DateTime` doesn't have time (note 2) assert!( DateTime::from_ymd(2020, 1, 1).unwrap() > DateTime::new(-2f32, 2019, 12, 31, 23, 59, 0f64).unwrap() ); // In the following cases, the partially defined `DateTime` is a range WRT // the fully defined `DateTime` and this range includes the fully defined `DateTime`, // but we can't tell if it's before or after and they are not equal (note 1) assert!(DateTime::new(2f32, 2019, 8, 20, 19, 43, 44.123_456f64) .unwrap() .partial_cmp(&DateTime::from_ymd(2019, 8, 20).unwrap()) .is_none()); assert!(DateTime::from_ymd(2019, 8, 20) .unwrap() .partial_cmp(&DateTime::new(2f32, 2019, 8, 20, 19, 43, 44.123_456f64).unwrap()) .is_none()); assert!(DateTime::from_ym(2019, 1) .unwrap() .partial_cmp(&DateTime::from_y(2019).unwrap()) .is_none()); } #[test] fn test_eq() { crate::init().unwrap(); assert_eq!( DateTime::new(2f32, 2018, 5, 28, 16, 6, 42.123_456f64).unwrap(), DateTime::new(2f32, 2018, 5, 28, 16, 6, 42.123_456f64).unwrap() ); assert_eq!( DateTime::new(2f32, 2018, 5, 28, 16, 6, 0f64).unwrap(), DateTime::new(2f32, 2018, 5, 28, 16, 6, 0f64).unwrap() ); assert_eq!( DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap(), DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap() ); assert_eq!( DateTime::from_ymd(2018, 5, 28).unwrap(), DateTime::from_ymd(2018, 5, 28).unwrap() ); // In the following cases, the partially defined `DateTime` is a range WRT // the fully defined `DateTime` and this range includes the fully defined `DateTime`, // but they are not equal (note 1) assert_ne!( DateTime::from_ymd(2018, 5, 28).unwrap(), DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap() ); assert_ne!( DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap(), DateTime::from_ym(2018, 5).unwrap() ); assert_ne!( DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap(), DateTime::from_y(2018).unwrap() ); } } gstreamer-0.23.5/src/date_time_serde.rs000064400000000000000000000237411046102023000161650ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #![allow(clippy::upper_case_acronyms)] use glib::{ translate::{FromGlib, IntoGlib}, types::StaticType, value::{ToValue, ToValueOptional}, }; use serde::{ de::{Deserialize, Deserializer, Error}, ser, ser::{Serialize, Serializer}, }; use crate::DateTime; #[derive(serde::Serialize, serde::Deserialize)] enum DateTimeVariants { Y(i32), YM(i32, i32), YMD(i32, i32, i32), YMDhmTz(i32, i32, i32, i32, i32, f32), YMDhmsTz(i32, i32, i32, i32, i32, f64, f32), } // Note: ser / de for `glib::Date` should be implemented in the `glib` crate // However, there is no `serde` feature in `glib` right now. The limitation is that // `Date` fields can only be ser / de when they are used in `Value`s (which implies // `Array`s, `List`s, `Structure` fields and `Tag`s) pub(crate) struct Date(glib::Date); impl From for Date { #[inline] fn from(glib_date: glib::Date) -> Self { skip_assert_initialized!(); Date(glib_date) } } impl ToValue for Date { fn to_value(&self) -> glib::Value { self.0.to_value() } fn value_type(&self) -> glib::Type { glib::Date::static_type() } } impl ToValueOptional for Date { fn to_value_optional(s: Option<&Self>) -> glib::Value { skip_assert_initialized!(); s.map(|s| &s.0).to_value() } } impl StaticType for Date { #[inline] fn static_type() -> glib::Type { glib::Date::static_type() } } impl From for glib::Value { #[inline] fn from(v: Date) -> glib::Value { skip_assert_initialized!(); v.0.into() } } impl Serialize for Date { fn serialize(&self, serializer: S) -> Result { DateTimeVariants::YMD( self.0.year() as i32, self.0.month().into_glib(), self.0.day() as i32, ) .serialize(serializer) } } impl Serialize for DateTime { fn serialize(&self, serializer: S) -> Result { let variant = if self.has_second() { DateTimeVariants::YMDhmsTz( self.year(), self.month().unwrap(), self.day().unwrap(), self.hour().unwrap(), self.minute().unwrap(), f64::from(self.second().unwrap()) + f64::from(self.microsecond().unwrap()) / 1_000_000f64, self.time_zone_offset().unwrap(), ) } else if self.has_time() { DateTimeVariants::YMDhmTz( self.year(), self.month().unwrap(), self.day().unwrap(), self.hour().unwrap(), self.minute().unwrap(), self.time_zone_offset().unwrap(), ) } else if self.has_day() { DateTimeVariants::YMD(self.year(), self.month().unwrap(), self.day().unwrap()) } else if self.has_month() { DateTimeVariants::YM(self.year(), self.month().unwrap()) } else if self.has_year() { DateTimeVariants::Y(self.year()) } else { return Err(ser::Error::custom(format!( "no parts could be found in `DateTime` {self}", ))); }; variant.serialize(serializer) } } impl TryFrom for Date { type Error = glib::BoolError; fn try_from(dt_variant: DateTimeVariants) -> Result { skip_assert_initialized!(); match dt_variant { DateTimeVariants::YMD(y, m, d) => { let month = unsafe { glib::DateMonth::from_glib(m) }; if let glib::DateMonth::__Unknown(_) = month { return Err(glib::bool_error!("Out of range `month` for `Date`")); } Ok(Date(glib::Date::from_dmy( d.try_into() .map_err(|_| glib::bool_error!("Out of range `day` for `Date`"))?, month, y.try_into() .map_err(|_| glib::bool_error!("Out of range `year` for `Date`"))?, )?)) } _ => Err(glib::bool_error!( "Incompatible variant for `Date` (expecting \"YMD\")" )), } } } impl<'de> Deserialize<'de> for Date { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); DateTimeVariants::deserialize(deserializer) .and_then(|dt_variant| dt_variant.try_into().map_err(D::Error::custom)) } } #[allow(clippy::many_single_char_names)] impl TryFrom for DateTime { type Error = glib::BoolError; fn try_from(dt_variant: DateTimeVariants) -> Result { skip_assert_initialized!(); match dt_variant { DateTimeVariants::Y(y) => DateTime::from_y(y), DateTimeVariants::YM(y, m) => DateTime::from_ym(y, m), DateTimeVariants::YMD(y, m, d) => DateTime::from_ymd(y, m, d), DateTimeVariants::YMDhmTz(y, m, d, h, mn, tz) => { DateTime::new(tz, y, m, d, h, mn, None) } DateTimeVariants::YMDhmsTz(y, m, d, h, mn, s, tz) => { DateTime::new(tz, y, m, d, h, mn, s) } } } } impl<'de> Deserialize<'de> for DateTime { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); DateTimeVariants::deserialize(deserializer) .and_then(|dt_variant| dt_variant.try_into().map_err(D::Error::custom)) } } #[cfg(test)] mod tests { use crate::DateTime; #[test] fn test_serialize() { crate::init().unwrap(); let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string()); let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, 42.123_456f64).unwrap(); let res = ron::ser::to_string_pretty(&datetime, pretty_config.clone()); assert_eq!( Ok("YMDhmsTz(2018, 5, 28, 16, 6, 42.123456, 2.0)".to_owned()), res, ); let res = serde_json::to_string(&datetime).unwrap(); assert_eq!( r#"{"YMDhmsTz":[2018,5,28,16,6,42.123456,2.0]}"#.to_owned(), res ); let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap(); let res = ron::ser::to_string_pretty(&datetime, pretty_config.clone()); assert_eq!(Ok("YMDhmTz(2018, 5, 28, 16, 6, 2.0)".to_owned()), res,); let datetime = DateTime::from_ymd(2018, 5, 28).unwrap(); let res = ron::ser::to_string_pretty(&datetime, pretty_config.clone()); assert_eq!(Ok("YMD(2018, 5, 28)".to_owned()), res); let datetime = DateTime::from_ym(2018, 5).unwrap(); let res = ron::ser::to_string_pretty(&datetime, pretty_config.clone()); assert_eq!(Ok("YM(2018, 5)".to_owned()), res); let datetime = DateTime::from_y(2018).unwrap(); let res = ron::ser::to_string_pretty(&datetime, pretty_config); assert_eq!(Ok("Y(2018)".to_owned()), res); } #[test] fn test_deserialize() { crate::init().unwrap(); let datetime_ron = "YMDhmsTz(2018, 5, 28, 16, 6, 42.123456, 2)"; let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); assert_eq!( datetime_de, DateTime::new(2f32, 2018, 5, 28, 16, 6, 42.123_456f64).unwrap() ); let datetime_json = r#"{"YMDhmsTz":[2018,5,28,16,6,42.123456,2.0]}"#; let datetime_de: DateTime = serde_json::from_str(datetime_json).unwrap(); assert_eq!( datetime_de, DateTime::new(2f32, 2018, 5, 28, 16, 6, 42.123_456f64).unwrap() ); let datetime_ron = "YMDhmTz(2018, 5, 28, 16, 6, 2)"; let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); assert_eq!( datetime_de, DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap() ); let datetime_ron = "YMD(2018, 5, 28)"; let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); assert_eq!(datetime_de, DateTime::from_ymd(2018, 5, 28).unwrap()); let datetime_ron = "YM(2018, 5)"; let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); assert_eq!(datetime_de, DateTime::from_ym(2018, 5).unwrap()); let datetime_ron = "Y(2018)"; let datetime_de: DateTime = ron::de::from_str(datetime_ron).unwrap(); assert_eq!(datetime_de, DateTime::from_y(2018).unwrap()); } #[test] fn test_serde_roundtrip() { crate::init().unwrap(); let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, 42.123_456f64).unwrap(); let datetime_ser = ron::ser::to_string(&datetime).unwrap(); let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); assert_eq!(datetime_de, datetime); let datetime = DateTime::new(2f32, 2018, 5, 28, 16, 6, None).unwrap(); let datetime_ser = ron::ser::to_string(&datetime).unwrap(); let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); assert_eq!(datetime_de, datetime); let datetime = DateTime::from_ymd(2018, 5, 28).unwrap(); let datetime_ser = ron::ser::to_string(&datetime).unwrap(); let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); assert_eq!(datetime_de, datetime); let datetime = DateTime::from_ym(2018, 5).unwrap(); let datetime_ser = ron::ser::to_string(&datetime).unwrap(); let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); assert_eq!(datetime_de, datetime); let datetime = DateTime::from_y(2018).unwrap(); let datetime_ser = ron::ser::to_string(&datetime).unwrap(); let datetime_de: DateTime = ron::de::from_str(datetime_ser.as_str()).unwrap(); assert_eq!(datetime_de, datetime); } } gstreamer-0.23.5/src/device_monitor.rs000064400000000000000000000043631046102023000160550ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::num::NonZeroU32; use glib::{prelude::*, translate::*}; use crate::{ffi, Caps, DeviceMonitor}; #[derive(Debug, PartialEq, Eq)] pub struct DeviceMonitorFilterId(NonZeroU32); impl IntoGlib for DeviceMonitorFilterId { type GlibType = libc::c_uint; #[inline] fn into_glib(self) -> libc::c_uint { self.0.get() } } impl FromGlib for DeviceMonitorFilterId { #[inline] unsafe fn from_glib(val: libc::c_uint) -> DeviceMonitorFilterId { skip_assert_initialized!(); debug_assert_ne!(val, 0); DeviceMonitorFilterId(NonZeroU32::new_unchecked(val)) } } mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait DeviceMonitorExtManual: sealed::Sealed + IsA + 'static { #[doc(alias = "gst_device_monitor_add_filter")] fn add_filter( &self, classes: Option<&str>, caps: Option<&Caps>, ) -> Option { let id = unsafe { ffi::gst_device_monitor_add_filter( self.as_ref().to_glib_none().0, classes.to_glib_none().0, caps.to_glib_none().0, ) }; if id == 0 { None } else { Some(unsafe { from_glib(id) }) } } #[doc(alias = "gst_device_monitor_remove_filter")] fn remove_filter( &self, filter_id: DeviceMonitorFilterId, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_device_monitor_remove_filter( self.as_ref().to_glib_none().0, filter_id.into_glib() ), "Failed to remove the filter" ) } } #[doc(alias = "gst_device_monitor_get_devices")] #[doc(alias = "get_devices")] fn devices(&self) -> glib::List { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_device_monitor_get_devices( self.as_ref().to_glib_none().0, )) } } } impl> DeviceMonitorExtManual for O {} gstreamer-0.23.5/src/device_provider.rs000064400000000000000000000046561046102023000162250ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ffi::CStr; use glib::{prelude::*, translate::*}; use crate::{ffi, DeviceProvider, Plugin, Rank}; impl DeviceProvider { #[doc(alias = "gst_device_provider_register")] pub fn register( plugin: Option<&Plugin>, name: &str, rank: Rank, type_: glib::types::Type, ) -> Result<(), glib::error::BoolError> { skip_assert_initialized!(); unsafe { glib::result_from_gboolean!( ffi::gst_device_provider_register( plugin.to_glib_none().0, name.to_glib_none().0, rank.into_glib() as u32, type_.into_glib() ), "Failed to register device provider factory" ) } } } mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait DeviceProviderExtManual: sealed::Sealed + IsA + 'static { #[doc(alias = "get_metadata")] #[doc(alias = "gst_device_provider_class_get_metadata")] fn metadata<'a>(&self, key: &str) -> Option<&'a str> { unsafe { self.unsafe_cast_ref::() .class() .metadata(key) } } #[doc(alias = "gst_device_provider_get_devices")] #[doc(alias = "get_devices")] fn devices(&self) -> glib::List { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_device_provider_get_devices( self.as_ref().to_glib_none().0, )) } } } impl> DeviceProviderExtManual for O {} pub unsafe trait DeviceProviderClassExt { #[doc(alias = "get_metadata")] #[doc(alias = "gst_device_provider_class_get_metadata")] fn metadata<'a>(&self, key: &str) -> Option<&'a str> { unsafe { let klass = self as *const _ as *const ffi::GstDeviceProviderClass; let ptr = ffi::gst_device_provider_class_get_metadata( mut_override(klass), key.to_glib_none().0, ); if ptr.is_null() { None } else { Some(CStr::from_ptr(ptr).to_str().unwrap()) } } } } unsafe impl + glib::object::IsClass> DeviceProviderClassExt for glib::object::Class { } gstreamer-0.23.5/src/device_provider_factory.rs000064400000000000000000000046671046102023000177560ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ffi::CStr; use glib::translate::*; use crate::{ ffi, DeviceProviderFactory, ELEMENT_METADATA_AUTHOR, ELEMENT_METADATA_DESCRIPTION, ELEMENT_METADATA_DOC_URI, ELEMENT_METADATA_ICON_NAME, ELEMENT_METADATA_KLASS, ELEMENT_METADATA_LONGNAME, }; impl DeviceProviderFactory { #[doc(alias = "gst_device_provider_factory_list_get_device_providers")] pub fn factories(minrank: crate::Rank) -> glib::List { assert_initialized_main_thread!(); unsafe { FromGlibPtrContainer::from_glib_full( ffi::gst_device_provider_factory_list_get_device_providers(minrank.into_glib()), ) } } #[doc(alias = "gst_device_provider_factory_get_metadata")] #[doc(alias = "get_metadata")] pub fn metadata(&self, key: &str) -> Option<&str> { unsafe { let ptr = ffi::gst_device_provider_factory_get_metadata( self.to_glib_none().0, key.to_glib_none().0, ); if ptr.is_null() { None } else { Some(CStr::from_ptr(ptr).to_str().unwrap()) } } } #[doc(alias = "get_longname")] #[doc(alias = "gst_device_provider_factory_get_longname")] pub fn longname(&self) -> &str { self.metadata(ELEMENT_METADATA_LONGNAME).unwrap() } #[doc(alias = "get_klass")] #[doc(alias = "gst_device_provider_factory_get_klass")] pub fn klass(&self) -> &str { self.metadata(ELEMENT_METADATA_KLASS).unwrap() } #[doc(alias = "get_description")] #[doc(alias = "gst_device_provider_factory_get_description")] pub fn description(&self) -> &str { self.metadata(ELEMENT_METADATA_DESCRIPTION).unwrap() } #[doc(alias = "get_author")] #[doc(alias = "gst_device_provider_factory_get_author")] pub fn author(&self) -> &str { self.metadata(ELEMENT_METADATA_AUTHOR).unwrap() } #[doc(alias = "get_documentation_uri")] #[doc(alias = "gst_device_provider_factory_get_documentation_uri")] pub fn documentation_uri(&self) -> Option<&str> { self.metadata(ELEMENT_METADATA_DOC_URI) } #[doc(alias = "get_icon_name")] #[doc(alias = "gst_device_provider_factory_get_icon_name")] pub fn icon_name(&self) -> Option<&str> { self.metadata(ELEMENT_METADATA_ICON_NAME) } } gstreamer-0.23.5/src/element.rs000064400000000000000000001213571046102023000145030ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ffi::CStr, future::Future, mem, num::NonZeroU64, pin::Pin}; use glib::translate::*; use itertools::Itertools; use crate::{ ffi, format::{ CompatibleFormattedValue, FormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic, }, prelude::*, ClockTime, Element, ElementFlags, Event, Format, GenericFormattedValue, Pad, PadTemplate, Plugin, QueryRef, Rank, State, }; impl Element { #[doc(alias = "gst_element_link_many")] pub fn link_many( elements: impl IntoIterator + Clone>, ) -> Result<(), glib::BoolError> { skip_assert_initialized!(); for (src, dest) in elements.into_iter().tuple_windows() { unsafe { glib::result_from_gboolean!( ffi::gst_element_link( src.as_ref().to_glib_none().0, dest.as_ref().to_glib_none().0, ), "Failed to link elements '{}' and '{}'", src.as_ref().name(), dest.as_ref().name(), )?; } } Ok(()) } #[doc(alias = "gst_element_unlink_many")] pub fn unlink_many(elements: impl IntoIterator + Clone>) { skip_assert_initialized!(); for (src, dest) in elements.into_iter().tuple_windows() { unsafe { ffi::gst_element_unlink( src.as_ref().to_glib_none().0, dest.as_ref().to_glib_none().0, ); } } } #[doc(alias = "gst_element_register")] pub fn register( plugin: Option<&Plugin>, name: &str, rank: Rank, type_: glib::types::Type, ) -> Result<(), glib::error::BoolError> { skip_assert_initialized!(); unsafe { glib::result_from_gboolean!( ffi::gst_element_register( plugin.to_glib_none().0, name.to_glib_none().0, rank.into_glib() as u32, type_.into_glib() ), "Failed to register element factory" ) } } } #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] pub enum ElementMessageType { Error, Warning, Info, } #[derive(Debug, PartialEq, Eq)] pub struct NotifyWatchId(NonZeroU64); impl IntoGlib for NotifyWatchId { type GlibType = libc::c_ulong; #[inline] fn into_glib(self) -> libc::c_ulong { self.0.get() as libc::c_ulong } } impl FromGlib for NotifyWatchId { #[inline] unsafe fn from_glib(val: libc::c_ulong) -> NotifyWatchId { skip_assert_initialized!(); debug_assert_ne!(val, 0); NotifyWatchId(NonZeroU64::new_unchecked(val as _)) } } mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait ElementExtManual: sealed::Sealed + IsA + 'static { #[doc(alias = "get_element_class")] #[inline] fn element_class(&self) -> &glib::Class { unsafe { self.unsafe_cast_ref::().class() } } #[doc(alias = "get_current_state")] fn current_state(&self) -> State { self.state(Some(ClockTime::ZERO)).1 } #[doc(alias = "get_pending_state")] fn pending_state(&self) -> State { self.state(Some(ClockTime::ZERO)).2 } #[doc(alias = "gst_element_query")] fn query(&self, query: &mut QueryRef) -> bool { unsafe { from_glib(ffi::gst_element_query( self.as_ref().to_glib_none().0, query.as_mut_ptr(), )) } } #[doc(alias = "gst_element_send_event")] fn send_event(&self, event: impl Into) -> bool { unsafe { from_glib(ffi::gst_element_send_event( self.as_ref().to_glib_none().0, event.into().into_glib_ptr(), )) } } #[doc(alias = "get_metadata")] #[doc(alias = "gst_element_class_get_metadata")] fn metadata<'a>(&self, key: &str) -> Option<&'a str> { self.element_class().metadata(key) } #[doc(alias = "get_pad_template")] #[doc(alias = "gst_element_class_get_pad_template")] fn pad_template(&self, name: &str) -> Option { self.element_class().pad_template(name) } #[doc(alias = "get_pad_template_list")] #[doc(alias = "gst_element_class_get_pad_template_list")] fn pad_template_list(&self) -> glib::List { self.element_class().pad_template_list() } #[allow(clippy::too_many_arguments)] #[doc(alias = "gst_element_message_full")] fn message_full( &self, type_: ElementMessageType, code: T, message: Option<&str>, debug: Option<&str>, file: &str, function: &str, line: u32, ) { unsafe { let type_ = match type_ { ElementMessageType::Error => ffi::GST_MESSAGE_ERROR, ElementMessageType::Warning => ffi::GST_MESSAGE_WARNING, ElementMessageType::Info => ffi::GST_MESSAGE_INFO, }; ffi::gst_element_message_full( self.as_ref().to_glib_none().0, type_, T::domain().into_glib(), code.code(), message.to_glib_full(), debug.to_glib_full(), file.to_glib_none().0, function.to_glib_none().0, line as i32, ); } } fn set_element_flags(&self, flags: ElementFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags |= flags.into_glib(); } } fn unset_element_flags(&self, flags: ElementFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags &= !flags.into_glib(); } } #[doc(alias = "get_element_flags")] fn element_flags(&self) -> ElementFlags { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); from_glib((*ptr).flags) } } #[allow(clippy::too_many_arguments)] #[doc(alias = "gst_element_message_full_with_details")] fn message_full_with_details( &self, type_: ElementMessageType, code: T, message: Option<&str>, debug: Option<&str>, file: &str, function: &str, line: u32, structure: crate::Structure, ) { unsafe { let type_ = match type_ { ElementMessageType::Error => ffi::GST_MESSAGE_ERROR, ElementMessageType::Warning => ffi::GST_MESSAGE_WARNING, ElementMessageType::Info => ffi::GST_MESSAGE_INFO, }; ffi::gst_element_message_full_with_details( self.as_ref().to_glib_none().0, type_, T::domain().into_glib(), code.code(), message.to_glib_full(), debug.to_glib_full(), file.to_glib_none().0, function.to_glib_none().0, line as i32, structure.into_glib_ptr(), ); } } fn post_error_message(&self, msg: crate::ErrorMessage) { let crate::ErrorMessage { error_domain, error_code, ref message, ref debug, filename, function, line, } = msg; unsafe { ffi::gst_element_message_full( self.as_ref().to_glib_none().0, ffi::GST_MESSAGE_ERROR, error_domain.into_glib(), error_code, message.to_glib_full(), debug.to_glib_full(), filename.to_glib_none().0, function.to_glib_none().0, line as i32, ); } } #[doc(alias = "gst_element_iterate_pads")] fn iterate_pads(&self) -> crate::Iterator { unsafe { from_glib_full(ffi::gst_element_iterate_pads( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_element_iterate_sink_pads")] fn iterate_sink_pads(&self) -> crate::Iterator { unsafe { from_glib_full(ffi::gst_element_iterate_sink_pads( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "gst_element_iterate_src_pads")] fn iterate_src_pads(&self) -> crate::Iterator { unsafe { from_glib_full(ffi::gst_element_iterate_src_pads( self.as_ref().to_glib_none().0, )) } } #[doc(alias = "get_pads")] #[doc(alias = "gst_element_foreach_pad")] fn pads(&self) -> Vec { unsafe { let elt: &ffi::GstElement = &*(self.as_ptr() as *const _); let _guard = self.as_ref().object_lock(); FromGlibPtrContainer::from_glib_none(elt.pads) } } #[doc(alias = "get_sink_pads")] #[doc(alias = "gst_element_foreach_sink_pad")] fn sink_pads(&self) -> Vec { unsafe { let elt: &ffi::GstElement = &*(self.as_ptr() as *const _); let _guard = self.as_ref().object_lock(); FromGlibPtrContainer::from_glib_none(elt.sinkpads) } } #[doc(alias = "get_src_pads")] #[doc(alias = "gst_element_foreach_src_pad")] fn src_pads(&self) -> Vec { unsafe { let elt: &ffi::GstElement = &*(self.as_ptr() as *const _); let _guard = self.as_ref().object_lock(); FromGlibPtrContainer::from_glib_none(elt.srcpads) } } fn num_pads(&self) -> u16 { unsafe { let elt: &ffi::GstElement = &*(self.as_ptr() as *const _); let _guard = self.as_ref().object_lock(); elt.numpads } } fn num_sink_pads(&self) -> u16 { unsafe { let elt: &ffi::GstElement = &*(self.as_ptr() as *const _); let _guard = self.as_ref().object_lock(); elt.numsinkpads } } fn num_src_pads(&self) -> u16 { unsafe { let elt: &ffi::GstElement = &*(self.as_ptr() as *const _); let _guard = self.as_ref().object_lock(); elt.numsrcpads } } #[doc(alias = "gst_element_add_property_deep_notify_watch")] fn add_property_deep_notify_watch( &self, property_name: Option<&str>, include_value: bool, ) -> NotifyWatchId { let property_name = property_name.to_glib_none(); unsafe { from_glib(ffi::gst_element_add_property_deep_notify_watch( self.as_ref().to_glib_none().0, property_name.0, include_value.into_glib(), )) } } #[doc(alias = "gst_element_add_property_notify_watch")] fn add_property_notify_watch( &self, property_name: Option<&str>, include_value: bool, ) -> NotifyWatchId { let property_name = property_name.to_glib_none(); unsafe { from_glib(ffi::gst_element_add_property_notify_watch( self.as_ref().to_glib_none().0, property_name.0, include_value.into_glib(), )) } } #[doc(alias = "gst_element_remove_property_notify_watch")] fn remove_property_notify_watch(&self, watch_id: NotifyWatchId) { unsafe { ffi::gst_element_remove_property_notify_watch( self.as_ref().to_glib_none().0, watch_id.into_glib(), ); } } #[doc(alias = "gst_element_query_convert")] fn query_convert( &self, src_val: impl FormattedValue, ) -> Option { unsafe { let mut dest_val = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_element_query_convert( self.as_ref().to_glib_none().0, src_val.format().into_glib(), src_val.into_raw_value(), U::default_format().into_glib(), dest_val.as_mut_ptr(), )); if ret { Some(U::from_raw(U::default_format(), dest_val.assume_init())) } else { None } } } #[doc(alias = "gst_element_query_convert")] fn query_convert_generic( &self, src_val: impl FormattedValue, dest_format: Format, ) -> Option { unsafe { let mut dest_val = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_element_query_convert( self.as_ref().to_glib_none().0, src_val.format().into_glib(), src_val.into_raw_value(), dest_format.into_glib(), dest_val.as_mut_ptr(), )); if ret { Some(GenericFormattedValue::new( dest_format, dest_val.assume_init(), )) } else { None } } } #[doc(alias = "gst_element_query_duration")] fn query_duration(&self) -> Option { unsafe { let mut duration = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_element_query_duration( self.as_ref().to_glib_none().0, T::default_format().into_glib(), duration.as_mut_ptr(), )); if ret { try_from_glib(duration.assume_init()).ok() } else { None } } } #[doc(alias = "gst_element_query_duration")] fn query_duration_generic(&self, format: Format) -> Option { unsafe { let mut duration = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_element_query_duration( self.as_ref().to_glib_none().0, format.into_glib(), duration.as_mut_ptr(), )); if ret { Some(GenericFormattedValue::new(format, duration.assume_init())) } else { None } } } #[doc(alias = "gst_element_query_position")] fn query_position(&self) -> Option { unsafe { let mut cur = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_element_query_position( self.as_ref().to_glib_none().0, T::default_format().into_glib(), cur.as_mut_ptr(), )); if ret { try_from_glib(cur.assume_init()).ok() } else { None } } } #[doc(alias = "gst_element_query_position")] fn query_position_generic(&self, format: Format) -> Option { unsafe { let mut cur = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_element_query_position( self.as_ref().to_glib_none().0, format.into_glib(), cur.as_mut_ptr(), )); if ret { Some(GenericFormattedValue::new(format, cur.assume_init())) } else { None } } } #[doc(alias = "gst_element_seek")] fn seek( &self, rate: f64, flags: crate::SeekFlags, start_type: crate::SeekType, start: V, stop_type: crate::SeekType, stop: impl CompatibleFormattedValue, ) -> Result<(), glib::error::BoolError> { let stop = stop.try_into_checked(start).unwrap(); unsafe { glib::result_from_gboolean!( ffi::gst_element_seek( self.as_ref().to_glib_none().0, rate, start.format().into_glib(), flags.into_glib(), start_type.into_glib(), start.into_raw_value(), stop_type.into_glib(), stop.into_raw_value(), ), "Failed to seek", ) } } #[doc(alias = "gst_element_seek_simple")] fn seek_simple( &self, seek_flags: crate::SeekFlags, seek_pos: impl FormattedValue, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_element_seek_simple( self.as_ref().to_glib_none().0, seek_pos.format().into_glib(), seek_flags.into_glib(), seek_pos.into_raw_value(), ), "Failed to seek", ) } } #[doc(alias = "gst_element_call_async")] fn call_async(&self, func: F) where F: FnOnce(&Self) + Send + 'static, { let user_data: Box> = Box::new(Some(func)); unsafe extern "C" fn trampoline, F: FnOnce(&O) + Send + 'static>( element: *mut ffi::GstElement, user_data: glib::ffi::gpointer, ) { let user_data: &mut Option = &mut *(user_data as *mut _); let callback = user_data.take().unwrap(); callback(Element::from_glib_borrow(element).unsafe_cast_ref()); } unsafe extern "C" fn free_user_data, F: FnOnce(&O) + Send + 'static>( user_data: glib::ffi::gpointer, ) { let _: Box> = Box::from_raw(user_data as *mut _); } unsafe { ffi::gst_element_call_async( self.as_ref().to_glib_none().0, Some(trampoline::), Box::into_raw(user_data) as *mut _, Some(free_user_data::), ); } } fn call_async_future(&self, func: F) -> Pin + Send + 'static>> where F: FnOnce(&Self) -> T + Send + 'static, T: Send + 'static, { use futures_channel::oneshot; let (sender, receiver) = oneshot::channel(); self.call_async(move |element| { let _ = sender.send(func(element)); }); Box::pin(async move { receiver.await.expect("sender dropped") }) } #[doc(alias = "get_current_running_time")] #[doc(alias = "gst_element_get_current_running_time")] fn current_running_time(&self) -> Option { let base_time = self.base_time(); let clock_time = self.current_clock_time(); clock_time .zip(base_time) .and_then(|(ct, bt)| ct.checked_sub(bt)) } #[doc(alias = "get_current_clock_time")] #[doc(alias = "gst_element_get_current_clock_time")] fn current_clock_time(&self) -> Option { if let Some(clock) = self.clock() { clock.time() } else { crate::ClockTime::NONE } } #[doc(alias = "gst_element_get_request_pad")] #[doc(alias = "get_request_pad")] #[doc(alias = "gst_element_request_pad_simple")] fn request_pad_simple(&self, name: &str) -> Option { unsafe { #[cfg(feature = "v1_20")] { from_glib_full(ffi::gst_element_request_pad_simple( self.as_ref().to_glib_none().0, name.to_glib_none().0, )) } #[cfg(not(feature = "v1_20"))] { from_glib_full(ffi::gst_element_get_request_pad( self.as_ref().to_glib_none().0, name.to_glib_none().0, )) } } } #[doc(alias = "gst_element_link")] fn link(&self, dest: &impl IsA) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_element_link( self.as_ref().to_glib_none().0, dest.as_ref().to_glib_none().0 ), "Failed to link elements '{}' and '{}'", self.as_ref().name(), dest.as_ref().name(), ) } } #[doc(alias = "gst_element_link_filtered")] fn link_filtered( &self, dest: &impl IsA, filter: &crate::Caps, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_element_link_filtered( self.as_ref().to_glib_none().0, dest.as_ref().to_glib_none().0, filter.to_glib_none().0 ), "Failed to link elements '{}' and '{}' with filter '{:?}'", self.as_ref().name(), dest.as_ref().name(), filter, ) } } #[doc(alias = "gst_element_link_pads")] fn link_pads( &self, srcpadname: Option<&str>, dest: &impl IsA, destpadname: Option<&str>, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_element_link_pads( self.as_ref().to_glib_none().0, srcpadname.to_glib_none().0, dest.as_ref().to_glib_none().0, destpadname.to_glib_none().0 ), "Failed to link pads '{}' and '{}'", if let Some(srcpadname) = srcpadname { format!("{}:{}", self.as_ref().name(), srcpadname) } else { format!("{}:*", self.as_ref().name()) }, if let Some(destpadname) = destpadname { format!("{}:{}", dest.as_ref().name(), destpadname) } else { format!("{}:*", dest.as_ref().name()) }, ) } } #[doc(alias = "gst_element_link_pads_filtered")] fn link_pads_filtered( &self, srcpadname: Option<&str>, dest: &impl IsA, destpadname: Option<&str>, filter: &crate::Caps, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_element_link_pads_filtered( self.as_ref().to_glib_none().0, srcpadname.to_glib_none().0, dest.as_ref().to_glib_none().0, destpadname.to_glib_none().0, filter.to_glib_none().0 ), "Failed to link pads '{}' and '{}' with filter '{:?}'", if let Some(srcpadname) = srcpadname { format!("{}:{}", self.as_ref().name(), srcpadname) } else { format!("{}:*", self.as_ref().name()) }, if let Some(destpadname) = destpadname { format!("{}:{}", dest.as_ref().name(), destpadname) } else { format!("{}:*", dest.as_ref().name()) }, filter, ) } } #[doc(alias = "gst_element_link_pads_full")] fn link_pads_full( &self, srcpadname: Option<&str>, dest: &impl IsA, destpadname: Option<&str>, flags: crate::PadLinkCheck, ) -> Result<(), glib::error::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_element_link_pads_full( self.as_ref().to_glib_none().0, srcpadname.to_glib_none().0, dest.as_ref().to_glib_none().0, destpadname.to_glib_none().0, flags.into_glib() ), "Failed to link pads '{}' and '{}' with flags '{:?}'", if let Some(srcpadname) = srcpadname { format!("{}:{}", self.as_ref().name(), srcpadname) } else { format!("{}:*", self.as_ref().name()) }, if let Some(destpadname) = destpadname { format!("{}:{}", dest.as_ref().name(), destpadname) } else { format!("{}:*", dest.as_ref().name()) }, flags, ) } } } impl> ElementExtManual for O {} pub unsafe trait ElementClassExt { #[doc(alias = "get_metadata")] #[doc(alias = "gst_element_class_get_metadata")] fn metadata<'a>(&self, key: &str) -> Option<&'a str> { unsafe { let klass = self as *const _ as *const ffi::GstElementClass; let ptr = ffi::gst_element_class_get_metadata(klass as *mut _, key.to_glib_none().0); if ptr.is_null() { None } else { Some(CStr::from_ptr(ptr).to_str().unwrap()) } } } #[doc(alias = "get_pad_template")] #[doc(alias = "gst_element_class_get_pad_template")] fn pad_template(&self, name: &str) -> Option { unsafe { let klass = self as *const _ as *const ffi::GstElementClass; from_glib_none(ffi::gst_element_class_get_pad_template( klass as *mut _, name.to_glib_none().0, )) } } #[doc(alias = "get_pad_template_list")] #[doc(alias = "gst_element_class_get_pad_template_list")] fn pad_template_list(&self) -> glib::List { unsafe { let klass = self as *const _ as *const ffi::GstElementClass; glib::List::from_glib_none(ffi::gst_element_class_get_pad_template_list( klass as *mut _, )) } } } unsafe impl + glib::object::IsClass> ElementClassExt for glib::object::Class {} #[doc(alias = "GST_ELEMENT_METADATA_AUTHOR")] pub static ELEMENT_METADATA_AUTHOR: &glib::GStr = unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_AUTHOR) }; #[doc(alias = "GST_ELEMENT_METADATA_DESCRIPTION")] pub static ELEMENT_METADATA_DESCRIPTION: &glib::GStr = unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_DESCRIPTION) }; #[doc(alias = "GST_ELEMENT_METADATA_DOC_URI")] pub static ELEMENT_METADATA_DOC_URI: &glib::GStr = unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_DOC_URI) }; #[doc(alias = "GST_ELEMENT_METADATA_ICON_NAME")] pub static ELEMENT_METADATA_ICON_NAME: &glib::GStr = unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_ICON_NAME) }; #[doc(alias = "GST_ELEMENT_METADATA_KLASS")] pub static ELEMENT_METADATA_KLASS: &glib::GStr = unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_KLASS) }; #[doc(alias = "GST_ELEMENT_METADATA_LONGNAME")] pub static ELEMENT_METADATA_LONGNAME: &glib::GStr = unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::GST_ELEMENT_METADATA_LONGNAME) }; #[doc(alias = "GST_ELEMENT_ERROR")] #[doc(alias = "GST_ELEMENT_ERROR_WITH_DETAILS")] #[macro_export] macro_rules! element_error( ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { { use $crate::prelude::ElementExtManual; $obj.message_full( $crate::ElementMessageType::Error, $err, Some(&format!($($msg)*)), Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), ); }}; ($obj:expr, $err:expr, ($($msg:tt)*)) => { { use $crate::prelude::ElementExtManual; $obj.message_full( $crate::ElementMessageType::Error, $err, Some(&format!($($msg)*)), None, file!(), $crate::glib::function_name!(), line!(), ); }}; ($obj:expr, $err:expr, [$($debug:tt)*]) => { { use $crate::prelude::ElementExtManual; $obj.message_full( $crate::ElementMessageType::Error, $err, None, Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), ); }}; ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { { use $crate::prelude::ElementExtManual; $obj.message_full_with_details( $crate::ElementMessageType::Error, $err, Some(&format!($($msg)*)), Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), $details, ); }}; ($obj:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { { use $crate::prelude::ElementExtManual; $obj.message_full_with_details( $crate::ElementMessageType::Error, $err, Some(&format!($($msg)*)), None, file!(), $crate::glib::function_name!(), line!(), $details, ); }}; ($obj:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { { use $crate::prelude::ElementExtManual; $obj.message_full_with_details( $crate::ElementMessageType::Error, $err, None, Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), $details, ); }}; ); #[doc(alias = "GST_ELEMENT_WARNING")] #[doc(alias = "GST_ELEMENT_WARNING_WITH_DETAILS")] #[macro_export] macro_rules! element_warning( ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { { use $crate::prelude::ElementExtManual; $obj.message_full( $crate::ElementMessageType::Warning, $err, Some(&format!($($msg)*)), Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), ); }}; ($obj:expr, $err:expr, ($($msg:tt)*)) => { { use $crate::prelude::ElementExtManual; $obj.message_full( $crate::ElementMessageType::Warning, $err, Some(&format!($($msg)*)), None, file!(), $crate::glib::function_name!(), line!(), ); }}; ($obj:expr, $err:expr, [$($debug:tt)*]) => { { use $crate::prelude::ElementExtManual; $obj.message_full( $crate::ElementMessageType::Warning, $err, None, Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), ); }}; ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { { use $crate::prelude::ElementExtManual; $obj.message_full_with_details( $crate::ElementMessageType::Warning, $err, Some(&format!($($msg)*)), Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), $details, ); }}; ($obj:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { { use $crate::prelude::ElementExtManual; $obj.message_full_with_details( $crate::ElementMessageType::Warning, $err, Some(&format!($($msg)*)), None, file!(), $crate::glib::function_name!(), line!(), $details, ); }}; ($obj:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { { use $crate::prelude::ElementExtManual; $obj.message_full_with_details( $crate::ElementMessageType::Warning, $err, None, Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), $details, ); }}; ); #[doc(alias = "GST_ELEMENT_INFO")] #[doc(alias = "GST_ELEMENT_INFO_WITH_DETAILS")] #[macro_export] macro_rules! element_info( ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { { use $crate::prelude::ElementExtManual; $obj.message_full( $crate::ElementMessageType::Info, $err, Some(&format!($($msg)*)), Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), ); }}; ($obj:expr, $err:expr, ($($msg:tt)*)) => { { use $crate::prelude::ElementExtManual; $obj.message_full( $crate::ElementMessageType::Info, $err, Some(&format!($($msg)*)), None, file!(), $crate::glib::function_name!(), line!(), ); }}; ($obj:expr, $err:expr, [$($debug:tt)*]) => { { use $crate::prelude::ElementExtManual; $obj.message_full( $crate::ElementMessageType::Info, $err, None, Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), ); }}; ($obj:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { { use $crate::prelude::ElementExtManual; $obj.message_full_with_details( $crate::ElementMessageType::Info, $err, Some(&format!($($msg)*)), Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), $details, ); }}; ($obj:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { { use $crate::prelude::ElementExtManual; $obj.message_full_with_details( $crate::ElementMessageType::Info, $err, Some(&format!($($msg)*)), None, file!(), $crate::glib::function_name!(), line!(), $details, ); }}; ($obj:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { { use $crate::prelude::ElementExtManual; $obj.message_full_with_details( $crate::ElementMessageType::Info, $err, None, Some(&format!($($debug)*)), file!(), $crate::glib::function_name!(), line!(), $details, ); }}; ); #[doc(alias = "GST_ELEMENT_ERROR")] #[doc(alias = "GST_ELEMENT_ERROR_WITH_DETAILS")] #[macro_export] macro_rules! element_imp_error( ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { { let obj = $imp.obj(); $crate::element_error!(obj, $err, ($($msg)*), [$($debug)*]); }}; ($imp:expr, $err:expr, ($($msg:tt)*)) => { { let obj = $imp.obj(); $crate::element_error!(obj, $err, ($($msg)*)); }}; ($imp:expr, $err:expr, [$($debug:tt)*]) => { { let obj = $imp.obj(); $crate::element_error!(obj, $err, [$($debug)*]); }}; ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { { let obj = $imp.obj(); $crate::element_error!(obj, $err, ($($msg)*), [$($debug)*], details: $details); }}; ($imp:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { { let obj = $imp.obj(); $crate::element_error!(obj, $err, ($($msg)*), details: $details); }}; ($imp:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { { let obj = $imp.obj(); $crate::element_error!(obj, $err, [$($debug)*], details: $details); }}; ); #[doc(alias = "GST_ELEMENT_WARNING")] #[doc(alias = "GST_ELEMENT_WARNING_WITH_DETAILS")] #[macro_export] macro_rules! element_imp_warning( ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { { let obj = $imp.obj(); $crate::element_warning!(obj, $err, ($($msg)*), [$($debug)*]); }}; ($imp:expr, $err:expr, ($($msg:tt)*)) => { { let obj = $imp.obj(); $crate::element_warning!(obj, $err, ($($msg)*)); }}; ($imp:expr, $err:expr, [$($debug:tt)*]) => { { let obj = $imp.obj(); $crate::element_warning!(obj, $err, [$($debug)*]); }}; ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { { let obj = $imp.obj(); $crate::element_warning!(obj, $err, ($($msg)*), [$($debug)*], details: $details); }}; ($imp:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { { let obj = $imp.obj(); $crate::element_warning!(obj, $err, ($($msg)*), details: $details); }}; ($imp:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { { let obj = $imp.obj(); $crate::element_warning!(obj, $err, [$($debug)*], details: $details); }}; ); #[doc(alias = "GST_ELEMENT_INFO")] #[doc(alias = "GST_ELEMENT_INFO_WITH_DETAILS")] #[macro_export] macro_rules! element_imp_info( ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { { let obj = $imp.obj(); $crate::element_info!(obj, $err, ($($msg)*), [$($debug)*]); }}; ($imp:expr, $err:expr, ($($msg:tt)*)) => { { let obj = $imp.obj(); $crate::element_info!(obj, $err, ($($msg)*)); }}; ($imp:expr, $err:expr, [$($debug:tt)*]) => { { let obj = $imp.obj(); $crate::element_info!(obj, $err, [$($debug)*]); }}; ($imp:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*], details: $details:expr) => { { let obj = $imp.obj(); $crate::element_info!(obj, $err, ($($msg)*), [$($debug)*], details: $details); }}; ($imp:expr, $err:expr, ($($msg:tt)*), details: $details:expr) => { { let obj = $imp.obj(); $crate::element_info!(obj, $err, ($($msg)*), details: $details); }}; ($imp:expr, $err:expr, [$($debug:tt)*], details: $details:expr) => { { let obj = $imp.obj(); $crate::element_info!(obj, $err, [$($debug)*], details: $details); }}; ); #[cfg(test)] mod tests { use std::sync::mpsc::channel; use glib::GString; use super::*; #[test] fn test_get_pads() { crate::init().unwrap(); let identity = crate::ElementFactory::make("identity").build().unwrap(); let mut pad_names = identity .pads() .iter() .map(|p| p.name()) .collect::>(); pad_names.sort(); assert_eq!(pad_names, vec![String::from("sink"), String::from("src")]); let mut pad_names = identity .sink_pads() .iter() .map(|p| p.name()) .collect::>(); pad_names.sort(); assert_eq!(pad_names, vec![String::from("sink")]); let mut pad_names = identity .src_pads() .iter() .map(|p| p.name()) .collect::>(); pad_names.sort(); assert_eq!(pad_names, vec![String::from("src")]); } #[test] fn test_foreach_pad() { crate::init().unwrap(); let identity = crate::ElementFactory::make("identity").build().unwrap(); let mut pad_names = Vec::new(); identity.foreach_pad(|_element, pad| { pad_names.push(pad.name()); true }); pad_names.sort(); assert_eq!(pad_names, vec![String::from("sink"), String::from("src")]); } #[test] fn test_call_async() { crate::init().unwrap(); let identity = crate::ElementFactory::make("identity").build().unwrap(); let (sender, receiver) = channel(); identity.call_async(move |_| { sender.send(()).unwrap(); }); assert_eq!(receiver.recv(), Ok(())); } #[test] fn test_element_error() { crate::init().unwrap(); let identity = crate::ElementFactory::make("identity").build().unwrap(); crate::element_error!(identity, crate::CoreError::Failed, ("msg"), ["debug"]); crate::element_error!(identity, crate::CoreError::Failed, ["debug"]); crate::element_error!(identity, crate::CoreError::Failed, ("msg")); // We define a new variable for each call so there would be a compiler warning if the // string formatting did not actually use it. let x = 123i32; crate::element_error!(identity, crate::CoreError::Failed, ("msg {x}"), ["debug"]); let x = 123i32; crate::element_error!(identity, crate::CoreError::Failed, ["debug {x}"]); let x = 123i32; crate::element_error!(identity, crate::CoreError::Failed, ("msg {}", x)); } } gstreamer-0.23.5/src/element_factory.rs000064400000000000000000000346461046102023000162360ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ffi::CStr; use glib::{prelude::*, translate::*}; use crate::{ ffi, CapsRef, Element, ElementFactory, Rank, StaticPadTemplate, ELEMENT_METADATA_AUTHOR, ELEMENT_METADATA_DESCRIPTION, ELEMENT_METADATA_DOC_URI, ELEMENT_METADATA_ICON_NAME, ELEMENT_METADATA_KLASS, ELEMENT_METADATA_LONGNAME, }; impl ElementFactory { #[doc(alias = "gst_element_factory_create")] #[doc(alias = "gst_element_factory_create_with_properties")] #[track_caller] pub fn create(&self) -> ElementBuilder { assert_initialized_main_thread!(); ElementBuilder { name_or_factory: NameOrFactory::Factory(self), properties: smallvec::SmallVec::new(), } } #[doc(alias = "gst_element_factory_make")] #[doc(alias = "gst_element_factory_make_with_properties")] #[track_caller] pub fn make(factoryname: &str) -> ElementBuilder { assert_initialized_main_thread!(); ElementBuilder { name_or_factory: NameOrFactory::Name(factoryname), properties: smallvec::SmallVec::new(), } } #[doc(alias = "gst_element_factory_create")] #[track_caller] pub fn create_with_name(&self, name: Option<&str>) -> Result { let mut builder = self.create(); if let Some(name) = name { builder = builder.name(name); } builder.build() } #[doc(alias = "gst_element_factory_make")] #[track_caller] pub fn make_with_name( factoryname: &str, name: Option<&str>, ) -> Result { skip_assert_initialized!(); let mut builder = Self::make(factoryname); if let Some(name) = name { builder = builder.name(name); } builder.build() } #[doc(alias = "gst_element_factory_get_static_pad_templates")] #[doc(alias = "get_static_pad_templates")] pub fn static_pad_templates(&self) -> glib::List { unsafe { glib::List::from_glib_none(ffi::gst_element_factory_get_static_pad_templates( self.to_glib_none().0, )) } } #[doc(alias = "gst_element_factory_list_is_type")] pub fn has_type(&self, type_: crate::ElementFactoryType) -> bool { unsafe { from_glib(ffi::gst_element_factory_list_is_type( self.to_glib_none().0, type_.into_glib(), )) } } #[doc(alias = "gst_element_factory_list_get_elements")] pub fn factories_with_type( type_: crate::ElementFactoryType, minrank: Rank, ) -> glib::List { assert_initialized_main_thread!(); unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_element_factory_list_get_elements( type_.into_glib(), minrank.into_glib(), )) } } #[doc(alias = "gst_element_factory_get_metadata")] #[doc(alias = "get_metadata")] pub fn metadata(&self, key: &str) -> Option<&str> { unsafe { let ptr = ffi::gst_element_factory_get_metadata(self.to_glib_none().0, key.to_glib_none().0); if ptr.is_null() { None } else { Some(CStr::from_ptr(ptr).to_str().unwrap()) } } } #[doc(alias = "get_longname")] #[doc(alias = "gst_element_factory_get_longname")] pub fn longname(&self) -> &str { self.metadata(ELEMENT_METADATA_LONGNAME).unwrap() } #[doc(alias = "get_klass")] #[doc(alias = "gst_element_factory_get_klass")] pub fn klass(&self) -> &str { self.metadata(ELEMENT_METADATA_KLASS).unwrap() } #[doc(alias = "get_description")] #[doc(alias = "gst_element_factory_get_description")] pub fn description(&self) -> &str { self.metadata(ELEMENT_METADATA_DESCRIPTION).unwrap() } #[doc(alias = "get_author")] #[doc(alias = "gst_element_factory_get_author")] pub fn author(&self) -> &str { self.metadata(ELEMENT_METADATA_AUTHOR).unwrap() } #[doc(alias = "get_documentation_uri")] #[doc(alias = "gst_element_factory_get_documentation_uri")] pub fn documentation_uri(&self) -> Option<&str> { self.metadata(ELEMENT_METADATA_DOC_URI) } #[doc(alias = "get_icon_name")] #[doc(alias = "gst_element_factory_get_icon_name")] pub fn icon_name(&self) -> Option<&str> { self.metadata(ELEMENT_METADATA_ICON_NAME) } #[doc(alias = "gst_element_factory_can_sink_all_caps")] pub fn can_sink_all_caps(&self, caps: &CapsRef) -> bool { unsafe { from_glib(ffi::gst_element_factory_can_sink_all_caps( self.to_glib_none().0, caps.as_ptr(), )) } } #[doc(alias = "gst_element_factory_can_sink_any_caps")] pub fn can_sink_any_caps(&self, caps: &CapsRef) -> bool { unsafe { from_glib(ffi::gst_element_factory_can_sink_any_caps( self.to_glib_none().0, caps.as_ptr(), )) } } #[doc(alias = "gst_element_factory_can_src_all_caps")] pub fn can_src_all_caps(&self, caps: &CapsRef) -> bool { unsafe { from_glib(ffi::gst_element_factory_can_src_all_caps( self.to_glib_none().0, caps.as_ptr(), )) } } #[doc(alias = "gst_element_factory_can_src_any_caps")] pub fn can_src_any_caps(&self, caps: &CapsRef) -> bool { unsafe { from_glib(ffi::gst_element_factory_can_src_any_caps( self.to_glib_none().0, caps.as_ptr(), )) } } } // rustdoc-stripper-ignore-next /// Builder for `Element`s. #[must_use = "The builder must be built to be used"] pub struct ElementBuilder<'a> { name_or_factory: NameOrFactory<'a>, properties: smallvec::SmallVec<[(&'a str, ValueOrStr<'a>); 16]>, } #[derive(Copy, Clone)] enum NameOrFactory<'a> { Name(&'a str), Factory(&'a ElementFactory), } enum ValueOrStr<'a> { Value(glib::Value), Str(&'a str), } impl<'a> ElementBuilder<'a> { // rustdoc-stripper-ignore-next /// Sets the name property to the given `name`. #[inline] pub fn name(self, name: impl Into) -> Self { self.property("name", name.into()) } // rustdoc-stripper-ignore-next /// Sets the name property to the given `name` if it is `Some`. #[inline] pub fn name_if_some(self, name: Option>) -> Self { if let Some(name) = name { self.name(name) } else { self } } // rustdoc-stripper-ignore-next /// Sets property `name` to the given value `value`. /// /// Overrides any default or previously defined value for `name`. #[inline] pub fn property(self, name: &'a str, value: impl Into + 'a) -> Self { Self { name_or_factory: self.name_or_factory, properties: { let mut properties = self.properties; properties.push((name, ValueOrStr::Value(value.into()))); properties }, } } impl_builder_gvalue_extra_setters!(property); // rustdoc-stripper-ignore-next /// Sets property `name` to the given string value `value`. #[inline] pub fn property_from_str(self, name: &'a str, value: &'a str) -> Self { Self { name_or_factory: self.name_or_factory, properties: { let mut properties = self.properties; properties.push((name, ValueOrStr::Str(value))); properties }, } } // rustdoc-stripper-ignore-next /// Sets property `name` to the given string value `value` if it is `Some`. #[inline] pub fn property_from_str_if_some(self, name: &'a str, value: Option<&'a str>) -> Self { if let Some(value) = value { self.property_from_str(name, value) } else { self } } // rustdoc-stripper-ignore-next /// Builds the element with the provided properties. /// /// This fails if there is no such element factory or the element factory can't be loaded. /// /// # Panics /// /// This panics if the element is not instantiable, doesn't have all the given properties or /// property values of the wrong type are provided. #[track_caller] #[must_use = "Building the element without using it has no effect"] pub fn build(self) -> Result { let mut _factory_found = None; let factory = match self.name_or_factory { NameOrFactory::Name(name) => { let factory = ElementFactory::find(name).ok_or_else(|| { crate::warning!(crate::CAT_RUST, "element factory '{}' not found", name); glib::bool_error!( "Failed to find element factory with name '{}' for creating element", name ) })?; _factory_found = Some(factory); _factory_found.as_ref().unwrap() } NameOrFactory::Factory(factory) => factory, }; // The below is basically a reimplementation of the C function. We want to call // glib::Object::with_type() ourselves here for checking properties and their values // correctly and to provide consistent behaviour. use crate::prelude::{ ElementExtManual, GstObjectExt, GstObjectExtManual, PluginFeatureExtManual, }; let factory = factory.load().map_err(|_| { crate::warning!( crate::CAT_RUST, obj = factory, "loading element factory '{}' failed", factory.name(), ); glib::bool_error!( "Failed to load element factory '{}' for creating element", factory.name() ) })?; let element_type = factory.element_type(); if !element_type.is_valid() { crate::warning!( crate::CAT_RUST, obj = &factory, "element factory '{}' has no type", factory.name() ); return Err(glib::bool_error!( "Failed to create element from factory '{}'", factory.name() )); } let mut properties = smallvec::SmallVec::<[_; 16]>::with_capacity(self.properties.len()); let klass = glib::Class::::from_type(element_type).unwrap(); for (name, value) in self.properties { match value { ValueOrStr::Value(value) => { properties.push((name, value)); } ValueOrStr::Str(value) => { use crate::value::GstValueExt; let pspec = match klass.find_property(name) { Some(pspec) => pspec, None => { panic!( "property '{}' of element factory '{}' not found", name, factory.name() ); } }; let value = { if pspec.value_type() == crate::Structure::static_type() && value == "NULL" { None::.to_value() } else { #[cfg(feature = "v1_20")] { glib::Value::deserialize_with_pspec(value, &pspec) .unwrap_or_else(|_| { panic!( "property '{}' of element factory '{}' can't be set from string '{}'", name, factory.name(), value, ) }) } #[cfg(not(feature = "v1_20"))] { glib::Value::deserialize(value, pspec.value_type()) .unwrap_or_else(|_| { panic!( "property '{}' of element factory '{}' can't be set from string '{}'", name, factory.name(), value, ) }) } } }; properties.push((name, value)); } } } let element = unsafe { glib::Object::with_mut_values(element_type, &mut properties) .unsafe_cast::() }; unsafe { use std::sync::atomic; let klass = element.element_class(); let factory_ptr: &atomic::AtomicPtr = &*(&klass.as_ref().elementfactory as *const *mut ffi::GstElementFactory as *const atomic::AtomicPtr); if factory_ptr .compare_exchange( std::ptr::null_mut(), factory.as_ptr(), atomic::Ordering::SeqCst, atomic::Ordering::SeqCst, ) .is_ok() { factory.set_object_flags(crate::ObjectFlags::MAY_BE_LEAKED); } if glib::gobject_ffi::g_object_is_floating(factory.as_ptr() as *mut _) != glib::ffi::GFALSE { glib::g_critical!( "GStreamer", "The created element should be floating, this is probably caused by faulty bindings", ); } } crate::log!( crate::CAT_RUST, obj = &factory, "created element \"{}\"", factory.name() ); Ok(element) } } gstreamer-0.23.5/src/element_factory_type.rs000064400000000000000000000100001046102023000172510ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::{bitflags::bitflags, translate::*}; use crate::ffi; bitflags! { #[doc(alias = "GstElementFactoryListType")] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct ElementFactoryType: u64 { #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_DECODER")] const DECODER = ffi::GST_ELEMENT_FACTORY_TYPE_DECODER; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_ENCODER")] const ENCODER = ffi::GST_ELEMENT_FACTORY_TYPE_ENCODER; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_SINK")] const SINK = ffi::GST_ELEMENT_FACTORY_TYPE_SINK; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_SRC")] const SRC = ffi::GST_ELEMENT_FACTORY_TYPE_SRC; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_MUXER")] const MUXER = ffi::GST_ELEMENT_FACTORY_TYPE_MUXER; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_DEMUXER")] const DEMUXER = ffi::GST_ELEMENT_FACTORY_TYPE_DEMUXER; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_PARSER")] const PARSER = ffi::GST_ELEMENT_FACTORY_TYPE_PARSER; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_PAYLOADER")] const PAYLOADER = ffi::GST_ELEMENT_FACTORY_TYPE_PAYLOADER; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_DEPAYLOADER")] const DEPAYLOADER = ffi::GST_ELEMENT_FACTORY_TYPE_DEPAYLOADER; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_FORMATTER")] const FORMATTER = ffi::GST_ELEMENT_FACTORY_TYPE_FORMATTER; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_DECRYPTOR")] const DECRYPTOR = ffi::GST_ELEMENT_FACTORY_TYPE_DECRYPTOR; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_ENCRYPTOR")] const ENCRYPTOR = ffi::GST_ELEMENT_FACTORY_TYPE_ENCRYPTOR; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_HARDWARE")] const HARDWARE = ffi::GST_ELEMENT_FACTORY_TYPE_HARDWARE; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_TIMESTAMPER")] const TIMESTAMPER = ffi::GST_ELEMENT_FACTORY_TYPE_TIMESTAMPER; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO")] const MEDIA_VIDEO = ffi::GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO")] const MEDIA_AUDIO = ffi::GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE")] const MEDIA_IMAGE = ffi::GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE")] const MEDIA_SUBTITLE = ffi::GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_MEDIA_METADATA")] const MEDIA_METADATA = ffi::GST_ELEMENT_FACTORY_TYPE_MEDIA_METADATA; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_ANY")] const ANY = ffi::GST_ELEMENT_FACTORY_TYPE_ANY; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_MEDIA_ANY")] const MEDIA_ANY = ffi::GST_ELEMENT_FACTORY_TYPE_MEDIA_ANY; const VIDEO_ENCODER = Self::ENCODER.bits() | Self::MEDIA_VIDEO.bits() | Self::MEDIA_IMAGE.bits(); const AUDIO_ENCODER = Self::ENCODER.bits() | Self::MEDIA_AUDIO.bits(); const AUDIOVIDEO_SINKS = Self::SINK.bits() | Self::MEDIA_AUDIO.bits() | Self::MEDIA_VIDEO.bits() | Self::MEDIA_IMAGE.bits(); const DECODABLE = Self::DECODER.bits() | Self::DEMUXER.bits() | Self::DEPAYLOADER.bits() | Self::PARSER.bits() | Self::DECRYPTOR.bits(); } } #[doc(hidden)] impl IntoGlib for ElementFactoryType { type GlibType = ffi::GstElementFactoryListType; #[inline] fn into_glib(self) -> ffi::GstElementFactoryListType { self.bits() } } #[doc(hidden)] impl FromGlib for ElementFactoryType { #[inline] unsafe fn from_glib(value: ffi::GstElementFactoryListType) -> ElementFactoryType { skip_assert_initialized!(); ElementFactoryType::from_bits_truncate(value) } } gstreamer-0.23.5/src/enums.rs000064400000000000000000000624251046102023000142010ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{cmp, ops}; use glib::{ prelude::*, translate::*, value::{FromValue, ToValue, Value}, Type, }; use thiserror::Error; use crate::{ffi, ClockReturn, State, StateChange, StateChangeReturn}; macro_rules! impl_return_result_traits { ($ffi_type:ident, $ret_type:ident, $ok_type:ident, $err_type:ident) => { impl From<$ok_type> for $ret_type { #[inline] fn from(value: $ok_type) -> Self { skip_assert_initialized!(); $ret_type::from_ok(value) } } impl IntoGlib for $ok_type { type GlibType = <$ret_type as IntoGlib>::GlibType; #[inline] fn into_glib(self) -> Self::GlibType { $ret_type::from_ok(self).into_glib() } } impl From<$err_type> for $ret_type { #[inline] fn from(value: $err_type) -> Self { skip_assert_initialized!(); $ret_type::from_error(value) } } impl IntoGlib for $err_type { type GlibType = <$ret_type as IntoGlib>::GlibType; #[inline] fn into_glib(self) -> Self::GlibType { $ret_type::from_error(self).into_glib() } } impl From> for $ret_type { #[inline] fn from(res: Result<$ok_type, $err_type>) -> Self { skip_assert_initialized!(); match res { Ok(success) => $ret_type::from_ok(success), Err(error) => $ret_type::from_error(error), } } } impl TryFromGlib for $ok_type { type Error = $err_type; #[inline] unsafe fn try_from_glib(val: ffi::$ffi_type) -> Result<$ok_type, $err_type> { skip_assert_initialized!(); $ret_type::from_glib(val).into_result() } } }; } impl StateChangeReturn { #[inline] pub fn into_result(self) -> Result { match self { StateChangeReturn::Failure => Err(StateChangeError), _ => Ok(unsafe { std::mem::transmute::(self) }), } } #[inline] pub fn from_error(_: StateChangeError) -> Self { skip_assert_initialized!(); StateChangeReturn::Failure } #[inline] pub fn from_ok(v: StateChangeSuccess) -> Self { skip_assert_initialized!(); unsafe { std::mem::transmute(v) } } } #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] #[repr(i32)] pub enum StateChangeSuccess { Success = ffi::GST_STATE_CHANGE_SUCCESS, Async = ffi::GST_STATE_CHANGE_ASYNC, NoPreroll = ffi::GST_STATE_CHANGE_NO_PREROLL, } #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Error)] #[must_use] #[error("Element failed to change its state")] pub struct StateChangeError; impl_return_result_traits!( GstStateChangeReturn, StateChangeReturn, StateChangeSuccess, StateChangeError ); #[must_use] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstFlowReturn")] pub enum FlowReturn { #[doc(alias = "GST_FLOW_CUSTOM_SUCCESS_2")] CustomSuccess2 = ffi::GST_FLOW_CUSTOM_SUCCESS_2, #[doc(alias = "GST_FLOW_CUSTOM_SUCCESS_1")] CustomSuccess1 = ffi::GST_FLOW_CUSTOM_SUCCESS_1, #[doc(alias = "GST_FLOW_CUSTOM_SUCCESS")] CustomSuccess = ffi::GST_FLOW_CUSTOM_SUCCESS, #[doc(alias = "GST_FLOW_OK")] Ok = ffi::GST_FLOW_OK, #[doc(alias = "GST_FLOW_NOT_LINKED")] NotLinked = ffi::GST_FLOW_NOT_LINKED, #[doc(alias = "GST_FLOW_FLUSHING")] Flushing = ffi::GST_FLOW_FLUSHING, #[doc(alias = "GST_FLOW_EOS")] Eos = ffi::GST_FLOW_EOS, #[doc(alias = "GST_FLOW_NOT_NEGOTIATED")] NotNegotiated = ffi::GST_FLOW_NOT_NEGOTIATED, #[doc(alias = "GST_FLOW_ERROR")] Error = ffi::GST_FLOW_ERROR, #[doc(alias = "GST_FLOW_NOT_SUPPORTED")] NotSupported = ffi::GST_FLOW_NOT_SUPPORTED, #[doc(alias = "GST_FLOW_CUSTOM_ERROR")] CustomError = ffi::GST_FLOW_CUSTOM_ERROR, #[doc(alias = "GST_FLOW_CUSTOM_ERROR_1")] CustomError1 = ffi::GST_FLOW_CUSTOM_ERROR_1, #[doc(alias = "GST_FLOW_CUSTOM_ERROR_2")] CustomError2 = ffi::GST_FLOW_CUSTOM_ERROR_2, } #[doc(hidden)] impl IntoGlib for FlowReturn { type GlibType = ffi::GstFlowReturn; #[inline] fn into_glib(self) -> ffi::GstFlowReturn { self as ffi::GstFlowReturn } } #[doc(hidden)] impl FromGlib for FlowReturn { #[inline] unsafe fn from_glib(value: ffi::GstFlowReturn) -> Self { skip_assert_initialized!(); if value < ffi::GST_FLOW_NOT_SUPPORTED && (value > ffi::GST_FLOW_CUSTOM_ERROR || value < ffi::GST_FLOW_CUSTOM_ERROR_2) { FlowReturn::Error } else if value > 0 && (value < ffi::GST_FLOW_CUSTOM_SUCCESS || value > ffi::GST_FLOW_CUSTOM_SUCCESS_2) { FlowReturn::Ok } else { std::mem::transmute::(value) } } } impl StaticType for FlowReturn { #[inline] fn static_type() -> Type { unsafe { from_glib(ffi::gst_flow_return_get_type()) } } } impl glib::value::ValueType for FlowReturn { type Type = Self; } unsafe impl<'a> FromValue<'a> for FlowReturn { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for FlowReturn { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: FlowReturn) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } impl FlowReturn { #[inline] pub fn into_result(self) -> Result { if self.into_glib() >= 0 { Ok(unsafe { std::mem::transmute::(self) }) } else { Err(unsafe { std::mem::transmute::(self) }) } } #[inline] pub fn from_error(v: FlowError) -> Self { skip_assert_initialized!(); unsafe { std::mem::transmute(v) } } #[inline] pub fn from_ok(v: FlowSuccess) -> Self { skip_assert_initialized!(); unsafe { std::mem::transmute(v) } } } #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] #[repr(i32)] pub enum FlowSuccess { CustomSuccess2 = ffi::GST_FLOW_CUSTOM_SUCCESS_2, CustomSuccess1 = ffi::GST_FLOW_CUSTOM_SUCCESS_1, CustomSuccess = ffi::GST_FLOW_CUSTOM_SUCCESS, Ok = ffi::GST_FLOW_OK, } #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Error)] #[must_use] #[repr(i32)] pub enum FlowError { #[error("Pad is not linked")] NotLinked = ffi::GST_FLOW_NOT_LINKED, #[error("Pad is flushing")] Flushing = ffi::GST_FLOW_FLUSHING, #[error("Pad is EOS")] Eos = ffi::GST_FLOW_EOS, #[error("Pad is not negotiated")] NotNegotiated = ffi::GST_FLOW_NOT_NEGOTIATED, #[error("Some (fatal) error occurred. Element generating this error should post an error message with more details")] Error = ffi::GST_FLOW_ERROR, #[error("This operation is not supported")] NotSupported = ffi::GST_FLOW_NOT_SUPPORTED, #[error("Elements can use values starting from this (and lower) to define custom error codes")] CustomError = ffi::GST_FLOW_CUSTOM_ERROR, #[error("Pre-defined custom error code")] CustomError1 = ffi::GST_FLOW_CUSTOM_ERROR_1, #[error("Pre-defined custom error code")] CustomError2 = ffi::GST_FLOW_CUSTOM_ERROR_2, } impl_return_result_traits!(GstFlowReturn, FlowReturn, FlowSuccess, FlowError); #[must_use] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[repr(i32)] #[doc(alias = "GstPadLinkReturn")] pub enum PadLinkReturn { #[doc(alias = "GST_PAD_LINK_OK")] Ok = ffi::GST_PAD_LINK_OK, #[doc(alias = "GST_PAD_LINK_WRONG_HIERARCHY")] WrongHierarchy = ffi::GST_PAD_LINK_WRONG_HIERARCHY, #[doc(alias = "GST_PAD_LINK_WAS_LINKED")] WasLinked = ffi::GST_PAD_LINK_WAS_LINKED, #[doc(alias = "GST_PAD_LINK_WRONG_DIRECTION")] WrongDirection = ffi::GST_PAD_LINK_WRONG_DIRECTION, #[doc(alias = "GST_PAD_LINK_NOFORMAT")] Noformat = ffi::GST_PAD_LINK_NOFORMAT, #[doc(alias = "GST_PAD_LINK_NOSCHED")] Nosched = ffi::GST_PAD_LINK_NOSCHED, #[doc(alias = "GST_PAD_LINK_REFUSED")] Refused = ffi::GST_PAD_LINK_REFUSED, } #[doc(hidden)] impl IntoGlib for PadLinkReturn { type GlibType = ffi::GstPadLinkReturn; #[inline] fn into_glib(self) -> ffi::GstPadLinkReturn { self as ffi::GstPadLinkReturn } } #[doc(hidden)] impl FromGlib for PadLinkReturn { #[inline] unsafe fn from_glib(value: ffi::GstPadLinkReturn) -> Self { skip_assert_initialized!(); if value >= 0 { PadLinkReturn::Ok } else if value < ffi::GST_PAD_LINK_REFUSED { PadLinkReturn::Refused } else { std::mem::transmute::(value) } } } impl StaticType for PadLinkReturn { #[inline] fn static_type() -> Type { unsafe { from_glib(ffi::gst_pad_link_return_get_type()) } } } impl glib::value::ValueType for PadLinkReturn { type Type = Self; } unsafe impl<'a> FromValue<'a> for PadLinkReturn { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for PadLinkReturn { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: PadLinkReturn) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } impl PadLinkReturn { #[inline] pub fn into_result(self) -> Result { if self == PadLinkReturn::Ok { Ok(PadLinkSuccess) } else { Err(unsafe { std::mem::transmute::(self) }) } } #[inline] pub fn from_error(v: PadLinkError) -> Self { skip_assert_initialized!(); unsafe { std::mem::transmute(v) } } #[inline] pub fn from_ok(_: PadLinkSuccess) -> Self { skip_assert_initialized!(); PadLinkReturn::Ok } } #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct PadLinkSuccess; #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Error)] #[must_use] #[repr(i32)] pub enum PadLinkError { #[error("Pads have no common grandparent")] WrongHierarchy = ffi::GST_PAD_LINK_WRONG_HIERARCHY, #[error("Pad was already linked")] WasLinked = ffi::GST_PAD_LINK_WAS_LINKED, #[error("Pads have wrong direction")] WrongDirection = ffi::GST_PAD_LINK_WRONG_DIRECTION, #[error("Pads do not have common format")] Noformat = ffi::GST_PAD_LINK_NOFORMAT, #[error("Pads cannot cooperate in scheduling")] Nosched = ffi::GST_PAD_LINK_NOSCHED, #[error("Refused for some other reason")] Refused = ffi::GST_PAD_LINK_REFUSED, } impl_return_result_traits!( GstPadLinkReturn, PadLinkReturn, PadLinkSuccess, PadLinkError ); impl ClockReturn { #[inline] pub fn into_result(self) -> Result { match self { ClockReturn::Ok => Ok(ClockSuccess::Ok), ClockReturn::Done => Ok(ClockSuccess::Done), _ => Err(unsafe { std::mem::transmute::(self) }), } } #[inline] pub fn from_error(v: ClockError) -> Self { skip_assert_initialized!(); unsafe { std::mem::transmute(v) } } #[inline] pub fn from_ok(v: ClockSuccess) -> Self { skip_assert_initialized!(); unsafe { std::mem::transmute(v) } } } #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] #[repr(i32)] pub enum ClockSuccess { Ok = ffi::GST_CLOCK_OK, Done = ffi::GST_CLOCK_DONE, } #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Error)] #[must_use] #[repr(i32)] pub enum ClockError { #[error("The operation was scheduled too late")] Early = ffi::GST_CLOCK_EARLY, #[error("The clockID was unscheduled")] Unscheduled = ffi::GST_CLOCK_UNSCHEDULED, #[error("The ClockID is busy")] Busy = ffi::GST_CLOCK_BUSY, #[error("A bad time was provided to a function")] Badtime = ffi::GST_CLOCK_BADTIME, #[error("An error occurred")] Error = ffi::GST_CLOCK_ERROR, #[error("Operation is not supported")] Unsupported = ffi::GST_CLOCK_UNSUPPORTED, } impl_return_result_traits!(GstClockReturn, ClockReturn, ClockSuccess, ClockError); impl PartialEq for crate::TypeFindProbability { #[inline] fn eq(&self, other: &crate::TypeFindProbability) -> bool { (self.into_glib() as u32).eq(&(other.into_glib() as u32)) } } impl Eq for crate::TypeFindProbability {} impl PartialOrd for crate::TypeFindProbability { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for crate::TypeFindProbability { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { (self.into_glib() as u32).cmp(&(other.into_glib() as u32)) } } impl ops::Add for crate::TypeFindProbability { type Output = crate::TypeFindProbability; #[inline] fn add(self, rhs: u32) -> crate::TypeFindProbability { let res = (self.into_glib() as u32).saturating_add(rhs); unsafe { from_glib(res as i32) } } } impl ops::AddAssign for crate::TypeFindProbability { #[inline] fn add_assign(&mut self, rhs: u32) { let res = (self.into_glib() as u32).saturating_add(rhs); *self = unsafe { from_glib(res as i32) }; } } impl ops::Sub for crate::TypeFindProbability { type Output = crate::TypeFindProbability; #[inline] fn sub(self, rhs: u32) -> crate::TypeFindProbability { let res = (self.into_glib() as u32).saturating_sub(rhs); unsafe { from_glib(res as i32) } } } impl ops::SubAssign for crate::TypeFindProbability { #[inline] fn sub_assign(&mut self, rhs: u32) { let res = (self.into_glib() as u32).saturating_sub(rhs); *self = unsafe { from_glib(res as i32) }; } } #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Error)] #[must_use] pub enum TagError { #[error("The value type doesn't match with the specified Tag")] TypeMismatch, } // This cannot be done automatically because in GStreamer it's exposed as a bitflag but works as an // enum instead #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] #[doc(alias = "GstMessageType")] #[non_exhaustive] pub enum MessageType { #[doc(alias = "GST_MESSAGE_UNKNOWN")] Unknown, #[doc(alias = "GST_MESSAGE_EOS")] Eos, #[doc(alias = "GST_MESSAGE_ERROR")] Error, #[doc(alias = "GST_MESSAGE_WARNING")] Warning, #[doc(alias = "GST_MESSAGE_INFO")] Info, #[doc(alias = "GST_MESSAGE_TAG")] Tag, #[doc(alias = "GST_MESSAGE_BUFFERING")] Buffering, #[doc(alias = "GST_MESSAGE_STATE_CHANGED")] StateChanged, #[doc(alias = "GST_MESSAGE_STATE_DIRTY")] StateDirty, #[doc(alias = "GST_MESSAGE_STEP_DONE")] StepDone, #[doc(alias = "GST_MESSAGE_CLOCK_PROVIDE")] ClockProvide, #[doc(alias = "GST_MESSAGE_CLOCK_LOST")] ClockLost, #[doc(alias = "GST_MESSAGE_NEW_CLOCK")] NewClock, #[doc(alias = "GST_MESSAGE_STRUCTURE_CHANGE")] StructureChange, #[doc(alias = "GST_MESSAGE_STREAM_STATUS")] StreamStatus, #[doc(alias = "GST_MESSAGE_APPLICATION")] Application, #[doc(alias = "GST_MESSAGE_ELEMENT")] Element, #[doc(alias = "GST_MESSAGE_SEGMENT_START")] SegmentStart, #[doc(alias = "GST_MESSAGE_SEGMENT_DONE")] SegmentDone, #[doc(alias = "GST_MESSAGE_DURATION_CHANGED")] DurationChanged, #[doc(alias = "GST_MESSAGE_LATENCY")] Latency, #[doc(alias = "GST_MESSAGE_ASYNC_START")] AsyncStart, #[doc(alias = "GST_MESSAGE_ASYNC_DONE")] AsyncDone, #[doc(alias = "GST_MESSAGE_REQUEST_STATE")] RequestState, #[doc(alias = "GST_MESSAGE_STEP_START")] StepStart, #[doc(alias = "GST_MESSAGE_QOS")] Qos, #[doc(alias = "GST_MESSAGE_PROGRESS")] Progress, #[doc(alias = "GST_MESSAGE_TOC")] Toc, #[doc(alias = "GST_MESSAGE_RESET_TIME")] ResetTime, #[doc(alias = "GST_MESSAGE_STREAM_START")] StreamStart, #[doc(alias = "GST_MESSAGE_NEED_CONTEXT")] NeedContext, #[doc(alias = "GST_MESSAGE_HAVE_CONTEXT")] HaveContext, #[doc(alias = "GST_MESSAGE_EXTENDED")] Extended, #[doc(alias = "GST_MESSAGE_DEVICE_ADDED")] DeviceAdded, #[doc(alias = "GST_MESSAGE_DEVICE_REMOVED")] DeviceRemoved, #[doc(alias = "GST_MESSAGE_PROPERTY_NOTIFY")] PropertyNotify, #[doc(alias = "GST_MESSAGE_STREAM_COLLECTION")] StreamCollection, #[doc(alias = "GST_MESSAGE_STREAMS_SELECTED")] StreamsSelected, #[doc(alias = "GST_MESSAGE_REDIRECT")] Redirect, #[doc(hidden)] __Unknown(i32), } #[doc(hidden)] impl IntoGlib for MessageType { type GlibType = ffi::GstMessageType; fn into_glib(self) -> ffi::GstMessageType { match self { MessageType::Unknown => ffi::GST_MESSAGE_UNKNOWN, MessageType::Eos => ffi::GST_MESSAGE_EOS, MessageType::Error => ffi::GST_MESSAGE_ERROR, MessageType::Warning => ffi::GST_MESSAGE_WARNING, MessageType::Info => ffi::GST_MESSAGE_INFO, MessageType::Tag => ffi::GST_MESSAGE_TAG, MessageType::Buffering => ffi::GST_MESSAGE_BUFFERING, MessageType::StateChanged => ffi::GST_MESSAGE_STATE_CHANGED, MessageType::StateDirty => ffi::GST_MESSAGE_STATE_DIRTY, MessageType::StepDone => ffi::GST_MESSAGE_STEP_DONE, MessageType::ClockProvide => ffi::GST_MESSAGE_CLOCK_PROVIDE, MessageType::ClockLost => ffi::GST_MESSAGE_CLOCK_LOST, MessageType::NewClock => ffi::GST_MESSAGE_NEW_CLOCK, MessageType::StructureChange => ffi::GST_MESSAGE_STRUCTURE_CHANGE, MessageType::StreamStatus => ffi::GST_MESSAGE_STREAM_STATUS, MessageType::Application => ffi::GST_MESSAGE_APPLICATION, MessageType::Element => ffi::GST_MESSAGE_ELEMENT, MessageType::SegmentStart => ffi::GST_MESSAGE_SEGMENT_START, MessageType::SegmentDone => ffi::GST_MESSAGE_SEGMENT_DONE, MessageType::DurationChanged => ffi::GST_MESSAGE_DURATION_CHANGED, MessageType::Latency => ffi::GST_MESSAGE_LATENCY, MessageType::AsyncStart => ffi::GST_MESSAGE_ASYNC_START, MessageType::AsyncDone => ffi::GST_MESSAGE_ASYNC_DONE, MessageType::RequestState => ffi::GST_MESSAGE_REQUEST_STATE, MessageType::StepStart => ffi::GST_MESSAGE_STEP_START, MessageType::Qos => ffi::GST_MESSAGE_QOS, MessageType::Progress => ffi::GST_MESSAGE_PROGRESS, MessageType::Toc => ffi::GST_MESSAGE_TOC, MessageType::ResetTime => ffi::GST_MESSAGE_RESET_TIME, MessageType::StreamStart => ffi::GST_MESSAGE_STREAM_START, MessageType::NeedContext => ffi::GST_MESSAGE_NEED_CONTEXT, MessageType::HaveContext => ffi::GST_MESSAGE_HAVE_CONTEXT, MessageType::Extended => ffi::GST_MESSAGE_EXTENDED, MessageType::DeviceAdded => ffi::GST_MESSAGE_DEVICE_ADDED, MessageType::DeviceRemoved => ffi::GST_MESSAGE_DEVICE_REMOVED, MessageType::PropertyNotify => ffi::GST_MESSAGE_PROPERTY_NOTIFY, MessageType::StreamCollection => ffi::GST_MESSAGE_STREAM_COLLECTION, MessageType::StreamsSelected => ffi::GST_MESSAGE_STREAMS_SELECTED, MessageType::Redirect => ffi::GST_MESSAGE_REDIRECT, MessageType::__Unknown(value) => value as u32, } } } #[doc(hidden)] impl FromGlib for MessageType { #[allow(clippy::unreadable_literal)] unsafe fn from_glib(value: ffi::GstMessageType) -> Self { skip_assert_initialized!(); match value { ffi::GST_MESSAGE_UNKNOWN => MessageType::Unknown, ffi::GST_MESSAGE_EOS => MessageType::Eos, ffi::GST_MESSAGE_ERROR => MessageType::Error, ffi::GST_MESSAGE_WARNING => MessageType::Warning, ffi::GST_MESSAGE_INFO => MessageType::Info, ffi::GST_MESSAGE_TAG => MessageType::Tag, ffi::GST_MESSAGE_BUFFERING => MessageType::Buffering, ffi::GST_MESSAGE_STATE_CHANGED => MessageType::StateChanged, ffi::GST_MESSAGE_STATE_DIRTY => MessageType::StateDirty, ffi::GST_MESSAGE_STEP_DONE => MessageType::StepDone, ffi::GST_MESSAGE_CLOCK_PROVIDE => MessageType::ClockProvide, ffi::GST_MESSAGE_CLOCK_LOST => MessageType::ClockLost, ffi::GST_MESSAGE_NEW_CLOCK => MessageType::NewClock, ffi::GST_MESSAGE_STRUCTURE_CHANGE => MessageType::StructureChange, ffi::GST_MESSAGE_STREAM_STATUS => MessageType::StreamStatus, ffi::GST_MESSAGE_APPLICATION => MessageType::Application, ffi::GST_MESSAGE_ELEMENT => MessageType::Element, ffi::GST_MESSAGE_SEGMENT_START => MessageType::SegmentStart, ffi::GST_MESSAGE_SEGMENT_DONE => MessageType::SegmentDone, ffi::GST_MESSAGE_DURATION_CHANGED => MessageType::DurationChanged, ffi::GST_MESSAGE_LATENCY => MessageType::Latency, ffi::GST_MESSAGE_ASYNC_START => MessageType::AsyncStart, ffi::GST_MESSAGE_ASYNC_DONE => MessageType::AsyncDone, ffi::GST_MESSAGE_REQUEST_STATE => MessageType::RequestState, ffi::GST_MESSAGE_STEP_START => MessageType::StepStart, ffi::GST_MESSAGE_QOS => MessageType::Qos, ffi::GST_MESSAGE_PROGRESS => MessageType::Progress, ffi::GST_MESSAGE_TOC => MessageType::Toc, ffi::GST_MESSAGE_RESET_TIME => MessageType::ResetTime, ffi::GST_MESSAGE_STREAM_START => MessageType::StreamStart, ffi::GST_MESSAGE_NEED_CONTEXT => MessageType::NeedContext, ffi::GST_MESSAGE_HAVE_CONTEXT => MessageType::HaveContext, ffi::GST_MESSAGE_EXTENDED => MessageType::Extended, ffi::GST_MESSAGE_DEVICE_ADDED => MessageType::DeviceAdded, ffi::GST_MESSAGE_DEVICE_REMOVED => MessageType::DeviceRemoved, ffi::GST_MESSAGE_PROPERTY_NOTIFY => MessageType::PropertyNotify, ffi::GST_MESSAGE_STREAM_COLLECTION => MessageType::StreamCollection, ffi::GST_MESSAGE_STREAMS_SELECTED => MessageType::StreamsSelected, ffi::GST_MESSAGE_REDIRECT => MessageType::Redirect, value => MessageType::__Unknown(value as i32), } } } impl StaticType for MessageType { #[inline] fn static_type() -> Type { unsafe { from_glib(ffi::gst_message_type_get_type()) } } } impl glib::value::ValueType for MessageType { type Type = Self; } unsafe impl FromValue<'_> for MessageType { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0) as ffi::GstMessageType) } } impl ToValue for MessageType { #[inline] fn to_value(&self) -> Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib() as i32) } value } #[inline] fn value_type(&self) -> Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: MessageType) -> glib::Value { skip_assert_initialized!(); ToValue::to_value(&v) } } impl State { #[must_use] #[inline] pub fn next(self, pending: Self) -> Self { let current = self.into_glib(); let pending = pending.into_glib(); let sign = (pending - current).signum(); unsafe { from_glib(current + sign) } } } impl StateChange { #[inline] pub fn new(current: State, next: State) -> Self { skip_assert_initialized!(); let current = current.into_glib(); let next = next.into_glib(); unsafe { from_glib((current << 3) | next) } } #[inline] pub fn current(self) -> State { unsafe { from_glib(self.into_glib() >> 3) } } #[inline] pub fn next(self) -> State { unsafe { from_glib(self.into_glib() & 0x7) } } } gstreamer-0.23.5/src/error.rs000064400000000000000000000117751046102023000142050ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::{prelude::*, translate::*}; use thiserror::Error; #[macro_export] macro_rules! error_msg( ($err:expr, ($($msg:tt)*), [$($dbg:tt)*]) => { { $crate::ErrorMessage::new(&$err, Some(format!($($msg)*).as_ref()), Some(format!($($dbg)*).as_ref()), file!(), $crate::glib::function_name!(), line!()) }}; ($err:expr, ($($msg:tt)*)) => { { $crate::ErrorMessage::new(&$err, Some(format!($($msg)*).as_ref()), None, file!(), $crate::glib::function_name!(), line!()) }}; ($err:expr, [$($dbg:tt)*]) => { { $crate::ErrorMessage::new(&$err, None, Some(format!($($dbg)*).as_ref()), file!(), $crate::glib::function_name!(), line!()) }}; ); #[derive(Clone, Debug, PartialEq, Eq, Error)] #[error("Error {:?} ({:?}) at {}:{}", .message, .debug, .filename, .line)] pub struct ErrorMessage { pub(crate) error_domain: glib::Quark, pub(crate) error_code: i32, pub(crate) message: Option, pub(crate) debug: Option, pub(crate) filename: &'static str, pub(crate) function: &'static str, pub(crate) line: u32, } impl ErrorMessage { pub fn new( error: &T, message: Option<&str>, debug: Option<&str>, filename: &'static str, function: &'static str, line: u32, ) -> ErrorMessage { skip_assert_initialized!(); let error_domain = T::domain(); let error_code = error.code(); ErrorMessage { error_domain, error_code, message: message.map(String::from), debug: debug.map(String::from), filename, function, line, } } } #[macro_export] macro_rules! loggable_error( ($cat:expr, $($msg:tt)*) => { { $crate::LoggableError::new($cat.clone(), $crate::glib::bool_error!($($msg)*)) }}; ); #[macro_export] macro_rules! result_from_gboolean( ($ffi_bool:expr, $cat:expr, $($msg:tt)*) => { { $crate::glib::result_from_gboolean!($ffi_bool, $($msg)*) .map_err(|bool_err| $crate::LoggableError::new($cat.clone(), bool_err)) }}; ); #[derive(Debug, Clone, Error)] #[error("Error {:?}: {:?} at {}:{}", .category.name(), .bool_error.message, .bool_error.filename, .bool_error.line)] pub struct LoggableError { category: crate::DebugCategory, bool_error: glib::BoolError, } impl LoggableError { pub fn new(category: crate::DebugCategory, bool_error: glib::BoolError) -> LoggableError { skip_assert_initialized!(); LoggableError { category, bool_error, } } #[inline(never)] pub fn log(&self) { self.bool_error.filename.run_with_gstr(|filename| { self.category.log( None::<&glib::Object>, crate::DebugLevel::Error, filename, self.bool_error.function, self.bool_error.line, format_args!("{}", self.bool_error.message), ); }); } pub fn log_with_object(&self, obj: &impl IsA) { self.log_with_object_internal(obj.as_ref()); } #[inline(never)] fn log_with_object_internal(&self, obj: &glib::Object) { self.bool_error.filename.run_with_gstr(|filename| { self.category.log( Some(obj), crate::DebugLevel::Error, filename, self.bool_error.function, self.bool_error.line, format_args!("{}", self.bool_error.message), ); }); } pub fn log_with_imp(&self, imp: &impl glib::subclass::types::ObjectSubclass) { use glib::subclass::prelude::*; self.log_with_object_internal(unsafe { imp.obj().unsafe_cast_ref::() }); } pub fn category(&self) -> crate::DebugCategory { self.category } } impl From for LoggableError { fn from(bool_error: glib::BoolError) -> Self { skip_assert_initialized!(); LoggableError { category: *crate::CAT_RUST, bool_error, } } } #[cfg(test)] mod tests { use super::*; #[test] fn error_message() { crate::init().unwrap(); let e = ErrorMessage::new( &crate::CoreError::Failed, Some("message"), Some("debug"), "filename", "function", 7, ); assert_eq!( format!("{e}"), "Error Some(\"message\") (Some(\"debug\")) at filename:7" ); } #[test] fn logabble_error() { crate::init().unwrap(); let e: LoggableError = glib::BoolError::new("msg", "filename", "function", 7).into(); assert_eq!(format!("{e}"), "Error \"GST_RUST\": \"msg\" at filename:7"); } } gstreamer-0.23.5/src/event.rs000064400000000000000000003052361046102023000141730ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ borrow::Borrow, cmp, ffi::CStr, fmt, mem, num::NonZeroU32, ops::Deref, ops::DerefMut, ptr, }; use glib::{ translate::{FromGlibPtrContainer, *}, value::ToSendValue, }; use crate::{ ffi, format::{ CompatibleFormattedValue, FormattedValue, FormattedValueIntrinsic, GenericFormattedValue, }, structure::*, ClockTime, EventType, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Seqnum(pub(crate) NonZeroU32); impl Seqnum { #[doc(alias = "gst_util_seqnum_next")] #[inline] pub fn next() -> Self { unsafe { let v = ffi::gst_util_seqnum_next(); if v == 0 { Seqnum::next() } else { Seqnum(NonZeroU32::new_unchecked(v)) } } } } impl IntoGlib for Seqnum { type GlibType = u32; #[inline] fn into_glib(self) -> u32 { self.0.get() } } impl cmp::PartialOrd for Seqnum { #[inline] fn partial_cmp(&self, other: &Seqnum) -> Option { Some(self.cmp(other)) } } impl cmp::Ord for Seqnum { #[inline] fn cmp(&self, other: &Seqnum) -> cmp::Ordering { unsafe { let ret = ffi::gst_util_seqnum_compare(self.0.get(), other.0.get()); ret.cmp(&0) } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct GroupId(pub(crate) NonZeroU32); impl GroupId { #[doc(alias = "gst_util_group_id_next")] #[inline] pub fn next() -> Self { unsafe { let v = ffi::gst_util_group_id_next(); if v == 0 { GroupId::next() } else { GroupId(NonZeroU32::new_unchecked(v)) } } } } impl EventType { #[doc(alias = "GST_EVENT_IS_UPSTREAM")] #[inline] pub fn is_upstream(self) -> bool { (self.into_glib() as u32) & ffi::GST_EVENT_TYPE_UPSTREAM != 0 } #[doc(alias = "GST_EVENT_IS_DOWNSTREAM")] #[inline] pub fn is_downstream(self) -> bool { (self.into_glib() as u32) & ffi::GST_EVENT_TYPE_DOWNSTREAM != 0 } #[doc(alias = "GST_EVENT_IS_SERIALIZED")] #[inline] pub fn is_serialized(self) -> bool { (self.into_glib() as u32) & ffi::GST_EVENT_TYPE_SERIALIZED != 0 } #[doc(alias = "GST_EVENT_IS_STICKY")] #[inline] pub fn is_sticky(self) -> bool { (self.into_glib() as u32) & ffi::GST_EVENT_TYPE_STICKY != 0 } #[doc(alias = "GST_EVENT_IS_STICKY_MULTI")] #[inline] pub fn is_sticky_multi(self) -> bool { (self.into_glib() as u32) & ffi::GST_EVENT_TYPE_STICKY_MULTI != 0 } } impl PartialOrd for EventType { fn partial_cmp(&self, other: &Self) -> Option { if !self.is_serialized() || !other.is_serialized() { return None; } // See gst_event_type_to_sticky_ordering() from 1.22 let fixup_event_ordering = |v| match v { ffi::GST_EVENT_INSTANT_RATE_CHANGE => ffi::GST_EVENT_SEGMENT as u32 + 1, _ => v as u32, }; let v1 = fixup_event_ordering(self.into_glib()); let v2 = fixup_event_ordering(other.into_glib()); let stream_start = ffi::GST_EVENT_STREAM_START as u32; let segment = ffi::GST_EVENT_SEGMENT as u32; let eos = ffi::GST_EVENT_EOS as u32; // Strictly ordered range between stream_start and segment, // and EOS is bigger than everything else if v1 >= stream_start && v1 <= segment || v2 >= stream_start && v2 <= segment { Some(v1.cmp(&v2)) // If one is EOS, the other is definitely less or equal } else if v1 == eos || v2 == eos { if v1 == v2 { Some(cmp::Ordering::Equal) } else if v1 == eos { Some(cmp::Ordering::Greater) } else { Some(cmp::Ordering::Less) } } else { None } } } mini_object_wrapper!(Event, EventRef, ffi::GstEvent, || { ffi::gst_event_get_type() }); impl EventRef { #[doc(alias = "get_seqnum")] #[doc(alias = "gst_event_get_seqnum")] pub fn seqnum(&self) -> Seqnum { unsafe { let seqnum = ffi::gst_event_get_seqnum(self.as_mut_ptr()); debug_assert_ne!(seqnum, 0); Seqnum(NonZeroU32::new_unchecked(seqnum)) } } #[doc(alias = "gst_event_set_seqnum")] pub fn set_seqnum(&mut self, seqnum: Seqnum) { unsafe { ffi::gst_event_set_seqnum(self.as_mut_ptr(), seqnum.0.get()); } } #[doc(alias = "get_running_time_offset")] #[doc(alias = "gst_event_get_running_time_offset")] pub fn running_time_offset(&self) -> i64 { unsafe { ffi::gst_event_get_running_time_offset(self.as_mut_ptr()) } } #[doc(alias = "gst_event_set_running_time_offset")] pub fn set_running_time_offset(&mut self, offset: i64) { unsafe { ffi::gst_event_set_running_time_offset(self.as_mut_ptr(), offset) } } #[doc(alias = "get_structure")] #[doc(alias = "gst_event_get_structure")] #[inline] pub fn structure(&self) -> Option<&StructureRef> { unsafe { let structure = ffi::gst_event_get_structure(self.as_mut_ptr()); if structure.is_null() { None } else { Some(StructureRef::from_glib_borrow(structure)) } } } #[doc(alias = "gst_event_writable_structure")] #[inline] pub fn structure_mut(&mut self) -> &mut StructureRef { unsafe { StructureRef::from_glib_borrow_mut(ffi::gst_event_writable_structure(self.as_mut_ptr())) } } #[doc(alias = "GST_EVENT_IS_UPSTREAM")] #[inline] pub fn is_upstream(&self) -> bool { self.type_().is_upstream() } #[doc(alias = "GST_EVENT_IS_DOWNSTREAM")] #[inline] pub fn is_downstream(&self) -> bool { self.type_().is_downstream() } #[doc(alias = "GST_EVENT_IS_SERIALIZED")] #[inline] pub fn is_serialized(&self) -> bool { self.type_().is_serialized() } #[doc(alias = "GST_EVENT_IS_STICKY")] #[inline] pub fn is_sticky(&self) -> bool { self.type_().is_sticky() } #[doc(alias = "GST_EVENT_IS_STICKY_MULTI")] #[inline] pub fn is_sticky_multi(&self) -> bool { self.type_().is_sticky_multi() } #[doc(alias = "get_type")] #[doc(alias = "GST_EVENT_TYPE")] #[inline] pub fn type_(&self) -> EventType { unsafe { from_glib((*self.as_ptr()).type_) } } #[doc(alias = "gst_event_has_name")] #[inline] pub fn has_name(&self, name: &str) -> bool { self.structure().is_some_and(|s| s.has_name(name)) } pub fn view(&self) -> EventView { unsafe { let type_ = (*self.as_ptr()).type_; match type_ { ffi::GST_EVENT_FLUSH_START => FlushStart::view(self), ffi::GST_EVENT_FLUSH_STOP => FlushStop::view(self), ffi::GST_EVENT_STREAM_START => StreamStart::view(self), ffi::GST_EVENT_CAPS => Caps::view(self), ffi::GST_EVENT_SEGMENT => Segment::view(self), ffi::GST_EVENT_STREAM_COLLECTION => StreamCollection::view(self), ffi::GST_EVENT_TAG => Tag::view(self), ffi::GST_EVENT_BUFFERSIZE => Buffersize::view(self), ffi::GST_EVENT_SINK_MESSAGE => SinkMessage::view(self), ffi::GST_EVENT_STREAM_GROUP_DONE => StreamGroupDone::view(self), ffi::GST_EVENT_EOS => Eos::view(self), ffi::GST_EVENT_TOC => Toc::view(self), ffi::GST_EVENT_PROTECTION => Protection::view(self), ffi::GST_EVENT_SEGMENT_DONE => SegmentDone::view(self), ffi::GST_EVENT_GAP => Gap::view(self), #[cfg(feature = "v1_18")] ffi::GST_EVENT_INSTANT_RATE_CHANGE => InstantRateChange::view(self), ffi::GST_EVENT_QOS => Qos::view(self), ffi::GST_EVENT_SEEK => Seek::view(self), ffi::GST_EVENT_NAVIGATION => Navigation::view(self), ffi::GST_EVENT_LATENCY => Latency::view(self), ffi::GST_EVENT_STEP => Step::view(self), ffi::GST_EVENT_RECONFIGURE => Reconfigure::view(self), ffi::GST_EVENT_TOC_SELECT => TocSelect::view(self), ffi::GST_EVENT_SELECT_STREAMS => SelectStreams::view(self), #[cfg(feature = "v1_18")] ffi::GST_EVENT_INSTANT_RATE_SYNC_TIME => InstantRateSyncTime::view(self), ffi::GST_EVENT_CUSTOM_UPSTREAM => CustomUpstream::view(self), ffi::GST_EVENT_CUSTOM_DOWNSTREAM => CustomDownstream::view(self), ffi::GST_EVENT_CUSTOM_DOWNSTREAM_OOB => CustomDownstreamOob::view(self), ffi::GST_EVENT_CUSTOM_DOWNSTREAM_STICKY => CustomDownstreamSticky::view(self), ffi::GST_EVENT_CUSTOM_BOTH => CustomBoth::view(self), ffi::GST_EVENT_CUSTOM_BOTH_OOB => CustomBothOob::view(self), _ => Other::view(self), } } } pub fn view_mut(&mut self) -> EventViewMut { unsafe { let type_ = (*self.as_ptr()).type_; match type_ { ffi::GST_EVENT_FLUSH_START => FlushStart::view_mut(self), ffi::GST_EVENT_FLUSH_STOP => FlushStop::view_mut(self), ffi::GST_EVENT_STREAM_START => StreamStart::view_mut(self), ffi::GST_EVENT_CAPS => Caps::view_mut(self), ffi::GST_EVENT_SEGMENT => Segment::view_mut(self), ffi::GST_EVENT_STREAM_COLLECTION => StreamCollection::view_mut(self), ffi::GST_EVENT_TAG => Tag::view_mut(self), ffi::GST_EVENT_BUFFERSIZE => Buffersize::view_mut(self), ffi::GST_EVENT_SINK_MESSAGE => SinkMessage::view_mut(self), ffi::GST_EVENT_STREAM_GROUP_DONE => StreamGroupDone::view_mut(self), ffi::GST_EVENT_EOS => Eos::view_mut(self), ffi::GST_EVENT_TOC => Toc::view_mut(self), ffi::GST_EVENT_PROTECTION => Protection::view_mut(self), ffi::GST_EVENT_SEGMENT_DONE => SegmentDone::view_mut(self), ffi::GST_EVENT_GAP => Gap::view_mut(self), #[cfg(feature = "v1_18")] ffi::GST_EVENT_INSTANT_RATE_CHANGE => InstantRateChange::view_mut(self), ffi::GST_EVENT_QOS => Qos::view_mut(self), ffi::GST_EVENT_SEEK => Seek::view_mut(self), ffi::GST_EVENT_NAVIGATION => Navigation::view_mut(self), ffi::GST_EVENT_LATENCY => Latency::view_mut(self), ffi::GST_EVENT_STEP => Step::view_mut(self), ffi::GST_EVENT_RECONFIGURE => Reconfigure::view_mut(self), ffi::GST_EVENT_TOC_SELECT => TocSelect::view_mut(self), ffi::GST_EVENT_SELECT_STREAMS => SelectStreams::view_mut(self), #[cfg(feature = "v1_18")] ffi::GST_EVENT_INSTANT_RATE_SYNC_TIME => InstantRateSyncTime::view_mut(self), ffi::GST_EVENT_CUSTOM_UPSTREAM => CustomUpstream::view_mut(self), ffi::GST_EVENT_CUSTOM_DOWNSTREAM => CustomDownstream::view_mut(self), ffi::GST_EVENT_CUSTOM_DOWNSTREAM_OOB => CustomDownstreamOob::view_mut(self), ffi::GST_EVENT_CUSTOM_DOWNSTREAM_STICKY => CustomDownstreamSticky::view_mut(self), ffi::GST_EVENT_CUSTOM_BOTH => CustomBoth::view_mut(self), ffi::GST_EVENT_CUSTOM_BOTH_OOB => CustomBothOob::view_mut(self), _ => Other::view_mut(self), } } } } impl fmt::Debug for Event { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { EventRef::fmt(self, f) } } impl fmt::Debug for EventRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Event") .field("ptr", &self.as_ptr()) .field("type", &self.type_().name()) .field("seqnum", &self.seqnum()) .field("structure", &self.structure()) .finish() } } pub trait StickyEventType: ToOwned { const TYPE: EventType; unsafe fn from_event(event: Event) -> Self::Owned; } #[derive(Debug)] #[non_exhaustive] pub enum EventView<'a> { FlushStart(&'a FlushStart), FlushStop(&'a FlushStop), StreamStart(&'a StreamStart), Caps(&'a Caps), Segment(&'a Segment), StreamCollection(&'a StreamCollection), Tag(&'a Tag), Buffersize(&'a Buffersize), SinkMessage(&'a SinkMessage), StreamGroupDone(&'a StreamGroupDone), Eos(&'a Eos), Toc(&'a Toc), Protection(&'a Protection), SegmentDone(&'a SegmentDone), Gap(&'a Gap), #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] InstantRateChange(&'a InstantRateChange), Qos(&'a Qos), Seek(&'a Seek), Navigation(&'a Navigation), Latency(&'a Latency), Step(&'a Step), Reconfigure(&'a Reconfigure), TocSelect(&'a TocSelect), SelectStreams(&'a SelectStreams), #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] InstantRateSyncTime(&'a InstantRateSyncTime), CustomUpstream(&'a CustomUpstream), CustomDownstream(&'a CustomDownstream), CustomDownstreamOob(&'a CustomDownstreamOob), CustomDownstreamSticky(&'a CustomDownstreamSticky), CustomBoth(&'a CustomBoth), CustomBothOob(&'a CustomBothOob), Other(&'a Other), } #[derive(Debug)] #[non_exhaustive] pub enum EventViewMut<'a> { FlushStart(&'a mut FlushStart), FlushStop(&'a mut FlushStop), StreamStart(&'a mut StreamStart), Caps(&'a mut Caps), Segment(&'a mut Segment), StreamCollection(&'a mut StreamCollection), Tag(&'a mut Tag), Buffersize(&'a mut Buffersize), SinkMessage(&'a mut SinkMessage), StreamGroupDone(&'a mut StreamGroupDone), Eos(&'a mut Eos), Toc(&'a mut Toc), Protection(&'a mut Protection), SegmentDone(&'a mut SegmentDone), Gap(&'a mut Gap), #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] InstantRateChange(&'a mut InstantRateChange), Qos(&'a mut Qos), Seek(&'a mut Seek), Navigation(&'a mut Navigation), Latency(&'a mut Latency), Step(&'a mut Step), Reconfigure(&'a mut Reconfigure), TocSelect(&'a mut TocSelect), SelectStreams(&'a mut SelectStreams), #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] InstantRateSyncTime(&'a mut InstantRateSyncTime), CustomUpstream(&'a mut CustomUpstream), CustomDownstream(&'a mut CustomDownstream), CustomDownstreamOob(&'a mut CustomDownstreamOob), CustomDownstreamSticky(&'a mut CustomDownstreamSticky), CustomBoth(&'a mut CustomBoth), CustomBothOob(&'a mut CustomBothOob), Other(&'a mut Other), } macro_rules! declare_concrete_event { (@sticky $name:ident, $param:ident) => { declare_concrete_event!($name, $param); impl StickyEventType for $name { const TYPE: EventType = EventType::$name; #[inline] unsafe fn from_event(event: Event) -> Self::Owned { $name::(event) } } }; ($name:ident, $param:ident) => { #[repr(transparent)] pub struct $name<$param = EventRef>($param); impl $name { #[inline] pub fn event(&self) -> &EventRef { unsafe { &*(self as *const Self as *const EventRef) } } #[inline] pub fn event_mut(&mut self) -> &mut EventRef { unsafe { &mut *(self as *mut Self as *mut EventRef) } } #[inline] unsafe fn view(event: &EventRef) -> EventView<'_> { let event = &*(event as *const EventRef as *const Self); EventView::$name(event) } #[inline] unsafe fn view_mut(event: &mut EventRef) -> EventViewMut<'_> { let event = &mut *(event as *mut EventRef as *mut Self); EventViewMut::$name(event) } } impl Deref for $name { type Target = EventRef; #[inline] fn deref(&self) -> &Self::Target { self.event() } } impl DerefMut for $name { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.event_mut() } } impl ToOwned for $name { type Owned = $name; #[inline] fn to_owned(&self) -> Self::Owned { $name::(self.copy()) } } impl $name { #[inline] pub fn get_mut(&mut self) -> Option<&mut $name> { self.0 .get_mut() .map(|event| unsafe { &mut *(event as *mut EventRef as *mut $name) }) } } impl Deref for $name { type Target = $name; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self.0.as_ptr() as *const Self::Target) } } } impl DerefMut for $name { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { debug_assert!(self.0.is_writable()); unsafe { &mut *(self.0.as_mut_ptr() as *mut Self::Target) } } } impl Borrow<$name> for $name { #[inline] fn borrow(&self) -> &$name { &*self } } impl From<$name> for Event { #[inline] fn from(concrete: $name) -> Self { skip_assert_initialized!(); concrete.0 } } }; } declare_concrete_event!(FlushStart, T); impl FlushStart { #[doc(alias = "gst_event_new_flush_start")] #[allow(clippy::new_ret_no_self)] pub fn new() -> Event { skip_assert_initialized!(); Self::builder().build() } pub fn builder<'a>() -> FlushStartBuilder<'a> { assert_initialized_main_thread!(); FlushStartBuilder::new() } } impl std::fmt::Debug for FlushStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FlushStart") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .finish() } } impl std::fmt::Debug for FlushStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { FlushStart::::fmt(self, f) } } declare_concrete_event!(FlushStop, T); impl FlushStop { #[doc(alias = "gst_event_new_flush_stop")] #[allow(clippy::new_ret_no_self)] pub fn new(reset_time: bool) -> Event { skip_assert_initialized!(); Self::builder(reset_time).build() } pub fn builder<'a>(reset_time: bool) -> FlushStopBuilder<'a> { assert_initialized_main_thread!(); FlushStopBuilder::new(reset_time) } } impl FlushStop { #[doc(alias = "get_reset_time")] #[doc(alias = "gst_event_parse_flush_stop")] pub fn resets_time(&self) -> bool { unsafe { let mut reset_time = mem::MaybeUninit::uninit(); ffi::gst_event_parse_flush_stop(self.as_mut_ptr(), reset_time.as_mut_ptr()); from_glib(reset_time.assume_init()) } } } impl std::fmt::Debug for FlushStop { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FlushStop") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("resets-time", &self.resets_time()) .finish() } } impl std::fmt::Debug for FlushStop { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { FlushStop::::fmt(self, f) } } declare_concrete_event!(@sticky StreamStart, T); impl StreamStart { #[doc(alias = "gst_event_new_stream_start")] #[allow(clippy::new_ret_no_self)] pub fn new(stream_id: &str) -> Event { skip_assert_initialized!(); Self::builder(stream_id).build() } pub fn builder(stream_id: &str) -> StreamStartBuilder { assert_initialized_main_thread!(); StreamStartBuilder::new(stream_id) } } impl StreamStart { #[doc(alias = "get_stream_id")] #[doc(alias = "gst_event_parse_stream_start")] pub fn stream_id(&self) -> &str { unsafe { let mut stream_id = ptr::null(); ffi::gst_event_parse_stream_start(self.as_mut_ptr(), &mut stream_id); CStr::from_ptr(stream_id).to_str().unwrap() } } #[doc(alias = "get_stream_flags")] #[doc(alias = "gst_event_parse_stream_flags")] pub fn stream_flags(&self) -> crate::StreamFlags { unsafe { let mut stream_flags = mem::MaybeUninit::uninit(); ffi::gst_event_parse_stream_flags(self.as_mut_ptr(), stream_flags.as_mut_ptr()); from_glib(stream_flags.assume_init()) } } #[doc(alias = "get_group_id")] #[doc(alias = "gst_event_parse_group_id")] pub fn group_id(&self) -> Option { unsafe { let mut group_id = mem::MaybeUninit::uninit(); ffi::gst_event_parse_group_id(self.as_mut_ptr(), group_id.as_mut_ptr()); let group_id = group_id.assume_init(); if group_id == 0 { None } else { Some(GroupId(NonZeroU32::new_unchecked(group_id))) } } } #[doc(alias = "gst_event_set_group_id")] pub fn set_group_id(&mut self, group_id: GroupId) { unsafe { ffi::gst_event_set_group_id(self.as_mut_ptr(), group_id.0.get()); } } #[doc(alias = "get_stream")] #[doc(alias = "gst_event_parse_stream")] pub fn stream(&self) -> Option { unsafe { let mut stream = ptr::null_mut(); ffi::gst_event_parse_stream(self.as_mut_ptr(), &mut stream); from_glib_full(stream) } } } impl std::fmt::Debug for StreamStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StreamStart") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("stream-id", &self.stream_id()) .field("stream-flags", &self.stream_flags()) .field("group-id", &self.group_id()) .field("stream", &self.stream()) .finish() } } impl std::fmt::Debug for StreamStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StreamStart::::fmt(self, f) } } declare_concrete_event!(@sticky Caps, T); impl Caps { #[doc(alias = "gst_event_new_caps")] #[allow(clippy::new_ret_no_self)] pub fn new(caps: &crate::Caps) -> Event { skip_assert_initialized!(); Self::builder(caps).build() } pub fn builder(caps: &crate::Caps) -> CapsBuilder { assert_initialized_main_thread!(); CapsBuilder::new(caps) } } impl Caps { #[doc(alias = "get_caps")] #[doc(alias = "gst_event_parse_caps")] pub fn caps(&self) -> &crate::CapsRef { unsafe { let mut caps = ptr::null_mut(); ffi::gst_event_parse_caps(self.as_mut_ptr(), &mut caps); crate::CapsRef::from_ptr(caps) } } #[doc(alias = "get_caps_owned")] #[doc(alias = "gst_event_parse_caps")] pub fn caps_owned(&self) -> crate::Caps { unsafe { from_glib_none(self.caps().as_ptr()) } } } impl std::fmt::Debug for Caps { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Caps") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("caps", &self.caps()) .finish() } } impl std::fmt::Debug for Caps { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Caps::::fmt(self, f) } } declare_concrete_event!(@sticky Segment, T); impl Segment { #[doc(alias = "gst_event_new_segment")] #[allow(clippy::new_ret_no_self)] pub fn new(segment: &crate::FormattedSegment) -> Event { skip_assert_initialized!(); Self::builder(segment).build() } pub fn builder( segment: &crate::FormattedSegment, ) -> SegmentBuilder { assert_initialized_main_thread!(); SegmentBuilder::new(segment.as_ref()) } } impl Segment { #[doc(alias = "get_segment")] #[doc(alias = "gst_event_parse_segment")] pub fn segment(&self) -> &crate::Segment { unsafe { let mut segment = ptr::null(); ffi::gst_event_parse_segment(self.as_mut_ptr(), &mut segment); &*(segment as *mut ffi::GstSegment as *mut crate::Segment) } } } impl std::fmt::Debug for Segment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Segment") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("segment", &self.segment()) .finish() } } impl std::fmt::Debug for Segment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Segment::::fmt(self, f) } } declare_concrete_event!(@sticky StreamCollection, T); impl StreamCollection { #[doc(alias = "gst_event_new_stream_collection")] #[allow(clippy::new_ret_no_self)] pub fn new(stream_collection: &crate::StreamCollection) -> Event { skip_assert_initialized!(); Self::builder(stream_collection).build() } pub fn builder(stream_collection: &crate::StreamCollection) -> StreamCollectionBuilder { assert_initialized_main_thread!(); StreamCollectionBuilder::new(stream_collection) } } impl StreamCollection { #[doc(alias = "get_stream_collection")] #[doc(alias = "gst_event_parse_stream_collection")] pub fn stream_collection(&self) -> crate::StreamCollection { unsafe { let mut stream_collection = ptr::null_mut(); ffi::gst_event_parse_stream_collection(self.as_mut_ptr(), &mut stream_collection); from_glib_full(stream_collection) } } } impl std::fmt::Debug for StreamCollection { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StreamCollection") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("stream-collection", &self.stream_collection()) .finish() } } impl std::fmt::Debug for StreamCollection { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StreamCollection::::fmt(self, f) } } declare_concrete_event!(@sticky Tag, T); impl Tag { #[doc(alias = "gst_event_new_tag")] #[allow(clippy::new_ret_no_self)] pub fn new(tags: crate::TagList) -> Event { skip_assert_initialized!(); Self::builder(tags).build() } pub fn builder<'a>(tags: crate::TagList) -> TagBuilder<'a> { assert_initialized_main_thread!(); TagBuilder::new(tags) } } impl Tag { #[doc(alias = "get_tag")] #[doc(alias = "gst_event_parse_tag")] pub fn tag(&self) -> &crate::TagListRef { unsafe { let mut tags = ptr::null_mut(); ffi::gst_event_parse_tag(self.as_mut_ptr(), &mut tags); crate::TagListRef::from_ptr(tags) } } #[doc(alias = "get_tag_owned")] #[doc(alias = "gst_event_parse_tag")] pub fn tag_owned(&self) -> crate::TagList { unsafe { from_glib_none(self.tag().as_ptr()) } } } impl std::fmt::Debug for Tag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Tag") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("tag", &self.tag()) .finish() } } impl std::fmt::Debug for Tag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Tag::::fmt(self, f) } } declare_concrete_event!(@sticky Buffersize, T); impl Buffersize { #[doc(alias = "gst_event_new_buffer_size")] #[allow(clippy::new_ret_no_self)] pub fn new( minsize: V, maxsize: impl CompatibleFormattedValue, r#async: bool, ) -> Event { skip_assert_initialized!(); Self::builder(minsize, maxsize, r#async).build() } pub fn builder<'a, V: FormattedValue>( minsize: V, maxsize: impl CompatibleFormattedValue, r#async: bool, ) -> BuffersizeBuilder<'a> { assert_initialized_main_thread!(); let maxsize = maxsize.try_into_checked(minsize).unwrap(); BuffersizeBuilder::new(minsize.into(), maxsize.into(), r#async) } } impl Buffersize { #[doc(alias = "gst_event_parse_buffer_size")] pub fn get(&self) -> (GenericFormattedValue, GenericFormattedValue, bool) { unsafe { let mut fmt = mem::MaybeUninit::uninit(); let mut minsize = mem::MaybeUninit::uninit(); let mut maxsize = mem::MaybeUninit::uninit(); let mut async_ = mem::MaybeUninit::uninit(); ffi::gst_event_parse_buffer_size( self.as_mut_ptr(), fmt.as_mut_ptr(), minsize.as_mut_ptr(), maxsize.as_mut_ptr(), async_.as_mut_ptr(), ); ( GenericFormattedValue::new(from_glib(fmt.assume_init()), minsize.assume_init()), GenericFormattedValue::new(from_glib(fmt.assume_init()), maxsize.assume_init()), from_glib(async_.assume_init()), ) } } } impl std::fmt::Debug for Buffersize { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (minsize, maxsize, async_) = self.get(); f.debug_struct("Buffersize") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("min-size", &minsize) .field("max-size", &maxsize) .field("async", &async_) .finish() } } impl std::fmt::Debug for Buffersize { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Buffersize::::fmt(self, f) } } declare_concrete_event!(@sticky SinkMessage, T); impl SinkMessage { #[doc(alias = "gst_event_new_sink_message")] #[allow(clippy::new_ret_no_self)] pub fn new(name: &str, msg: &crate::Message) -> Event { skip_assert_initialized!(); Self::builder(name, msg).build() } pub fn builder<'a>(name: &'a str, msg: &'a crate::Message) -> SinkMessageBuilder<'a> { assert_initialized_main_thread!(); SinkMessageBuilder::new(name, msg) } } impl SinkMessage { #[doc(alias = "get_message")] #[doc(alias = "gst_event_parse_sink_message")] pub fn message(&self) -> crate::Message { unsafe { let mut msg = ptr::null_mut(); ffi::gst_event_parse_sink_message(self.as_mut_ptr(), &mut msg); from_glib_full(msg) } } } impl std::fmt::Debug for SinkMessage { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SinkMessage") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("message", &self.message()) .finish() } } impl std::fmt::Debug for SinkMessage { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { SinkMessage::::fmt(self, f) } } declare_concrete_event!(@sticky StreamGroupDone, T); impl StreamGroupDone { #[doc(alias = "gst_event_new_stream_group_done")] #[allow(clippy::new_ret_no_self)] pub fn new(group_id: GroupId) -> Event { skip_assert_initialized!(); Self::builder(group_id).build() } pub fn builder<'a>(group_id: GroupId) -> StreamGroupDoneBuilder<'a> { assert_initialized_main_thread!(); StreamGroupDoneBuilder::new(group_id) } } impl StreamGroupDone { #[doc(alias = "get_group_id")] #[doc(alias = "gst_event_parse_stream_group_done")] pub fn group_id(&self) -> GroupId { unsafe { let mut group_id = mem::MaybeUninit::uninit(); ffi::gst_event_parse_stream_group_done(self.as_mut_ptr(), group_id.as_mut_ptr()); let group_id = group_id.assume_init(); debug_assert_ne!(group_id, 0); GroupId(NonZeroU32::new_unchecked(group_id)) } } } impl std::fmt::Debug for StreamGroupDone { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StreamGroupDone") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("group-id", &self.group_id()) .finish() } } impl std::fmt::Debug for StreamGroupDone { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StreamGroupDone::::fmt(self, f) } } declare_concrete_event!(@sticky Eos, T); impl Eos { #[doc(alias = "gst_event_new_eos")] #[allow(clippy::new_ret_no_self)] pub fn new() -> Event { skip_assert_initialized!(); Self::builder().build() } pub fn builder<'a>() -> EosBuilder<'a> { assert_initialized_main_thread!(); EosBuilder::new() } } impl std::fmt::Debug for Eos { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Eos") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .finish() } } impl std::fmt::Debug for Eos { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Eos::::fmt(self, f) } } declare_concrete_event!(@sticky Toc, T); impl Toc { // FIXME could use false for updated as default // Even better: use an enum for updated so that it is more explicit than true / false #[doc(alias = "gst_event_new_toc")] #[allow(clippy::new_ret_no_self)] pub fn new(toc: &crate::Toc, updated: bool) -> Event { skip_assert_initialized!(); Self::builder(toc, updated).build() } pub fn builder(toc: &crate::Toc, updated: bool) -> TocBuilder { assert_initialized_main_thread!(); TocBuilder::new(toc, updated) } } impl Toc { #[doc(alias = "get_toc")] #[doc(alias = "gst_event_parse_toc")] pub fn toc(&self) -> (&crate::TocRef, bool) { unsafe { let mut toc = ptr::null_mut(); let mut updated = mem::MaybeUninit::uninit(); ffi::gst_event_parse_toc(self.as_mut_ptr(), &mut toc, updated.as_mut_ptr()); ( crate::TocRef::from_ptr(toc), from_glib(updated.assume_init()), ) } } #[doc(alias = "get_toc_owned")] #[doc(alias = "gst_event_parse_toc")] pub fn toc_owned(&self) -> (crate::Toc, bool) { unsafe { let (toc, updated) = self.toc(); (from_glib_none(toc.as_ptr()), updated) } } } impl std::fmt::Debug for Toc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Toc") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("toc", &self.toc()) .finish() } } impl std::fmt::Debug for Toc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Toc::::fmt(self, f) } } declare_concrete_event!(@sticky Protection, T); impl Protection { #[doc(alias = "gst_event_new_protection")] #[allow(clippy::new_ret_no_self)] pub fn new(system_id: &str, data: &crate::Buffer) -> Event { skip_assert_initialized!(); Self::builder(system_id, data).build() } pub fn builder<'a>(system_id: &'a str, data: &'a crate::Buffer) -> ProtectionBuilder<'a> { assert_initialized_main_thread!(); ProtectionBuilder::new(system_id, data) } } impl Protection { #[doc(alias = "gst_event_parse_protection")] pub fn get(&self) -> (&str, &crate::BufferRef, Option<&str>) { unsafe { let mut system_id = ptr::null(); let mut buffer = ptr::null_mut(); let mut origin = ptr::null(); ffi::gst_event_parse_protection( self.as_mut_ptr(), &mut system_id, &mut buffer, &mut origin, ); ( CStr::from_ptr(system_id).to_str().unwrap(), crate::BufferRef::from_ptr(buffer), if origin.is_null() { None } else { Some(CStr::from_ptr(origin).to_str().unwrap()) }, ) } } #[doc(alias = "gst_event_parse_protection")] pub fn get_owned(&self) -> (&str, crate::Buffer, Option<&str>) { unsafe { let (system_id, buffer, origin) = self.get(); (system_id, from_glib_none(buffer.as_ptr()), origin) } } } impl std::fmt::Debug for Protection { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (system_id, buffer, origin) = self.get(); f.debug_struct("Protection") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("system-id", &system_id) .field("buffer", &buffer) .field("origin", &origin) .finish() } } impl std::fmt::Debug for Protection { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Protection::::fmt(self, f) } } declare_concrete_event!(SegmentDone, T); impl SegmentDone { #[doc(alias = "gst_event_new_segment_done")] #[allow(clippy::new_ret_no_self)] pub fn new(position: impl FormattedValue) -> Event { skip_assert_initialized!(); Self::builder(position).build() } pub fn builder<'a>(position: impl FormattedValue) -> SegmentDoneBuilder<'a> { assert_initialized_main_thread!(); SegmentDoneBuilder::new(position.into()) } } impl SegmentDone { #[doc(alias = "gst_event_parse_segment_done")] pub fn get(&self) -> GenericFormattedValue { unsafe { let mut fmt = mem::MaybeUninit::uninit(); let mut position = mem::MaybeUninit::uninit(); ffi::gst_event_parse_segment_done( self.as_mut_ptr(), fmt.as_mut_ptr(), position.as_mut_ptr(), ); GenericFormattedValue::new(from_glib(fmt.assume_init()), position.assume_init()) } } } impl std::fmt::Debug for SegmentDone { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SegmentDone") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("segment", &self.get()) .finish() } } impl std::fmt::Debug for SegmentDone { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { SegmentDone::::fmt(self, f) } } declare_concrete_event!(Gap, T); impl Gap { #[doc(alias = "gst_event_new_gap")] #[allow(clippy::new_ret_no_self)] pub fn new(timestamp: ClockTime, duration: impl Into>) -> Event { skip_assert_initialized!(); Self::builder(timestamp).duration(duration).build() } pub fn builder<'a>(timestamp: ClockTime) -> GapBuilder<'a> { assert_initialized_main_thread!(); GapBuilder::new(timestamp) } } impl Gap { #[doc(alias = "gst_event_parse_gap")] pub fn get(&self) -> (ClockTime, Option) { unsafe { let mut timestamp = mem::MaybeUninit::uninit(); let mut duration = mem::MaybeUninit::uninit(); ffi::gst_event_parse_gap( self.as_mut_ptr(), timestamp.as_mut_ptr(), duration.as_mut_ptr(), ); ( try_from_glib(timestamp.assume_init()).expect("undefined timestamp"), from_glib(duration.assume_init()), ) } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[doc(alias = "gst_event_parse_gap_flags")] pub fn gap_flags(&self) -> crate::GapFlags { unsafe { let mut flags = mem::MaybeUninit::uninit(); ffi::gst_event_parse_gap_flags(self.as_mut_ptr(), flags.as_mut_ptr()); from_glib(flags.assume_init()) } } } impl std::fmt::Debug for Gap { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (timestamp, duration) = self.get(); let mut f = f.debug_struct("Gap"); f.field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("timestamp", ×tamp) .field("duration", &duration); #[cfg(feature = "v1_20")] f.field("flags", &self.gap_flags()); f.finish() } } impl std::fmt::Debug for Gap { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Gap::::fmt(self, f) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] declare_concrete_event!(@sticky InstantRateChange, T); #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl InstantRateChange { #[doc(alias = "gst_event_new_instant_rate_change")] #[allow(clippy::new_ret_no_self)] pub fn new(multiplier: f64, new_flags: crate::SegmentFlags) -> Event { skip_assert_initialized!(); Self::builder(multiplier, new_flags).build() } pub fn builder<'a>( multiplier: f64, new_flags: crate::SegmentFlags, ) -> InstantRateChangeBuilder<'a> { assert_initialized_main_thread!(); InstantRateChangeBuilder::new(multiplier, new_flags) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl InstantRateChange { #[doc(alias = "gst_event_parse_instant_rate_change")] pub fn get(&self) -> (f64, crate::SegmentFlags) { unsafe { let mut multiplier = mem::MaybeUninit::uninit(); let mut new_flags = mem::MaybeUninit::uninit(); ffi::gst_event_parse_instant_rate_change( self.as_mut_ptr(), multiplier.as_mut_ptr(), new_flags.as_mut_ptr(), ); (multiplier.assume_init(), from_glib(new_flags.assume_init())) } } } #[cfg(feature = "v1_18")] impl std::fmt::Debug for InstantRateChange { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (multiplier, new_flags) = self.get(); f.debug_struct("InstantRateChange") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("multiplier", &multiplier) .field("new-flags", &new_flags) .finish() } } #[cfg(feature = "v1_18")] impl std::fmt::Debug for InstantRateChange { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { InstantRateChange::::fmt(self, f) } } declare_concrete_event!(Qos, T); impl Qos { #[doc(alias = "gst_event_new_qos")] #[allow(clippy::new_ret_no_self)] pub fn new( type_: crate::QOSType, proportion: f64, diff: i64, timestamp: impl Into>, ) -> Event { skip_assert_initialized!(); Self::builder(type_, proportion, diff) .timestamp(timestamp) .build() } pub fn builder<'a>(type_: crate::QOSType, proportion: f64, diff: i64) -> QosBuilder<'a> { assert_initialized_main_thread!(); QosBuilder::new(type_, proportion, diff) } } impl Qos { #[doc(alias = "gst_event_parse_qos")] pub fn get(&self) -> (crate::QOSType, f64, i64, Option) { unsafe { let mut type_ = mem::MaybeUninit::uninit(); let mut proportion = mem::MaybeUninit::uninit(); let mut diff = mem::MaybeUninit::uninit(); let mut timestamp = mem::MaybeUninit::uninit(); ffi::gst_event_parse_qos( self.as_mut_ptr(), type_.as_mut_ptr(), proportion.as_mut_ptr(), diff.as_mut_ptr(), timestamp.as_mut_ptr(), ); ( from_glib(type_.assume_init()), proportion.assume_init(), diff.assume_init(), from_glib(timestamp.assume_init()), ) } } } impl std::fmt::Debug for Qos { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (type_, proportion, diff, timestamp) = self.get(); f.debug_struct("Qos") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("type", &type_) .field("proportion", &proportion) .field("diff", &diff) .field("timestamp", ×tamp) .finish() } } impl std::fmt::Debug for Qos { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Qos::::fmt(self, f) } } declare_concrete_event!(Seek, T); impl Seek { #[doc(alias = "gst_event_new_seek")] #[allow(clippy::new_ret_no_self)] pub fn new( rate: f64, flags: crate::SeekFlags, start_type: crate::SeekType, start: V, stop_type: crate::SeekType, stop: impl CompatibleFormattedValue, ) -> Event { skip_assert_initialized!(); Self::builder(rate, flags, start_type, start, stop_type, stop).build() } pub fn builder<'a, V: FormattedValue>( rate: f64, flags: crate::SeekFlags, start_type: crate::SeekType, start: V, stop_type: crate::SeekType, stop: impl CompatibleFormattedValue, ) -> SeekBuilder<'a> { assert_initialized_main_thread!(); let stop = stop.try_into_checked(start).unwrap(); SeekBuilder::new( rate, flags, start_type, start.into(), stop_type, stop.into(), ) } } impl Seek { #[doc(alias = "gst_event_parse_seek")] pub fn get( &self, ) -> ( f64, crate::SeekFlags, crate::SeekType, GenericFormattedValue, crate::SeekType, GenericFormattedValue, ) { unsafe { let mut rate = mem::MaybeUninit::uninit(); let mut fmt = mem::MaybeUninit::uninit(); let mut flags = mem::MaybeUninit::uninit(); let mut start_type = mem::MaybeUninit::uninit(); let mut start = mem::MaybeUninit::uninit(); let mut stop_type = mem::MaybeUninit::uninit(); let mut stop = mem::MaybeUninit::uninit(); ffi::gst_event_parse_seek( self.as_mut_ptr(), rate.as_mut_ptr(), fmt.as_mut_ptr(), flags.as_mut_ptr(), start_type.as_mut_ptr(), start.as_mut_ptr(), stop_type.as_mut_ptr(), stop.as_mut_ptr(), ); ( rate.assume_init(), from_glib(flags.assume_init()), from_glib(start_type.assume_init()), GenericFormattedValue::new(from_glib(fmt.assume_init()), start.assume_init()), from_glib(stop_type.assume_init()), GenericFormattedValue::new(from_glib(fmt.assume_init()), stop.assume_init()), ) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "get_trickmode_interval")] #[doc(alias = "gst_event_parse_seek_trickmode_interval")] pub fn trickmode_interval(&self) -> Option { unsafe { let mut trickmode_interval = mem::MaybeUninit::uninit(); ffi::gst_event_parse_seek_trickmode_interval( self.as_mut_ptr(), trickmode_interval.as_mut_ptr(), ); from_glib(trickmode_interval.assume_init()) } } } impl std::fmt::Debug for Seek { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (rate, flags, start_type, start, stop_type, stop) = self.get(); f.debug_struct("Seek") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("rate", &rate) .field("flags", &flags) .field("start-type", &start_type) .field("start", &start) .field("stop-type", &stop_type) .field("stop", &stop) .finish() } } impl std::fmt::Debug for Seek { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Seek::::fmt(self, f) } } declare_concrete_event!(Navigation, T); impl Navigation { #[doc(alias = "gst_event_new_navigation")] #[allow(clippy::new_ret_no_self)] pub fn new(structure: crate::Structure) -> Event { skip_assert_initialized!(); Self::builder(structure).build() } pub fn builder<'a>(structure: crate::Structure) -> NavigationBuilder<'a> { assert_initialized_main_thread!(); NavigationBuilder::new(structure) } } impl std::fmt::Debug for Navigation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Navigation") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .finish() } } impl std::fmt::Debug for Navigation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Navigation::::fmt(self, f) } } declare_concrete_event!(Latency, T); impl Latency { #[doc(alias = "gst_event_new_latency")] #[allow(clippy::new_ret_no_self)] pub fn new(latency: ClockTime) -> Event { skip_assert_initialized!(); Self::builder(latency).build() } pub fn builder<'a>(latency: ClockTime) -> LatencyBuilder<'a> { assert_initialized_main_thread!(); LatencyBuilder::new(latency) } } impl Latency { #[doc(alias = "get_latency")] #[doc(alias = "gst_event_parse_latency")] pub fn latency(&self) -> ClockTime { unsafe { let mut latency = mem::MaybeUninit::uninit(); ffi::gst_event_parse_latency(self.as_mut_ptr(), latency.as_mut_ptr()); try_from_glib(latency.assume_init()).expect("undefined latency") } } } impl std::fmt::Debug for Latency { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Latency") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("latency", &self.latency()) .finish() } } impl std::fmt::Debug for Latency { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Latency::::fmt(self, f) } } declare_concrete_event!(Step, T); impl Step { #[doc(alias = "gst_event_new_step")] #[allow(clippy::new_ret_no_self)] pub fn new(amount: impl FormattedValue, rate: f64, flush: bool, intermediate: bool) -> Event { skip_assert_initialized!(); Self::builder(amount, rate, flush, intermediate).build() } pub fn builder<'a>( amount: impl FormattedValue, rate: f64, flush: bool, intermediate: bool, ) -> StepBuilder<'a> { assert_initialized_main_thread!(); StepBuilder::new(amount.into(), rate, flush, intermediate) } } impl Step { #[doc(alias = "gst_event_parse_step")] pub fn get(&self) -> (GenericFormattedValue, f64, bool, bool) { unsafe { let mut fmt = mem::MaybeUninit::uninit(); let mut amount = mem::MaybeUninit::uninit(); let mut rate = mem::MaybeUninit::uninit(); let mut flush = mem::MaybeUninit::uninit(); let mut intermediate = mem::MaybeUninit::uninit(); ffi::gst_event_parse_step( self.as_mut_ptr(), fmt.as_mut_ptr(), amount.as_mut_ptr(), rate.as_mut_ptr(), flush.as_mut_ptr(), intermediate.as_mut_ptr(), ); ( GenericFormattedValue::new( from_glib(fmt.assume_init()), amount.assume_init() as i64, ), rate.assume_init(), from_glib(flush.assume_init()), from_glib(intermediate.assume_init()), ) } } } impl std::fmt::Debug for Step { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (amount, rate, flush, intermediate) = self.get(); f.debug_struct("Step") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("amount", &amount) .field("rate", &rate) .field("flush", &flush) .field("intermediate", &intermediate) .finish() } } impl std::fmt::Debug for Step { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Step::::fmt(self, f) } } declare_concrete_event!(Reconfigure, T); impl Reconfigure { #[doc(alias = "gst_event_new_reconfigure")] #[allow(clippy::new_ret_no_self)] pub fn new() -> Event { skip_assert_initialized!(); Self::builder().build() } pub fn builder<'a>() -> ReconfigureBuilder<'a> { assert_initialized_main_thread!(); ReconfigureBuilder::new() } } impl std::fmt::Debug for Reconfigure { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Reconfigure") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .finish() } } impl std::fmt::Debug for Reconfigure { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Reconfigure::::fmt(self, f) } } declare_concrete_event!(TocSelect, T); impl TocSelect { #[doc(alias = "gst_event_new_toc_select")] #[allow(clippy::new_ret_no_self)] pub fn new(uid: &str) -> Event { skip_assert_initialized!(); Self::builder(uid).build() } pub fn builder(uid: &str) -> TocSelectBuilder { assert_initialized_main_thread!(); TocSelectBuilder::new(uid) } } impl TocSelect { #[doc(alias = "get_uid")] pub fn uid(&self) -> &str { unsafe { let mut uid = ptr::null_mut(); ffi::gst_event_parse_toc_select(self.as_mut_ptr(), &mut uid); CStr::from_ptr(uid).to_str().unwrap() } } } impl std::fmt::Debug for TocSelect { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TocSelect") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("uid", &self.uid()) .finish() } } impl std::fmt::Debug for TocSelect { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { TocSelect::::fmt(self, f) } } declare_concrete_event!(SelectStreams, T); impl SelectStreams { #[doc(alias = "gst_event_new_select_streams")] #[allow(clippy::new_ret_no_self)] pub fn new(streams: &[&str]) -> Event { skip_assert_initialized!(); Self::builder(streams).build() } pub fn builder<'a>(streams: &'a [&'a str]) -> SelectStreamsBuilder<'a> { assert_initialized_main_thread!(); SelectStreamsBuilder::new(streams) } } impl SelectStreams { #[doc(alias = "get_streams")] #[doc(alias = "gst_event_parse_select_streams")] pub fn streams(&self) -> Vec { unsafe { let mut streams = ptr::null_mut(); ffi::gst_event_parse_select_streams(self.as_mut_ptr(), &mut streams); FromGlibPtrContainer::from_glib_full(streams) } } } impl std::fmt::Debug for SelectStreams { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SelectStreams") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("streams", &self.streams()) .finish() } } impl std::fmt::Debug for SelectStreams { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { SelectStreams::::fmt(self, f) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] declare_concrete_event!(InstantRateSyncTime, T); #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl InstantRateSyncTime { #[doc(alias = "gst_event_new_instant_rate_sync_time")] #[allow(clippy::new_ret_no_self)] pub fn new( rate_multiplier: f64, running_time: ClockTime, upstream_running_time: ClockTime, ) -> Event { skip_assert_initialized!(); Self::builder(rate_multiplier, running_time, upstream_running_time).build() } pub fn builder<'a>( rate_multiplier: f64, running_time: ClockTime, upstream_running_time: ClockTime, ) -> InstantRateSyncTimeBuilder<'a> { assert_initialized_main_thread!(); InstantRateSyncTimeBuilder::new(rate_multiplier, running_time, upstream_running_time) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl InstantRateSyncTime { #[doc(alias = "parse_instant_rate_sync_time")] #[doc(alias = "gst_event_parse_instant_rate_sync_time")] pub fn get(&self) -> (f64, ClockTime, ClockTime) { unsafe { let mut rate_multiplier = mem::MaybeUninit::uninit(); let mut running_time = mem::MaybeUninit::uninit(); let mut upstream_running_time = mem::MaybeUninit::uninit(); ffi::gst_event_parse_instant_rate_sync_time( self.as_mut_ptr(), rate_multiplier.as_mut_ptr(), running_time.as_mut_ptr(), upstream_running_time.as_mut_ptr(), ); ( rate_multiplier.assume_init(), try_from_glib(running_time.assume_init()).expect("undefined timestamp"), try_from_glib(upstream_running_time.assume_init()).expect("undefined timestamp"), ) } } } #[cfg(feature = "v1_18")] impl std::fmt::Debug for InstantRateSyncTime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (rate_multiplier, running_time, upstream_running_time) = self.get(); f.debug_struct("InstantRateSyncTime") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .field("rate-multiplier", &rate_multiplier) .field("running-time", &running_time) .field("upstream-running-time", &upstream_running_time) .finish() } } #[cfg(feature = "v1_18")] impl std::fmt::Debug for InstantRateSyncTime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { InstantRateSyncTime::::fmt(self, f) } } declare_concrete_event!(CustomUpstream, T); impl CustomUpstream { #[doc(alias = "gst_event_new_custom")] #[allow(clippy::new_ret_no_self)] pub fn new(structure: crate::Structure) -> Event { skip_assert_initialized!(); Self::builder(structure).build() } pub fn builder<'a>(structure: crate::Structure) -> CustomUpstreamBuilder<'a> { assert_initialized_main_thread!(); CustomUpstreamBuilder::new(structure) } } impl std::fmt::Debug for CustomUpstream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CustomUpstream") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .finish() } } impl std::fmt::Debug for CustomUpstream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { CustomUpstream::::fmt(self, f) } } declare_concrete_event!(CustomDownstream, T); impl CustomDownstream { #[doc(alias = "gst_event_new_custom")] #[allow(clippy::new_ret_no_self)] pub fn new(structure: crate::Structure) -> Event { skip_assert_initialized!(); Self::builder(structure).build() } pub fn builder<'a>(structure: crate::Structure) -> CustomDownstreamBuilder<'a> { assert_initialized_main_thread!(); CustomDownstreamBuilder::new(structure) } } impl std::fmt::Debug for CustomDownstream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CustomDownstream") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .finish() } } impl std::fmt::Debug for CustomDownstream { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { CustomDownstream::::fmt(self, f) } } declare_concrete_event!(CustomDownstreamOob, T); impl CustomDownstreamOob { #[doc(alias = "gst_event_new_custom")] #[allow(clippy::new_ret_no_self)] pub fn new(structure: crate::Structure) -> Event { skip_assert_initialized!(); Self::builder(structure).build() } pub fn builder<'a>(structure: crate::Structure) -> CustomDownstreamOobBuilder<'a> { assert_initialized_main_thread!(); CustomDownstreamOobBuilder::new(structure) } } impl std::fmt::Debug for CustomDownstreamOob { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CustomDownstreamOob") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .finish() } } impl std::fmt::Debug for CustomDownstreamOob { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { CustomDownstreamOob::::fmt(self, f) } } declare_concrete_event!(@sticky CustomDownstreamSticky, T); impl CustomDownstreamSticky { #[doc(alias = "gst_event_new_custom")] #[allow(clippy::new_ret_no_self)] pub fn new(structure: crate::Structure) -> Event { skip_assert_initialized!(); Self::builder(structure).build() } pub fn builder<'a>(structure: crate::Structure) -> CustomDownstreamStickyBuilder<'a> { assert_initialized_main_thread!(); CustomDownstreamStickyBuilder::new(structure) } } impl std::fmt::Debug for CustomDownstreamSticky { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CustomDownstreamSticky") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .finish() } } impl std::fmt::Debug for CustomDownstreamSticky { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { CustomDownstreamSticky::::fmt(self, f) } } declare_concrete_event!(CustomBoth, T); impl CustomBoth { #[doc(alias = "gst_event_new_custom")] #[allow(clippy::new_ret_no_self)] pub fn new(structure: crate::Structure) -> Event { skip_assert_initialized!(); Self::builder(structure).build() } pub fn builder<'a>(structure: crate::Structure) -> CustomBothBuilder<'a> { assert_initialized_main_thread!(); CustomBothBuilder::new(structure) } } impl std::fmt::Debug for CustomBoth { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CustomBoth") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .finish() } } impl std::fmt::Debug for CustomBoth { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { CustomBoth::::fmt(self, f) } } declare_concrete_event!(CustomBothOob, T); impl CustomBothOob { #[doc(alias = "gst_event_new_custom")] #[allow(clippy::new_ret_no_self)] pub fn new(structure: crate::Structure) -> Event { skip_assert_initialized!(); Self::builder(structure).build() } pub fn builder<'a>(structure: crate::Structure) -> CustomBothOobBuilder<'a> { assert_initialized_main_thread!(); CustomBothOobBuilder::new(structure) } } impl std::fmt::Debug for CustomBothOob { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CustomBothOob") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .finish() } } impl std::fmt::Debug for CustomBothOob { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { CustomBothOob::::fmt(self, f) } } declare_concrete_event!(Other, T); impl std::fmt::Debug for Other { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Other") .field("seqnum", &self.event().seqnum()) .field("running-time-offset", &self.event().running_time_offset()) .field("structure", &self.event().structure()) .finish() } } impl std::fmt::Debug for Other { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Other::::fmt(self, f) } } struct EventBuilder<'a> { seqnum: Option, running_time_offset: Option, other_fields: Vec<(&'a str, glib::SendValue)>, } impl<'a> EventBuilder<'a> { fn new() -> Self { Self { seqnum: None, running_time_offset: None, other_fields: Vec::new(), } } fn seqnum(self, seqnum: Seqnum) -> Self { Self { seqnum: Some(seqnum), ..self } } fn running_time_offset(self, running_time_offset: i64) -> Self { Self { running_time_offset: Some(running_time_offset), ..self } } fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self { let mut other_fields = self.other_fields; other_fields.push((name, value.to_send_value())); Self { other_fields, ..self } } fn other_fields(self, other_fields: &[(&'a str, &'a (dyn ToSendValue + Sync))]) -> Self { let mut s = self; for (name, value) in other_fields { s = s.other_field(name, value.to_send_value()); } s } } macro_rules! event_builder_generic_impl { ($new_fn:expr) => { #[doc(alias = "gst_event_set_seqnum")] #[allow(clippy::needless_update)] pub fn seqnum(self, seqnum: Seqnum) -> Self { Self { builder: self.builder.seqnum(seqnum), ..self } } #[doc(alias = "gst_event_set_seqnum")] #[allow(clippy::needless_update)] pub fn seqnum_if(self, seqnum: Seqnum, predicate: bool) -> Self { if predicate { self.seqnum(seqnum) } else { self } } #[doc(alias = "gst_event_set_seqnum")] #[allow(clippy::needless_update)] pub fn seqnum_if_some(self, seqnum: Option) -> Self { if let Some(seqnum) = seqnum { self.seqnum(seqnum) } else { self } } #[doc(alias = "gst_event_set_running_time_offset")] #[allow(clippy::needless_update)] pub fn running_time_offset(self, running_time_offset: i64) -> Self { Self { builder: self.builder.running_time_offset(running_time_offset), ..self } } #[doc(alias = "gst_event_set_running_time_offset")] #[allow(clippy::needless_update)] pub fn running_time_offset_if(self, running_time_offset: i64, predicate: bool) -> Self { if predicate { self.running_time_offset(running_time_offset) } else { self } } #[doc(alias = "gst_event_set_running_time_offset")] #[allow(clippy::needless_update)] pub fn running_time_offset_if_some(self, running_time_offset: Option) -> Self { if let Some(running_time_offset) = running_time_offset { self.running_time_offset(running_time_offset) } else { self } } // rustdoc-stripper-ignore-next /// Sets field `name` to the given value `value`. /// /// Overrides any default or previously defined value for `name`. #[allow(clippy::needless_update)] pub fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self { Self { builder: self.builder.other_field(name, value), ..self } } impl_builder_gvalue_extra_setters!(other_field); #[deprecated = "use build.other_field() instead"] #[allow(clippy::needless_update)] pub fn other_fields( self, other_fields: &[(&'a str, &'a (dyn ToSendValue + Sync))], ) -> Self { Self { builder: self.builder.other_fields(other_fields), ..self } } #[must_use = "Building the event without using it has no effect"] #[allow(clippy::redundant_closure_call)] pub fn build(mut self) -> Event { unsafe { let event = $new_fn(&mut self); if let Some(seqnum) = self.builder.seqnum { ffi::gst_event_set_seqnum(event, seqnum.0.get()); } if let Some(running_time_offset) = self.builder.running_time_offset { ffi::gst_event_set_running_time_offset(event, running_time_offset); } if !self.builder.other_fields.is_empty() { let s = StructureRef::from_glib_borrow_mut(ffi::gst_event_writable_structure( event, )); for (k, v) in self.builder.other_fields { s.set_value(k, v); } } from_glib_full(event) } } }; } #[must_use = "The builder must be built to be used"] pub struct FlushStartBuilder<'a> { builder: EventBuilder<'a>, } impl<'a> FlushStartBuilder<'a> { fn new() -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), } } event_builder_generic_impl!(|_| { ffi::gst_event_new_flush_start() }); } #[must_use = "The builder must be built to be used"] pub struct FlushStopBuilder<'a> { builder: EventBuilder<'a>, reset_time: bool, } impl<'a> FlushStopBuilder<'a> { fn new(reset_time: bool) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), reset_time, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_flush_stop(s.reset_time.into_glib()) }); } #[must_use = "The builder must be built to be used"] pub struct StreamStartBuilder<'a> { builder: EventBuilder<'a>, stream_id: &'a str, flags: Option, group_id: Option, stream: Option, } impl<'a> StreamStartBuilder<'a> { fn new(stream_id: &'a str) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), stream_id, flags: None, group_id: None, stream: None, } } pub fn flags(self, flags: crate::StreamFlags) -> Self { Self { flags: Some(flags), ..self } } pub fn flags_if(self, flags: crate::StreamFlags, predicate: bool) -> Self { if predicate { self.flags(flags) } else { self } } pub fn flags_if_some(self, flags: Option) -> Self { if let Some(flags) = flags { self.flags(flags) } else { self } } pub fn group_id(self, group_id: GroupId) -> Self { Self { group_id: Some(group_id), ..self } } pub fn group_id_if(self, group_id: GroupId, predicate: bool) -> Self { if predicate { self.group_id(group_id) } else { self } } pub fn group_id_if_some(self, group_id: Option) -> Self { if let Some(group_id) = group_id { self.group_id(group_id) } else { self } } pub fn stream(self, stream: crate::Stream) -> Self { Self { stream: Some(stream), ..self } } pub fn stream_if(self, stream: crate::Stream, predicate: bool) -> Self { if predicate { self.stream(stream) } else { self } } pub fn stream_if_some(self, stream: Option) -> Self { if let Some(stream) = stream { self.stream(stream) } else { self } } event_builder_generic_impl!(|s: &Self| { let ev = ffi::gst_event_new_stream_start(s.stream_id.to_glib_none().0); if let Some(flags) = s.flags { ffi::gst_event_set_stream_flags(ev, flags.into_glib()); } if let Some(group_id) = s.group_id { ffi::gst_event_set_group_id(ev, group_id.0.get()); } if let Some(ref stream) = s.stream { ffi::gst_event_set_stream(ev, stream.to_glib_none().0); } ev }); } #[must_use = "The builder must be built to be used"] pub struct CapsBuilder<'a> { builder: EventBuilder<'a>, caps: &'a crate::Caps, } impl<'a> CapsBuilder<'a> { fn new(caps: &'a crate::Caps) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), caps, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_caps(s.caps.as_mut_ptr()) }); } #[must_use = "The builder must be built to be used"] pub struct SegmentBuilder<'a> { builder: EventBuilder<'a>, segment: &'a crate::Segment, } impl<'a> SegmentBuilder<'a> { fn new(segment: &'a crate::Segment) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), segment, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_segment(s.segment.to_glib_none().0) }); } #[must_use = "The builder must be built to be used"] pub struct StreamCollectionBuilder<'a> { builder: EventBuilder<'a>, stream_collection: &'a crate::StreamCollection, } impl<'a> StreamCollectionBuilder<'a> { fn new(stream_collection: &'a crate::StreamCollection) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), stream_collection, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_stream_collection(s.stream_collection.to_glib_none().0) }); } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[must_use = "The builder must be built to be used"] pub struct InstantRateSyncTimeBuilder<'a> { builder: EventBuilder<'a>, rate_multiplier: f64, running_time: ClockTime, upstream_running_time: ClockTime, } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl<'a> InstantRateSyncTimeBuilder<'a> { fn new( rate_multiplier: f64, running_time: ClockTime, upstream_running_time: ClockTime, ) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), rate_multiplier, running_time, upstream_running_time, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_instant_rate_sync_time( s.rate_multiplier, s.running_time.into_glib(), s.upstream_running_time.into_glib(), ) }); } #[must_use = "The builder must be built to be used"] pub struct TagBuilder<'a> { builder: EventBuilder<'a>, tags: Option, } impl<'a> TagBuilder<'a> { fn new(tags: crate::TagList) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), tags: Some(tags), } } event_builder_generic_impl!(|s: &mut Self| { let tags = s.tags.take().unwrap(); ffi::gst_event_new_tag(tags.into_glib_ptr()) }); } #[must_use = "The builder must be built to be used"] pub struct BuffersizeBuilder<'a> { builder: EventBuilder<'a>, minsize: GenericFormattedValue, maxsize: GenericFormattedValue, r#async: bool, } impl<'a> BuffersizeBuilder<'a> { fn new(minsize: GenericFormattedValue, maxsize: GenericFormattedValue, r#async: bool) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), minsize, maxsize, r#async, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_buffer_size( s.minsize.format().into_glib(), s.minsize.value(), s.maxsize.value(), s.r#async.into_glib(), ) }); } #[must_use = "The builder must be built to be used"] pub struct SinkMessageBuilder<'a> { builder: EventBuilder<'a>, name: &'a str, msg: &'a crate::Message, } impl<'a> SinkMessageBuilder<'a> { fn new(name: &'a str, msg: &'a crate::Message) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), name, msg, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_sink_message(s.name.to_glib_none().0, s.msg.as_mut_ptr()) }); } #[must_use = "The builder must be built to be used"] pub struct StreamGroupDoneBuilder<'a> { builder: EventBuilder<'a>, group_id: GroupId, } impl<'a> StreamGroupDoneBuilder<'a> { fn new(group_id: GroupId) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), group_id, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_stream_group_done(s.group_id.0.get()) }); } #[must_use = "The builder must be built to be used"] pub struct EosBuilder<'a> { builder: EventBuilder<'a>, } impl<'a> EosBuilder<'a> { fn new() -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), } } event_builder_generic_impl!(|_| ffi::gst_event_new_eos()); } #[must_use = "The builder must be built to be used"] pub struct TocBuilder<'a> { builder: EventBuilder<'a>, toc: &'a crate::Toc, updated: bool, } impl<'a> TocBuilder<'a> { fn new(toc: &'a crate::Toc, updated: bool) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), toc, updated, } } event_builder_generic_impl!(|s: &Self| ffi::gst_event_new_toc( s.toc.to_glib_none().0, s.updated.into_glib() )); } #[must_use = "The builder must be built to be used"] pub struct ProtectionBuilder<'a> { builder: EventBuilder<'a>, system_id: &'a str, data: &'a crate::Buffer, origin: Option<&'a str>, } impl<'a> ProtectionBuilder<'a> { fn new(system_id: &'a str, data: &'a crate::Buffer) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), system_id, data, origin: None, } } pub fn origin(self, origin: &'a str) -> Self { Self { origin: Some(origin), ..self } } pub fn origin_if(self, origin: &'a str, predicate: bool) -> Self { if predicate { self.origin(origin) } else { self } } pub fn origin_if_some(self, origin: Option<&'a str>) -> Self { if let Some(origin) = origin { self.origin(origin) } else { self } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_protection( s.system_id.to_glib_none().0, s.data.as_mut_ptr(), s.origin.to_glib_none().0, ) }); } #[must_use = "The builder must be built to be used"] pub struct SegmentDoneBuilder<'a> { builder: EventBuilder<'a>, position: GenericFormattedValue, } impl<'a> SegmentDoneBuilder<'a> { fn new(position: GenericFormattedValue) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), position, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_segment_done(s.position.format().into_glib(), s.position.value()) }); } #[must_use = "The builder must be built to be used"] pub struct GapBuilder<'a> { builder: EventBuilder<'a>, timestamp: ClockTime, duration: Option, #[cfg(feature = "v1_20")] gap_flags: Option, } impl<'a> GapBuilder<'a> { fn new(timestamp: ClockTime) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), timestamp, duration: None, #[cfg(feature = "v1_20")] gap_flags: None, } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] pub fn gap_flags(mut self, flags: crate::GapFlags) -> Self { self.gap_flags = Some(flags); self } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] pub fn gap_flags_if(self, flags: crate::GapFlags, predicate: bool) -> Self { if predicate { self.gap_flags(flags) } else { self } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] pub fn gap_flags_if_some(self, flags: Option) -> Self { if let Some(flags) = flags { self.gap_flags(flags) } else { self } } pub fn duration(mut self, duration: impl Into>) -> Self { self.duration = duration.into(); self } pub fn duration_if(self, duration: ClockTime, predicate: bool) -> Self { if predicate { self.duration(duration) } else { self } } pub fn duration_if_some(self, duration: Option) -> Self { if let Some(duration) = duration { self.duration(duration) } else { self } } event_builder_generic_impl!(|s: &Self| { #[allow(clippy::let_and_return)] let ev = ffi::gst_event_new_gap(s.timestamp.into_glib(), s.duration.into_glib()); #[cfg(feature = "v1_20")] if let Some(ref flags) = s.gap_flags { ffi::gst_event_set_gap_flags(ev, flags.into_glib()); } ev }); } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[must_use = "The builder must be built to be used"] pub struct InstantRateChangeBuilder<'a> { builder: EventBuilder<'a>, multiplier: f64, new_flags: crate::SegmentFlags, } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl<'a> InstantRateChangeBuilder<'a> { fn new(multiplier: f64, new_flags: crate::SegmentFlags) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), multiplier, new_flags, } } event_builder_generic_impl!(|s: &Self| ffi::gst_event_new_instant_rate_change( s.multiplier, s.new_flags.into_glib() )); } #[must_use = "The builder must be built to be used"] pub struct QosBuilder<'a> { builder: EventBuilder<'a>, type_: crate::QOSType, proportion: f64, diff: i64, timestamp: Option, } impl<'a> QosBuilder<'a> { fn new(type_: crate::QOSType, proportion: f64, diff: i64) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), type_, proportion, diff, timestamp: None, } } pub fn timestamp(mut self, timestamp: impl Into>) -> Self { self.timestamp = timestamp.into(); self } pub fn timestamp_if(self, timestamp: ClockTime, predicate: bool) -> Self { if predicate { self.timestamp(timestamp) } else { self } } pub fn timestamp_if_some(self, timestamp: Option) -> Self { if let Some(timestamp) = timestamp { self.timestamp(timestamp) } else { self } } event_builder_generic_impl!(|s: &Self| ffi::gst_event_new_qos( s.type_.into_glib(), s.proportion, s.diff, s.timestamp.into_glib(), )); } #[must_use = "The builder must be built to be used"] pub struct SeekBuilder<'a> { builder: EventBuilder<'a>, rate: f64, flags: crate::SeekFlags, start_type: crate::SeekType, start: GenericFormattedValue, stop_type: crate::SeekType, stop: GenericFormattedValue, #[allow(unused)] trickmode_interval: Option, } impl<'a> SeekBuilder<'a> { fn new( rate: f64, flags: crate::SeekFlags, start_type: crate::SeekType, start: GenericFormattedValue, stop_type: crate::SeekType, stop: GenericFormattedValue, ) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), rate, flags, start_type, start, stop_type, stop, trickmode_interval: None, } } pub fn trickmode_interval(mut self, trickmode_interval: impl Into>) -> Self { self.trickmode_interval = trickmode_interval.into(); self } event_builder_generic_impl!(|s: &Self| { #[allow(clippy::let_and_return)] { let ev = ffi::gst_event_new_seek( s.rate, s.start.format().into_glib(), s.flags.into_glib(), s.start_type.into_glib(), s.start.value(), s.stop_type.into_glib(), s.stop.value(), ); #[cfg(feature = "v1_16")] if let Some(trickmode_interval) = s.trickmode_interval { ffi::gst_event_set_seek_trickmode_interval(ev, trickmode_interval.into_glib()); } ev } }); } #[must_use = "The builder must be built to be used"] pub struct NavigationBuilder<'a> { builder: EventBuilder<'a>, structure: Option, } impl<'a> NavigationBuilder<'a> { fn new(structure: Structure) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), structure: Some(structure), } } event_builder_generic_impl!(|s: &mut Self| { let structure = s.structure.take().unwrap(); ffi::gst_event_new_navigation(structure.into_glib_ptr()) }); } #[must_use = "The builder must be built to be used"] pub struct LatencyBuilder<'a> { builder: EventBuilder<'a>, latency: ClockTime, } impl<'a> LatencyBuilder<'a> { fn new(latency: ClockTime) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), latency, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_latency(s.latency.into_glib()) }); } #[must_use = "The builder must be built to be used"] pub struct StepBuilder<'a> { builder: EventBuilder<'a>, amount: GenericFormattedValue, rate: f64, flush: bool, intermediate: bool, } impl<'a> StepBuilder<'a> { fn new(amount: GenericFormattedValue, rate: f64, flush: bool, intermediate: bool) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), amount, rate, flush, intermediate, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_step( s.amount.format().into_glib(), s.amount.value() as u64, s.rate, s.flush.into_glib(), s.intermediate.into_glib(), ) }); } #[must_use = "The builder must be built to be used"] pub struct ReconfigureBuilder<'a> { builder: EventBuilder<'a>, } impl<'a> ReconfigureBuilder<'a> { fn new() -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), } } event_builder_generic_impl!(|_| { ffi::gst_event_new_reconfigure() }); } #[must_use = "The builder must be built to be used"] pub struct TocSelectBuilder<'a> { builder: EventBuilder<'a>, uid: &'a str, } impl<'a> TocSelectBuilder<'a> { fn new(uid: &'a str) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), uid, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_toc_select(s.uid.to_glib_none().0) }); } #[must_use = "The builder must be built to be used"] pub struct SelectStreamsBuilder<'a> { builder: EventBuilder<'a>, streams: &'a [&'a str], } impl<'a> SelectStreamsBuilder<'a> { fn new(streams: &'a [&'a str]) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), streams, } } event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_select_streams(s.streams.to_glib_none().0) }); } #[must_use = "The builder must be built to be used"] pub struct CustomUpstreamBuilder<'a> { builder: EventBuilder<'a>, structure: Option, } impl<'a> CustomUpstreamBuilder<'a> { fn new(structure: Structure) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), structure: Some(structure), } } event_builder_generic_impl!(|s: &mut Self| { let structure = s.structure.take().unwrap(); ffi::gst_event_new_custom(ffi::GST_EVENT_CUSTOM_UPSTREAM, structure.into_glib_ptr()) }); } #[must_use = "The builder must be built to be used"] pub struct CustomDownstreamBuilder<'a> { builder: EventBuilder<'a>, structure: Option, } impl<'a> CustomDownstreamBuilder<'a> { fn new(structure: Structure) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), structure: Some(structure), } } event_builder_generic_impl!(|s: &mut Self| { let structure = s.structure.take().unwrap(); ffi::gst_event_new_custom(ffi::GST_EVENT_CUSTOM_DOWNSTREAM, structure.into_glib_ptr()) }); } #[must_use = "The builder must be built to be used"] pub struct CustomDownstreamOobBuilder<'a> { builder: EventBuilder<'a>, structure: Option, } impl<'a> CustomDownstreamOobBuilder<'a> { fn new(structure: Structure) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), structure: Some(structure), } } event_builder_generic_impl!(|s: &mut Self| { let structure = s.structure.take().unwrap(); ffi::gst_event_new_custom( ffi::GST_EVENT_CUSTOM_DOWNSTREAM_OOB, structure.into_glib_ptr(), ) }); } #[must_use = "The builder must be built to be used"] pub struct CustomDownstreamStickyBuilder<'a> { builder: EventBuilder<'a>, structure: Option, } impl<'a> CustomDownstreamStickyBuilder<'a> { fn new(structure: Structure) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), structure: Some(structure), } } event_builder_generic_impl!(|s: &mut Self| { let structure = s.structure.take().unwrap(); ffi::gst_event_new_custom( ffi::GST_EVENT_CUSTOM_DOWNSTREAM_STICKY, structure.into_glib_ptr(), ) }); } #[must_use = "The builder must be built to be used"] pub struct CustomBothBuilder<'a> { builder: EventBuilder<'a>, structure: Option, } impl<'a> CustomBothBuilder<'a> { fn new(structure: Structure) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), structure: Some(structure), } } event_builder_generic_impl!(|s: &mut Self| { let structure = s.structure.take().unwrap(); ffi::gst_event_new_custom(ffi::GST_EVENT_CUSTOM_BOTH, structure.into_glib_ptr()) }); } #[must_use = "The builder must be built to be used"] pub struct CustomBothOobBuilder<'a> { builder: EventBuilder<'a>, structure: Option, } impl<'a> CustomBothOobBuilder<'a> { fn new(structure: Structure) -> Self { skip_assert_initialized!(); Self { builder: EventBuilder::new(), structure: Some(structure), } } event_builder_generic_impl!(|s: &mut Self| { let structure = s.structure.take().unwrap(); ffi::gst_event_new_custom(ffi::GST_EVENT_CUSTOM_BOTH_OOB, structure.into_glib_ptr()) }); } #[cfg(test)] mod tests { use super::*; #[test] #[allow(deprecated)] fn test_simple() { crate::init().unwrap(); // Event without arguments let flush_start_evt = FlushStart::new(); match flush_start_evt.view() { EventView::FlushStart(flush_start_evt) => { assert!(!flush_start_evt.is_sticky()); assert!(flush_start_evt.structure().is_none()); } _ => panic!("flush_start_evt.view() is not an EventView::FlushStart(_)"), } let flush_start_evt = FlushStart::builder() .other_fields(&[("extra-field", &true)]) .build(); match flush_start_evt.view() { EventView::FlushStart(flush_start_evt) => { assert!(flush_start_evt.structure().is_some()); if let Some(other_fields) = flush_start_evt.structure() { assert!(other_fields.has_field("extra-field")); } } _ => panic!("flush_start_evt.view() is not an EventView::FlushStart(_)"), } // Event with arguments let flush_stop_evt = FlushStop::builder(true) .other_field("extra-field", true) .build(); match flush_stop_evt.view() { EventView::FlushStop(flush_stop_evt) => { assert!(flush_stop_evt.resets_time()); assert!(flush_stop_evt.structure().is_some()); if let Some(other_fields) = flush_stop_evt.structure() { assert!(other_fields.has_field("extra-field")); } } _ => panic!("flush_stop_evt.view() is not an EventView::FlushStop(_)"), } } #[test] fn test_get_structure_mut() { crate::init().unwrap(); let mut flush_start_evt = FlushStart::new(); { let flush_start_evt = flush_start_evt.get_mut().unwrap(); let structure = flush_start_evt.structure_mut(); structure.set("test", 42u32); } let structure = flush_start_evt.structure().unwrap(); assert_eq!(structure.get("test"), Ok(42u32)); } #[test] fn test_view_lifetimes() { crate::init().unwrap(); let caps = crate::Caps::builder("some/x-caps").build(); let event = crate::event::Caps::new(&caps); let caps2 = match event.view() { EventView::Caps(caps) => caps.caps(), _ => unreachable!(), }; assert_eq!(&*caps, caps2); } #[test] fn test_select_streams() { crate::init().unwrap(); let s = ["foo", "bar"].to_vec(); let event = crate::event::SelectStreams::new(&s); let streams = match event.view() { EventView::SelectStreams(streams) => streams.streams(), _ => unreachable!(), }; assert_eq!(streams, s); } } gstreamer-0.23.5/src/flag_serde.rs000064400000000000000000000476411046102023000151500ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::{ prelude::*, translate::{from_glib, ToGlibPtr}, FlagsClass, }; bitflags_serde_impl!(crate::BinFlags); bitflags_serde_impl!(crate::BufferCopyFlags); bitflags_serde_impl!(crate::BufferFlags); bitflags_serde_impl!(crate::BufferPoolAcquireFlags); bitflags_serde_impl!(crate::ClockFlags); impl serde::Serialize for crate::DebugColorFlags { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { serializer.serialize_str(&format!( "{}+{}{}{}", match *self & Self::from_bits(0b111).expect("Failed to create value from fg-color mask") { Self::FG_BLACK => "fg-black", Self::FG_RED => "fg-red", Self::FG_GREEN => "fg-green", Self::FG_YELLOW => "fg-yellow", Self::FG_BLUE => "fg-blue", Self::FG_MAGENTA => "fg-magenta", Self::FG_CYAN => "fg-cyan", Self::FG_WHITE => "fg-white", _ => unreachable!(), }, match *self & Self::from_bits(0b111_0000).expect("Failed to create value from bg-color mask") { Self::BG_BLACK => "bg-black", Self::BG_RED => "bg-red", Self::BG_GREEN => "bg-green", Self::BG_YELLOW => "bg-yellow", Self::BG_BLUE => "bg-blue", Self::BG_MAGENTA => "bg-magenta", Self::BG_CYAN => "bg-cyan", Self::BG_WHITE => "bg-white", _ => unreachable!(), }, if self.contains(Self::BOLD) { "+bold" } else { "" }, if self.contains(Self::UNDERLINE) { "+underline" } else { "" } )) } } bitflags_deserialize_impl!(crate::DebugColorFlags); bitflags_serialize_impl!(crate::DebugGraphDetails, by_ones_decreasing); bitflags_deserialize_impl!(crate::DebugGraphDetails); bitflags_serde_impl!(crate::ElementFlags); bitflags_serde_impl!(crate::EventTypeFlags); bitflags_serde_impl!(crate::GapFlags, "v1_20"); bitflags_serde_impl!(crate::MemoryFlags); bitflags_serde_impl!(crate::MetaFlags); bitflags_serde_impl!(crate::ObjectFlags); bitflags_serde_impl!(crate::PadFlags); bitflags_serde_impl!(crate::PadLinkCheck); bitflags_serde_impl!(crate::PadProbeType); bitflags_serde_impl!(crate::ParseFlags); bitflags_serde_impl!(crate::PluginAPIFlags, "v1_18"); bitflags_serde_impl!(crate::PluginDependencyFlags); bitflags_serde_impl!(crate::PluginFlags); bitflags_serde_impl!(crate::SchedulingFlags); bitflags_serde_impl!(crate::SeekFlags); bitflags_serde_impl!(crate::SegmentFlags); bitflags_serde_impl!(crate::SerializeFlags, "v1_20"); bitflags_serde_impl!(crate::StackTraceFlags); bitflags_serde_impl!(crate::StreamFlags); bitflags_serde_impl!(crate::StreamType); #[cfg(test)] mod tests { macro_rules! check_serialize { ($flags:expr, $expected:expr) => { let actual = serde_json::to_string(&$flags).unwrap(); assert_eq!(actual, $expected); }; } macro_rules! check_deserialize { ($ty:ty, $expected:expr, $json:expr) => { let actual: $ty = serde_json::from_str(&$json).unwrap(); assert_eq!(actual, $expected); }; } macro_rules! check_roundtrip { ($ty:ty, $flags:expr) => { let json = serde_json::to_string(&$flags).unwrap(); let deserialized: $ty = serde_json::from_str(&json).unwrap(); assert_eq!(deserialized, $flags); }; } #[test] fn test_serialize() { crate::init().unwrap(); check_serialize!(crate::BinFlags::empty(), "\"\""); check_serialize!(crate::BinFlags::all(), "\"no-resync+streams-aware\""); check_serialize!( crate::BufferCopyFlags::all(), "\"flags+timestamps+meta+memory+merge+deep\"" ); check_serialize!( crate::BufferFlags::all(), concat!( "\"live+decode-only+discont+resync+corrupted+marker+header+gap", "+droppable+delta-unit+tag-memory+sync-after+non-droppable\"" ) ); check_serialize!( crate::BufferPoolAcquireFlags::all(), "\"key-unit+dontwait+discont\"" ); check_serialize!( crate::ClockFlags::all(), concat!( "\"can-do-single-sync+can-do-single-async", "+can-do-periodic-sync+can-do-periodic-async", "+can-set-resolution+can-set-master+needs-startup-sync\"" ) ); check_serialize!( crate::DebugColorFlags::all(), "\"fg-white+bg-white+bold+underline\"" ); check_serialize!( crate::DebugColorFlags::FG_MAGENTA | crate::DebugColorFlags::BOLD, "\"fg-magenta+bg-black+bold\"" ); check_serialize!( crate::DebugColorFlags::FG_RED | crate::DebugColorFlags::FG_BLUE | crate::DebugColorFlags::BG_BLACK, "\"fg-magenta+bg-black\"" ); check_serialize!(crate::DebugGraphDetails::all(), "\"verbose\""); check_serialize!( crate::DebugGraphDetails::MEDIA_TYPE | crate::DebugGraphDetails::CAPS_DETAILS | crate::DebugGraphDetails::NON_DEFAULT_PARAMS | crate::DebugGraphDetails::STATES | crate::DebugGraphDetails::FULL_PARAMS | crate::DebugGraphDetails::ALL, "\"all+full-params\"" ); check_serialize!( crate::DebugGraphDetails::MEDIA_TYPE | crate::DebugGraphDetails::CAPS_DETAILS | crate::DebugGraphDetails::NON_DEFAULT_PARAMS | crate::DebugGraphDetails::STATES | crate::DebugGraphDetails::FULL_PARAMS, "\"all+full-params\"" ); check_serialize!( crate::ElementFlags::all(), "\"locked-state+sink+source+provide-clock+require-clock+indexable\"" ); check_serialize!( crate::EventTypeFlags::all(), "\"upstream+downstream+serialized+sticky+sticky-multi\"" ); #[cfg(feature = "v1_20")] check_serialize!(crate::GapFlags::all(), "\"data\""); check_serialize!( crate::MemoryFlags::all(), concat!( "\"readonly+no-share+zero-prefixed+zero-padded", "+physically-contiguous+not-mappable\"" ) ); check_serialize!(crate::MetaFlags::all(), "\"readonly+pooled+locked\""); cfg_if::cfg_if! { if #[cfg(feature = "v1_24")] { check_serialize!(crate::ObjectFlags::all(), "\"may-be-leaked+constructed\""); } else { check_serialize!(crate::ObjectFlags::all(), "\"may-be-leaked\""); } } check_serialize!( crate::PadFlags::all(), concat!( "\"blocked+flushing+eos+blocking+need-parent+need-reconfigure", "+pending-events+fixed-caps+proxy-caps+proxy-allocation", "+proxy-scheduling+accept-intersect+accept-template\"" ) ); check_serialize!( crate::PadLinkCheck::all(), "\"hierarchy+template-caps+caps+no-reconfigure\"" ); check_serialize!( crate::PadProbeType::all(), concat!( "\"idle+block+buffer+buffer-list+event-downstream", "+event-upstream+event-flush+query-downstream+query-upstream", "+push+pull\"" ) ); check_serialize!( crate::ParseFlags::all(), "\"fatal-errors+no-single-element-bins+place-in-bin\"" ); #[cfg(feature = "v1_18")] check_serialize!(crate::PluginAPIFlags::all(), "\"members\""); check_serialize!( crate::PluginDependencyFlags::all(), concat!( "\"recurse+paths-are-default-only+file-name-is-suffix", "+file-name-is-prefix+paths-are-relative-to-exe\"" ) ); check_serialize!(crate::PluginFlags::all(), "\"cached+blacklisted\""); check_serialize!( crate::SchedulingFlags::all(), "\"seekable+sequential+bandwidth-limited\"" ); #[cfg(feature = "v1_18")] check_serialize!( crate::SeekFlags::all(), concat!( "\"flush+accurate+key-unit+segment+trickmode+snap-before", "+snap-after+trickmode-key-units+trickmode-no-audio", "+trickmode-forward-predicted+instant-rate-change\"" ) ); #[cfg(feature = "v1_18")] check_serialize!( crate::SegmentFlags::all(), concat!( "\"reset+trickmode+segment+trickmode-key-units", "+trickmode-forward-predicted+trickmode-no-audio\"" ) ); #[cfg(feature = "v1_20")] check_serialize!(crate::SerializeFlags::all(), "\"backward-compat\""); check_serialize!(crate::StackTraceFlags::all(), "\"full\""); check_serialize!(crate::StreamFlags::all(), "\"sparse+select+unselect\""); check_serialize!( crate::StreamType::all(), "\"unknown+audio+video+container+text\"" ); } #[test] fn test_deserialize() { crate::init().unwrap(); check_deserialize!(crate::BinFlags, crate::BinFlags::empty(), "\"\""); check_deserialize!( crate::BinFlags, crate::BinFlags::all(), "\"no-resync+streams-aware\"" ); check_deserialize!( crate::BufferCopyFlags, crate::BufferCopyFlags::all(), "\"flags+timestamps+meta+memory+merge+deep\"" ); check_deserialize!( crate::BufferFlags, crate::BufferFlags::all(), concat!( "\"live+decode-only+discont+resync+corrupted+marker+header+gap", "+droppable+delta-unit+tag-memory+sync-after+non-droppable\"" ) ); check_deserialize!( crate::BufferPoolAcquireFlags, crate::BufferPoolAcquireFlags::all(), "\"key-unit+dontwait+discont\"" ); check_deserialize!( crate::ClockFlags, crate::ClockFlags::all(), concat!( "\"can-do-single-sync+can-do-single-async", "+can-do-periodic-sync+can-do-periodic-async", "+can-set-resolution+can-set-master+needs-startup-sync\"" ) ); check_deserialize!( crate::DebugColorFlags, crate::DebugColorFlags::all(), "\"fg-white+bg-white+bold+underline\"" ); check_deserialize!( crate::DebugColorFlags, crate::DebugColorFlags::FG_MAGENTA | crate::DebugColorFlags::BOLD, "\"fg-magenta+bg-black+bold\"" ); check_deserialize!( crate::DebugColorFlags, crate::DebugColorFlags::FG_RED | crate::DebugColorFlags::FG_BLUE | crate::DebugColorFlags::BG_BLACK, "\"fg-magenta+bg-black\"" ); check_deserialize!( crate::DebugGraphDetails, crate::DebugGraphDetails::all(), "\"verbose\"" ); check_deserialize!( crate::DebugGraphDetails, crate::DebugGraphDetails::MEDIA_TYPE | crate::DebugGraphDetails::CAPS_DETAILS | crate::DebugGraphDetails::NON_DEFAULT_PARAMS | crate::DebugGraphDetails::STATES | crate::DebugGraphDetails::FULL_PARAMS | crate::DebugGraphDetails::ALL, "\"all+full-params\"" ); check_deserialize!( crate::DebugGraphDetails, crate::DebugGraphDetails::MEDIA_TYPE | crate::DebugGraphDetails::CAPS_DETAILS | crate::DebugGraphDetails::NON_DEFAULT_PARAMS | crate::DebugGraphDetails::STATES | crate::DebugGraphDetails::FULL_PARAMS, "\"all+full-params\"" ); check_deserialize!( crate::ElementFlags, crate::ElementFlags::all(), "\"locked-state+sink+source+provide-clock+require-clock+indexable\"" ); check_deserialize!( crate::EventTypeFlags, crate::EventTypeFlags::all(), "\"upstream+downstream+serialized+sticky+sticky-multi\"" ); #[cfg(feature = "v1_20")] check_deserialize!(crate::GapFlags, crate::GapFlags::all(), "\"data\""); check_deserialize!( crate::MemoryFlags, crate::MemoryFlags::all(), concat!( "\"readonly+no-share+zero-prefixed+zero-padded", "+physically-contiguous+not-mappable\"" ) ); check_deserialize!( crate::MetaFlags, crate::MetaFlags::all(), "\"readonly+pooled+locked\"" ); check_deserialize!( crate::ObjectFlags, crate::ObjectFlags::all(), "\"may-be-leaked+constructed\"" ); check_deserialize!( crate::PadFlags, crate::PadFlags::all(), concat!( "\"blocked+flushing+eos+blocking+need-parent+need-reconfigure", "+pending-events+fixed-caps+proxy-caps+proxy-allocation", "+proxy-scheduling+accept-intersect+accept-template\"" ) ); check_deserialize!( crate::PadLinkCheck, crate::PadLinkCheck::all(), "\"hierarchy+template-caps+caps+no-reconfigure\"" ); check_deserialize!( crate::PadProbeType, crate::PadProbeType::all(), concat!( "\"idle+block+buffer+buffer-list+event-downstream", "+event-upstream+event-flush+query-downstream+query-upstream", "+push+pull\"" ) ); check_deserialize!( crate::ParseFlags, crate::ParseFlags::all(), "\"fatal-errors+no-single-element-bins+place-in-bin\"" ); #[cfg(feature = "v1_18")] check_deserialize!( crate::PluginAPIFlags, crate::PluginAPIFlags::all(), "\"members\"" ); check_deserialize!( crate::PluginDependencyFlags, crate::PluginDependencyFlags::all(), concat!( "\"recurse+paths-are-default-only+file-name-is-suffix", "+file-name-is-prefix+paths-are-relative-to-exe\"" ) ); check_deserialize!( crate::PluginFlags, crate::PluginFlags::all(), "\"cached+blacklisted\"" ); check_deserialize!( crate::SchedulingFlags, crate::SchedulingFlags::all(), "\"seekable+sequential+bandwidth-limited\"" ); #[cfg(feature = "v1_18")] check_deserialize!( crate::SeekFlags, crate::SeekFlags::all(), concat!( "\"flush+accurate+key-unit+segment+trickmode+snap-before", "+snap-after+trickmode-key-units+trickmode-no-audio", "+trickmode-forward-predicted+instant-rate-change\"" ) ); #[cfg(feature = "v1_18")] check_deserialize!( crate::SegmentFlags, crate::SegmentFlags::all(), concat!( "\"reset+trickmode+segment+trickmode-key-units", "+trickmode-forward-predicted+trickmode-no-audio\"" ) ); #[cfg(feature = "v1_20")] check_deserialize!( crate::SerializeFlags, crate::SerializeFlags::all(), "\"backward-compat\"" ); check_deserialize!( crate::StackTraceFlags, crate::StackTraceFlags::all(), "\"full\"" ); check_deserialize!( crate::StreamFlags, crate::StreamFlags::all(), "\"sparse+select+unselect\"" ); check_deserialize!( crate::StreamType, crate::StreamType::all(), "\"unknown+audio+video+container+text\"" ); } #[test] fn test_serde_roundtrip() { crate::init().unwrap(); check_roundtrip!(crate::BinFlags, crate::BinFlags::empty()); check_roundtrip!(crate::BinFlags, crate::BinFlags::all()); check_roundtrip!(crate::BufferCopyFlags, crate::BufferCopyFlags::all()); check_roundtrip!(crate::BufferFlags, crate::BufferFlags::all()); check_roundtrip!( crate::BufferPoolAcquireFlags, crate::BufferPoolAcquireFlags::all() ); check_roundtrip!(crate::ClockFlags, crate::ClockFlags::all()); check_roundtrip!(crate::DebugColorFlags, crate::DebugColorFlags::all()); check_roundtrip!( crate::DebugColorFlags, crate::DebugColorFlags::FG_MAGENTA | crate::DebugColorFlags::BOLD ); check_roundtrip!( crate::DebugColorFlags, crate::DebugColorFlags::FG_RED | crate::DebugColorFlags::FG_BLUE | crate::DebugColorFlags::BG_BLACK ); check_roundtrip!(crate::DebugGraphDetails, crate::DebugGraphDetails::all()); check_roundtrip!( crate::DebugGraphDetails, crate::DebugGraphDetails::MEDIA_TYPE | crate::DebugGraphDetails::CAPS_DETAILS | crate::DebugGraphDetails::NON_DEFAULT_PARAMS | crate::DebugGraphDetails::STATES | crate::DebugGraphDetails::FULL_PARAMS | crate::DebugGraphDetails::ALL ); check_roundtrip!( crate::DebugGraphDetails, crate::DebugGraphDetails::MEDIA_TYPE | crate::DebugGraphDetails::CAPS_DETAILS | crate::DebugGraphDetails::NON_DEFAULT_PARAMS | crate::DebugGraphDetails::STATES | crate::DebugGraphDetails::FULL_PARAMS ); check_roundtrip!(crate::ElementFlags, crate::ElementFlags::all()); check_roundtrip!(crate::EventTypeFlags, crate::EventTypeFlags::all()); #[cfg(feature = "v1_20")] check_roundtrip!(crate::GapFlags, crate::GapFlags::all()); check_roundtrip!(crate::MemoryFlags, crate::MemoryFlags::all()); check_roundtrip!(crate::MetaFlags, crate::MetaFlags::all()); check_roundtrip!(crate::ObjectFlags, crate::ObjectFlags::all()); check_roundtrip!(crate::PadFlags, crate::PadFlags::all()); check_roundtrip!(crate::PadLinkCheck, crate::PadLinkCheck::all()); check_roundtrip!(crate::PadProbeType, crate::PadProbeType::all()); check_roundtrip!(crate::ParseFlags, crate::ParseFlags::all()); #[cfg(feature = "v1_18")] check_roundtrip!(crate::PluginAPIFlags, crate::PluginAPIFlags::all()); check_roundtrip!( crate::PluginDependencyFlags, crate::PluginDependencyFlags::all() ); check_roundtrip!(crate::PluginFlags, crate::PluginFlags::all()); check_roundtrip!(crate::SchedulingFlags, crate::SchedulingFlags::all()); #[cfg(feature = "v1_18")] check_roundtrip!(crate::SeekFlags, crate::SeekFlags::all()); #[cfg(feature = "v1_18")] check_roundtrip!(crate::SegmentFlags, crate::SegmentFlags::all()); #[cfg(feature = "v1_20")] check_roundtrip!(crate::SerializeFlags, crate::SerializeFlags::all()); check_roundtrip!(crate::StackTraceFlags, crate::StackTraceFlags::all()); check_roundtrip!(crate::StreamFlags, crate::StreamFlags::all()); check_roundtrip!(crate::StreamType, crate::StreamType::all()); } } gstreamer-0.23.5/src/format/clock_time.rs000064400000000000000000001766241046102023000164620ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ fmt, io::{self, prelude::*}, time::Duration, }; use crate::{ffi, prelude::*}; use glib::translate::*; use super::{ Format, FormattedValue, FormattedValueError, FormattedValueFullRange, FormattedValueIntrinsic, FormattedValueNoneBuilder, GenericFormattedValue, Signed, SpecificFormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic, }; const TRY_FROM_FLOAT_SECS_ERROR_MSG: &str = "can not convert float seconds to ClockTime: value is either negative, too big or NaN"; #[derive(Debug, Clone, PartialEq, Eq)] pub struct TryFromFloatSecsError; impl fmt::Display for TryFromFloatSecsError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(TRY_FROM_FLOAT_SECS_ERROR_MSG) } } impl std::error::Error for TryFromFloatSecsError {} #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] pub struct ClockTime(u64); impl ClockTime { #[doc(alias = "GST_SECOND")] pub const SECOND: ClockTime = ClockTime(1_000_000_000); #[doc(alias = "GST_MSECOND")] pub const MSECOND: ClockTime = ClockTime(1_000_000); #[doc(alias = "GST_USECOND")] pub const USECOND: ClockTime = ClockTime(1_000); #[doc(alias = "GST_NSECOND")] pub const NSECOND: ClockTime = ClockTime(1); // checker-ignore-item pub const MAX: ClockTime = ClockTime(ffi::GST_CLOCK_TIME_NONE - 1); #[inline] pub const fn hours(self) -> u64 { self.0 / Self::SECOND.0 / 60 / 60 } #[inline] pub const fn minutes(self) -> u64 { self.0 / Self::SECOND.0 / 60 } #[inline] pub const fn seconds(self) -> u64 { self.0 / Self::SECOND.0 } #[inline] pub fn seconds_f32(self) -> f32 { self.0 as f32 / Self::SECOND.0 as f32 } #[inline] pub fn seconds_f64(self) -> f64 { self.0 as f64 / Self::SECOND.0 as f64 } #[inline] pub const fn mseconds(self) -> u64 { self.0 / Self::MSECOND.0 } #[inline] pub const fn useconds(self) -> u64 { self.0 / Self::USECOND.0 } #[inline] pub const fn nseconds(self) -> u64 { self.0 } // rustdoc-stripper-ignore-next /// Builds a new `ClockTime` which value is the given number of seconds. /// /// # Panics /// /// Panics if the resulting duration in nanoseconds exceeds the `u64` range. #[track_caller] #[inline] pub const fn from_seconds(seconds: u64) -> Self { skip_assert_initialized!(); // `Option::expect` is not `const` as of rustc 1.63.0. ClockTime(match seconds.checked_mul(Self::SECOND.0) { Some(res) => res, None => panic!("Out of `ClockTime` range"), }) } // rustdoc-stripper-ignore-next /// Builds a new `ClockTime` which value is the given number of seconds. /// /// Returns an error if seconds is negative, infinite or NaN, or /// the resulting duration in nanoseconds exceeds the `u64` range. #[inline] pub fn try_from_seconds_f32(seconds: f32) -> Result { skip_assert_initialized!(); let dur = Duration::try_from_secs_f32(seconds).map_err(|_| TryFromFloatSecsError)?; ClockTime::try_from(dur).map_err(|_| TryFromFloatSecsError) } // rustdoc-stripper-ignore-next /// Builds a new `ClockTime` which value is the given number of seconds. /// /// # Panics /// /// Panics if seconds is negative, infinite or NaN, or the resulting duration /// in nanoseconds exceeds the `u64` range. #[track_caller] #[inline] pub fn from_seconds_f32(seconds: f32) -> Self { skip_assert_initialized!(); Self::try_from_seconds_f32(seconds).expect(TRY_FROM_FLOAT_SECS_ERROR_MSG) } // rustdoc-stripper-ignore-next /// Builds a new `ClockTime` which value is the given number of seconds. /// /// Returns an error if seconds is negative, infinite or NaN, or /// the resulting duration in nanoseconds exceeds the `u64` range. #[inline] pub fn try_from_seconds_f64(seconds: f64) -> Result { skip_assert_initialized!(); let dur = Duration::try_from_secs_f64(seconds).map_err(|_| TryFromFloatSecsError)?; ClockTime::try_from(dur).map_err(|_| TryFromFloatSecsError) } // rustdoc-stripper-ignore-next /// Builds a new `ClockTime` which value is the given number of seconds. /// /// # Panics /// /// Panics if seconds is negative, infinite or NaN, or the resulting duration /// in nanoseconds exceeds the `u64` range. #[track_caller] #[inline] pub fn from_seconds_f64(seconds: f64) -> Self { skip_assert_initialized!(); Self::try_from_seconds_f64(seconds).expect(TRY_FROM_FLOAT_SECS_ERROR_MSG) } // rustdoc-stripper-ignore-next /// Builds a new `ClockTime` which value is the given number of milliseconds. /// /// # Panics /// /// Panics if the resulting duration in nanoseconds exceeds the `u64` range. #[track_caller] #[inline] pub const fn from_mseconds(mseconds: u64) -> Self { skip_assert_initialized!(); // `Option::expect` is not `const` as of rustc 1.63.0. ClockTime(match mseconds.checked_mul(Self::MSECOND.0) { Some(res) => res, None => panic!("Out of `ClockTime` range"), }) } // rustdoc-stripper-ignore-next /// Builds a new `ClockTime` which value is the given number of microseconds. /// /// # Panics /// /// Panics if the resulting duration in nanoseconds exceeds the `u64` range. #[track_caller] #[inline] pub const fn from_useconds(useconds: u64) -> Self { skip_assert_initialized!(); // `Option::expect` is not `const` as of rustc 1.63.0. ClockTime(match useconds.checked_mul(Self::USECOND.0) { Some(res) => res, None => panic!("Out of `ClockTime` range"), }) } // rustdoc-stripper-ignore-next /// Builds a new `ClockTime` which value is the given number of nanoseconds. /// /// # Panics /// /// Panics if the requested duration equals `GST_CLOCK_TIME_NONE` /// (`u64::MAX`). #[track_caller] #[inline] pub const fn from_nseconds(nseconds: u64) -> Self { skip_assert_initialized!(); assert!( nseconds != ffi::GST_CLOCK_TIME_NONE, "Attempt to build a `ClockTime` with value `GST_CLOCK_TIME_NONE`", ); ClockTime(nseconds * Self::NSECOND.0) } } impl Signed { // rustdoc-stripper-ignore-next /// Returns the `self` in nanoseconds. #[inline] pub fn nseconds(self) -> Signed { match self { Signed::Positive(val) => Signed::Positive(val.nseconds()), Signed::Negative(val) => Signed::Negative(val.nseconds()), } } // rustdoc-stripper-ignore-next /// Creates new value from nanoseconds. #[inline] pub fn from_nseconds(val: Signed) -> Self { skip_assert_initialized!(); match val { Signed::Positive(val) => Signed::Positive(ClockTime::from_nseconds(val)), Signed::Negative(val) => Signed::Negative(ClockTime::from_nseconds(val)), } } // rustdoc-stripper-ignore-next /// Returns the `self` in microseconds. #[inline] pub fn useconds(self) -> Signed { match self { Signed::Positive(val) => Signed::Positive(val.useconds()), Signed::Negative(val) => Signed::Negative(val.useconds()), } } // rustdoc-stripper-ignore-next /// Creates new value from microseconds. #[inline] pub fn from_useconds(val: Signed) -> Self { skip_assert_initialized!(); match val { Signed::Positive(val) => Signed::Positive(ClockTime::from_useconds(val)), Signed::Negative(val) => Signed::Negative(ClockTime::from_useconds(val)), } } // rustdoc-stripper-ignore-next /// Returns the `self` in milliseconds. #[inline] pub fn mseconds(self) -> Signed { match self { Signed::Positive(val) => Signed::Positive(val.mseconds()), Signed::Negative(val) => Signed::Negative(val.mseconds()), } } // rustdoc-stripper-ignore-next /// Creates new value from milliseconds. #[inline] pub fn from_mseconds(val: Signed) -> Self { skip_assert_initialized!(); match val { Signed::Positive(val) => Signed::Positive(ClockTime::from_mseconds(val)), Signed::Negative(val) => Signed::Negative(ClockTime::from_mseconds(val)), } } // rustdoc-stripper-ignore-next /// Returns the `self` in seconds. #[inline] pub fn seconds(self) -> Signed { match self { Signed::Positive(val) => Signed::Positive(val.seconds()), Signed::Negative(val) => Signed::Negative(val.seconds()), } } // rustdoc-stripper-ignore-next /// Returns the `self` in f32 seconds. #[inline] pub fn seconds_f32(self) -> f32 { match self { Signed::Positive(val) => val.seconds_f32(), Signed::Negative(val) => -val.seconds_f32(), } } // rustdoc-stripper-ignore-next /// Returns the `self` in f64 seconds. #[inline] pub fn seconds_f64(self) -> f64 { match self { Signed::Positive(val) => val.seconds_f64(), Signed::Negative(val) => -val.seconds_f64(), } } // rustdoc-stripper-ignore-next /// Creates new value from seconds. #[inline] pub fn from_seconds(val: Signed) -> Self { skip_assert_initialized!(); match val { Signed::Positive(val) => Signed::Positive(ClockTime::from_seconds(val)), Signed::Negative(val) => Signed::Negative(ClockTime::from_seconds(val)), } } // rustdoc-stripper-ignore-next /// Builds a new `Signed` which value is the given number of seconds. /// /// Returns an error if seconds is infinite or NaN, or /// the resulting duration in nanoseconds exceeds the `u64` range. #[inline] pub fn try_from_seconds_f32(seconds: f32) -> Result { skip_assert_initialized!(); ClockTime::try_from_seconds_f32(seconds.abs()).map(|ct| { if seconds.is_sign_positive() { Signed::Positive(ct) } else { Signed::Negative(ct) } }) } // rustdoc-stripper-ignore-next /// Builds a new `Signed` which value is the given number of seconds. /// /// # Panics /// /// Panics if seconds is infinite or NaN, or the resulting duration /// in nanoseconds exceeds the `u64` range. #[track_caller] #[inline] pub fn from_seconds_f32(seconds: f32) -> Self { skip_assert_initialized!(); Self::try_from_seconds_f32(seconds).expect(TRY_FROM_FLOAT_SECS_ERROR_MSG) } // rustdoc-stripper-ignore-next /// Builds a new `Signed` which value is the given number of seconds. /// /// Returns an error if seconds is infinite or NaN, or /// the resulting duration in nanoseconds exceeds the `u64` range. #[inline] pub fn try_from_seconds_f64(seconds: f64) -> Result { skip_assert_initialized!(); ClockTime::try_from_seconds_f64(seconds.abs()).map(|ct| { if seconds.is_sign_positive() { Signed::Positive(ct) } else { Signed::Negative(ct) } }) } // rustdoc-stripper-ignore-next /// Builds a new `Signed` which value is the given number of seconds. /// /// # Panics /// /// Panics if seconds is infinite or NaN, or the resulting duration /// in nanoseconds exceeds the `u64` range. #[track_caller] #[inline] pub fn from_seconds_f64(seconds: f64) -> Self { skip_assert_initialized!(); Self::try_from_seconds_f64(seconds).expect(TRY_FROM_FLOAT_SECS_ERROR_MSG) } } impl_format_value_traits!(ClockTime, Time, Time, u64); option_glib_newtype_from_to!(ClockTime, ffi::GST_CLOCK_TIME_NONE); // FIXME `functions in traits cannot be const` (rustc 1.64.0) // rustdoc-stripper-ignore-next /// `ClockTime` formatted value constructor trait. pub trait TimeFormatConstructor { // rustdoc-stripper-ignore-next /// Builds a `ClockTime` formatted value from `self` interpreted as nano seconds. fn nseconds(self) -> ClockTime; // rustdoc-stripper-ignore-next /// Builds a `ClockTime` formatted value from `self` interpreted as micro seconds. fn useconds(self) -> ClockTime; // rustdoc-stripper-ignore-next /// Builds a `ClockTime` formatted value from `self` interpreted as milli seconds. fn mseconds(self) -> ClockTime; // rustdoc-stripper-ignore-next /// Builds a `ClockTime` formatted value from `self` interpreted as seconds. fn seconds(self) -> ClockTime; // rustdoc-stripper-ignore-next /// Builds a `ClockTime` formatted value from `self` interpreted as minutes. fn minutes(self) -> ClockTime; // rustdoc-stripper-ignore-next /// Builds a `ClockTime` formatted value from `self` interpreted as hours. fn hours(self) -> ClockTime; } impl TimeFormatConstructor for u64 { #[track_caller] #[inline] fn nseconds(self) -> ClockTime { ClockTime::from_nseconds(self) } #[track_caller] #[inline] fn useconds(self) -> ClockTime { ClockTime::from_useconds(self) } #[track_caller] #[inline] fn mseconds(self) -> ClockTime { ClockTime::from_mseconds(self) } #[track_caller] #[inline] fn seconds(self) -> ClockTime { ClockTime::from_seconds(self) } #[track_caller] #[inline] fn minutes(self) -> ClockTime { ClockTime::from_seconds(self * 60) } #[track_caller] #[inline] fn hours(self) -> ClockTime { ClockTime::from_seconds(self * 60 * 60) } } impl glib::value::ValueType for ClockTime { type Type = Self; } pub enum ClockTimeValueTypeOrNoneChecker {} unsafe impl glib::value::ValueTypeChecker for ClockTimeValueTypeOrNoneChecker { type Error = glib::value::ValueTypeMismatchOrNoneError; #[inline] fn check(value: &glib::Value) -> Result<(), Self::Error> { skip_assert_initialized!(); glib::value::GenericValueTypeChecker::::check(value)?; let gct = unsafe { glib::gobject_ffi::g_value_get_uint64(value.to_glib_none().0) }; if gct == ffi::GST_CLOCK_TIME_NONE { return Err(glib::value::ValueTypeMismatchOrNoneError::UnexpectedNone); } Ok(()) } } unsafe impl glib::value::FromValue<'_> for ClockTime { type Checker = ClockTimeValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &glib::Value) -> ClockTime { skip_assert_initialized!(); ClockTime(glib::gobject_ffi::g_value_get_uint64( value.to_glib_none().0, )) } } impl glib::value::ToValue for ClockTime { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); let gct = self.into_glib(); if gct == ffi::GST_CLOCK_TIME_NONE { crate::warning!( crate::CAT_RUST, "converting a defined `ClockTime` with value `GST_CLOCK_TIME_NONE` to `Value`, this is probably not what you wanted.", ); } unsafe { glib::gobject_ffi::g_value_set_uint64(value.to_glib_none_mut().0, gct) } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl glib::value::ToValueOptional for ClockTime { #[inline] fn to_value_optional(opt: Option<&Self>) -> glib::Value { skip_assert_initialized!(); let mut value = glib::Value::for_value_type::(); let inner = opt.map(|inner| inner.0).unwrap_or(ffi::GST_CLOCK_TIME_NONE); unsafe { glib::gobject_ffi::g_value_set_uint64(value.to_glib_none_mut().0, inner) }; value } } impl From for glib::Value { #[inline] fn from(v: ClockTime) -> glib::Value { glib::value::ToValue::to_value(&v) } } #[doc(hidden)] impl StaticType for ClockTime { #[inline] fn static_type() -> glib::Type { ::static_type() } } impl HasParamSpec for ClockTime { type ParamSpec = glib::ParamSpecUInt64; type SetValue = Self; type BuilderFn = fn(&str) -> glib::ParamSpecUInt64Builder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder } } #[derive(Debug)] pub struct DurationError; impl fmt::Display for DurationError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "out of range conversion from Duration attempted") } } impl std::error::Error for DurationError {} impl TryFrom for ClockTime { type Error = DurationError; #[inline] fn try_from(d: Duration) -> Result { skip_assert_initialized!(); let nanos = d.as_nanos(); // Note: `u64::MAX` is `ClockTime::NONE`. if nanos >= u64::MAX as u128 { return Err(DurationError); } Ok(ClockTime::from_nseconds(nanos as u64)) } } impl From for Duration { #[inline] fn from(t: ClockTime) -> Self { skip_assert_initialized!(); Duration::from_nanos(t.nseconds()) } } impl_common_ops_for_newtype_uint!(ClockTime, u64); impl_signed_div_mul!(ClockTime, u64); impl_signed_int_into_signed!(ClockTime, u64); // rustdoc-stripper-ignore-next /// Tell [`pad_clocktime`] what kind of time we're formatting enum Sign { // rustdoc-stripper-ignore-next /// An undefined time (`None`) Undefined, // rustdoc-stripper-ignore-next /// A non-negative time (zero or greater) NonNegative, // For a future ClockTimeDiff formatting #[allow(dead_code)] // rustdoc-stripper-ignore-next /// A negative time (below zero) Negative, } // Derived from libcore `Formatter::pad_integral` (same APACHE v2 + MIT licenses) // // TODO: Would be useful for formatting ClockTimeDiff // if it was a new type instead of an alias for i64 // // rustdoc-stripper-ignore-next /// Performs the correct padding for a clock time which has already been /// emitted into a str, as by [`write_clocktime`]. The str should *not* /// contain the sign; that will be added by this method. fn pad_clocktime(f: &mut fmt::Formatter<'_>, sign: Sign, buf: &str) -> fmt::Result { skip_assert_initialized!(); use std::fmt::{Alignment, Write}; use self::Sign::*; // Start by determining how we're padding, gathering // settings from the Formatter and the Sign // Choose the fill character let sign_aware_zero_pad = f.sign_aware_zero_pad(); let fill_char = match sign { Undefined if sign_aware_zero_pad => '-', // Zero-padding an undefined time _ if sign_aware_zero_pad => '0', // Zero-padding a valid time _ => f.fill(), // Otherwise, pad with the user-chosen character }; // Choose the sign character let sign_plus = f.sign_plus(); let sign_char = match sign { Undefined if sign_plus => Some(fill_char), // User requested sign, time is undefined NonNegative if sign_plus => Some('+'), // User requested sign, time is zero or above Negative => Some('-'), // Time is below zero _ => None, // Otherwise, add no sign }; // Our minimum width is the value's width, plus 1 for the sign if present let width = buf.len() + sign_char.map_or(0, |_| 1); // Subtract the minimum width from the requested width to get the padding, // taking care not to allow wrapping due to underflow let padding = f.width().unwrap_or(0).saturating_sub(width); // Split the required padding into the three possible parts let align = f.align().unwrap_or(Alignment::Right); let (pre_padding, zero_padding, post_padding) = match align { _ if sign_aware_zero_pad => (0, padding, 0), // Zero-padding: Pad between sign and value Alignment::Left => (0, 0, padding), // Align left: Pad on the right side Alignment::Right => (padding, 0, 0), // Align right: Pad on the left side // Align center: Split equally between left and right side // If the required padding is odd, the right side gets one more char Alignment::Center => (padding / 2, 0, (padding + 1) / 2), }; // And now for the actual writing for _ in 0..pre_padding { f.write_char(fill_char)?; // Left padding } if let Some(c) = sign_char { f.write_char(c)?; // ------- Sign character } for _ in 0..zero_padding { f.write_char(fill_char)?; // Padding between sign and value } f.write_str(buf)?; // ---------- Value for _ in 0..post_padding { f.write_char(fill_char)?; // Right padding } Ok(()) } // rustdoc-stripper-ignore-next /// Writes an unpadded, signless clocktime string with the given precision fn write_clocktime( mut writer: W, clocktime: Option, precision: usize, ) -> io::Result<()> { skip_assert_initialized!(); let precision = std::cmp::min(9, precision); if let Some(ns) = clocktime.map(ClockTime::nseconds) { // Split the time into parts let (s, ns) = num_integer::div_rem(ns, 1_000_000_000); let (m, s) = num_integer::div_rem(s, 60); let (h, m) = num_integer::div_rem(m, 60); // Write HH:MM:SS write!(writer, "{h}:{m:02}:{s:02}")?; if precision > 0 { // Format the nanoseconds into a stack-allocated string // The value is zero-padded so always 9 digits long let mut buf = [0u8; 9]; write!(&mut buf[..], "{ns:09}").unwrap(); let buf_str = std::str::from_utf8(&buf[..]).unwrap(); // Write decimal point and a prefix of the nanoseconds for more precision write!(writer, ".{buf_str:.precision$}")?; } } else { // Undefined time // Write HH:MM:SS, but invalid write!(writer, "--:--:--")?; if precision > 0 { // Write decimal point and dashes for more precision write!(writer, ".{:->p$}", "", p = precision)?; } } Ok(()) } fn fmt_opt_clock_time(ct: Option, f: &mut fmt::Formatter) -> fmt::Result { skip_assert_initialized!(); let precision = f.precision().unwrap_or(9); // What the maximum time (u64::MAX - 1) would format to const MAX_SIZE: usize = "5124095:34:33.709551614".len(); // Write the unpadded clocktime value into a stack-allocated string let mut buf = [0u8; MAX_SIZE]; let mut cursor = io::Cursor::new(&mut buf[..]); write_clocktime(&mut cursor, ct, precision).unwrap(); let pos = cursor.position() as usize; let buf_str = std::str::from_utf8(&buf[..pos]).unwrap(); let sign = if ct.is_some() { Sign::NonNegative } else { Sign::Undefined }; pad_clocktime(f, sign, buf_str) } impl fmt::Display for ClockTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt_opt_clock_time(Some(*self), f) } } impl fmt::Debug for ClockTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } } pub struct DisplayableOptClockTime(Option); impl fmt::Display for DisplayableOptClockTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt_opt_clock_time(self.0, f) } } impl fmt::Debug for DisplayableOptClockTime { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } } impl crate::utils::Displayable for Option { type DisplayImpl = DisplayableOptClockTime; fn display(self) -> DisplayableOptClockTime { DisplayableOptClockTime(self) } } impl crate::utils::Displayable for ClockTime { type DisplayImpl = ClockTime; fn display(self) -> ClockTime { self } } impl std::iter::Sum for ClockTime { fn sum>(iter: I) -> Self { skip_assert_initialized!(); iter.fold(ClockTime::ZERO, |a, b| a + b) } } #[cfg(test)] mod tests { use opt_ops::prelude::*; use super::*; use crate::format::{Signed, UnsignedIntoSigned}; const CT_1: ClockTime = ClockTime::from_nseconds(1); const CT_2: ClockTime = ClockTime::from_nseconds(2); const CT_3: ClockTime = ClockTime::from_nseconds(3); const CT_10: ClockTime = ClockTime::from_nseconds(10); const CT_20: ClockTime = ClockTime::from_nseconds(20); const CT_30: ClockTime = ClockTime::from_nseconds(30); const P_CT_0: Signed = Signed::Positive(ClockTime::ZERO); const P_CT_NONE: Option> = None; const P_CT_1: Signed = Signed::Positive(ClockTime::from_nseconds(1)); const P_CT_2: Signed = Signed::Positive(ClockTime::from_nseconds(2)); const P_CT_3: Signed = Signed::Positive(ClockTime::from_nseconds(3)); const N_CT_1: Signed = Signed::Negative(ClockTime::from_nseconds(1)); const N_CT_2: Signed = Signed::Negative(ClockTime::from_nseconds(2)); const N_CT_3: Signed = Signed::Negative(ClockTime::from_nseconds(3)); #[test] fn opt_time_clock() { assert_eq!(CT_1.into_glib(), 1); assert_eq!(Some(CT_1).into_glib(), 1); assert_eq!(ClockTime::NONE.into_glib(), ffi::GST_CLOCK_TIME_NONE); let ct_1_from: ClockTime = unsafe { try_from_glib(1u64) }.unwrap(); assert_eq!(ct_1_from, CT_1); let opt_ct_some: Option = unsafe { from_glib(1u64) }; assert_eq!(opt_ct_some, Some(CT_1)); let ct_none: Option = unsafe { from_glib(ffi::GST_CLOCK_TIME_NONE) }; assert_eq!(ct_none, None); } #[test] #[allow(clippy::eq_op, clippy::op_ref)] fn ops() { assert_eq!(CT_10 + CT_20, CT_30); assert_eq!(CT_30 - CT_20, CT_10); assert_eq!(CT_30 - CT_30, ClockTime::ZERO); assert_eq!(CT_10 * 3, CT_30); assert_eq!(3 * CT_10, CT_30); assert_eq!(CT_20 / 2, CT_10); assert_eq!(CT_20 / CT_2, 10); assert_eq!(CT_30.nseconds(), 30); assert_eq!(P_CT_1 + P_CT_2, P_CT_3); assert_eq!(P_CT_3 + N_CT_2, P_CT_1); assert_eq!(P_CT_2 + N_CT_3, N_CT_1); assert_eq!(N_CT_3 + P_CT_1, N_CT_2); assert_eq!(N_CT_2 + P_CT_3, P_CT_1); assert_eq!(N_CT_2 + N_CT_1, N_CT_3); assert_eq!(CT_1 + P_CT_2, P_CT_3); assert_eq!(P_CT_1 + CT_2, P_CT_3); assert_eq!(CT_3 + N_CT_1, P_CT_2); assert_eq!(N_CT_1 + CT_2, P_CT_1); assert_eq!(P_CT_3 - P_CT_2, P_CT_1); assert_eq!(P_CT_2 - P_CT_3, N_CT_1); assert_eq!(P_CT_2 - N_CT_1, P_CT_3); assert_eq!(N_CT_2 - P_CT_1, N_CT_3); assert_eq!(N_CT_3 - N_CT_1, N_CT_2); assert_eq!(CT_3 - P_CT_2, P_CT_1); assert_eq!(P_CT_3 - CT_2, P_CT_1); assert_eq!(N_CT_2 - CT_1, N_CT_3); assert_eq!(CT_2 - N_CT_1, P_CT_3); assert_eq!(P_CT_1 * 2i64, P_CT_2); assert_eq!(P_CT_1 * -2i64, N_CT_2); assert_eq!(N_CT_1 * 2i64, N_CT_2); assert_eq!(N_CT_1 * -2i64, P_CT_2); assert_eq!(2i64 * P_CT_1, P_CT_2); assert_eq!(-2i64 * P_CT_1, N_CT_2); assert_eq!(P_CT_1 * 2u64, P_CT_2); assert_eq!(N_CT_1 * 2u64, N_CT_2); assert_eq!(P_CT_2 / 2i64, P_CT_1); assert_eq!(P_CT_2 / -2i64, N_CT_1); assert_eq!(N_CT_2 / 2i64, N_CT_1); assert_eq!(N_CT_2 / -2i64, P_CT_1); assert_eq!(P_CT_2 / N_CT_2, Signed::Negative(1)); assert_eq!(P_CT_2 / 2u64, P_CT_1); assert_eq!(N_CT_2 / 2u64, N_CT_1); assert_eq!(P_CT_3 % 2i64, P_CT_1); assert_eq!(P_CT_3 % -2i64, P_CT_1); assert_eq!(N_CT_3 % 2i64, N_CT_1); assert_eq!(N_CT_3 % -2i64, N_CT_1); assert_eq!(N_CT_3 % N_CT_2, N_CT_1); assert_eq!(P_CT_3 % 2u64, P_CT_1); assert_eq!(N_CT_3 % 2u64, N_CT_1); } #[test] fn checked_ops() { assert_eq!(CT_1.checked_add(CT_1), Some(CT_2)); assert_eq!(P_CT_1.checked_add(P_CT_2), Some(P_CT_3)); assert_eq!(P_CT_3.checked_add(N_CT_2), Some(P_CT_1)); assert_eq!(P_CT_2.checked_add(N_CT_3), Some(N_CT_1)); assert_eq!(N_CT_3.checked_add(P_CT_1), Some(N_CT_2)); assert_eq!(N_CT_2.checked_add(P_CT_3), Some(P_CT_1)); assert_eq!(N_CT_2.checked_add(N_CT_1), Some(N_CT_3)); assert_eq!(CT_1.opt_checked_add(CT_1), Ok(Some(CT_2))); assert_eq!(CT_1.opt_checked_add(Some(CT_1)), Ok(Some(CT_2))); assert_eq!(Some(CT_1).opt_checked_add(Some(CT_1)), Ok(Some(CT_2))); assert_eq!(CT_1.opt_checked_add(ClockTime::NONE), Ok(None)); assert_eq!(Some(CT_1).opt_checked_add(ClockTime::NONE), Ok(None)); assert_eq!(CT_1.opt_checked_add(P_CT_1), Ok(Some(P_CT_2))); assert_eq!(N_CT_3.opt_checked_add(CT_1), Ok(Some(N_CT_2))); assert!(ClockTime::MAX.checked_add(CT_1).is_none()); assert_eq!( ClockTime::MAX.opt_checked_add(Some(CT_1)), Err(opt_ops::Error::Overflow) ); assert_eq!(P_CT_1.opt_checked_add(P_CT_1), Ok(Some(P_CT_2))); assert_eq!(P_CT_1.opt_checked_add(Some(N_CT_2)), Ok(Some(N_CT_1))); assert_eq!(Some(P_CT_1).opt_checked_add(Some(P_CT_1)), Ok(Some(P_CT_2))); assert_eq!(P_CT_1.opt_checked_add(ClockTime::NONE), Ok(None)); assert_eq!(Some(N_CT_1).opt_checked_add(ClockTime::NONE), Ok(None)); assert_eq!( ClockTime::MAX.into_positive().opt_checked_add(Some(P_CT_1)), Err(opt_ops::Error::Overflow) ); assert_eq!(CT_2.checked_sub(CT_1), Some(CT_1)); assert_eq!(P_CT_3.checked_sub(P_CT_2), Some(P_CT_1)); assert_eq!(P_CT_2.checked_sub(P_CT_3), Some(N_CT_1)); assert_eq!(P_CT_2.checked_sub(N_CT_1), Some(P_CT_3)); assert_eq!(N_CT_2.checked_sub(P_CT_1), Some(N_CT_3)); assert_eq!(N_CT_3.checked_sub(N_CT_1), Some(N_CT_2)); assert_eq!(N_CT_2.checked_sub(N_CT_3), Some(P_CT_1)); assert_eq!(CT_2.opt_checked_sub(CT_1), Ok(Some(CT_1))); assert_eq!(CT_2.opt_checked_sub(Some(CT_1)), Ok(Some(CT_1))); assert_eq!(Some(CT_2).opt_checked_sub(CT_1), Ok(Some(CT_1))); assert_eq!(Some(CT_2).opt_checked_sub(Some(CT_1)), Ok(Some(CT_1))); assert_eq!(CT_2.opt_checked_sub(ClockTime::NONE), Ok(None)); assert_eq!(Some(CT_2).opt_checked_sub(ClockTime::NONE), Ok(None)); assert_eq!(P_CT_2.opt_checked_sub(CT_1), Ok(Some(P_CT_1))); assert_eq!(N_CT_2.opt_checked_sub(CT_1), Ok(Some(N_CT_3))); assert!(CT_1.checked_sub(CT_2).is_none()); assert_eq!( Some(CT_1).opt_checked_sub(CT_2), Err(opt_ops::Error::Overflow) ); assert_eq!(P_CT_2.opt_checked_sub(Some(N_CT_1)), Ok(Some(P_CT_3))); assert_eq!(Some(N_CT_2).opt_checked_sub(P_CT_1), Ok(Some(N_CT_3))); assert_eq!(CT_1.checked_mul(2), Some(CT_2)); assert_eq!(Some(CT_1).opt_checked_mul(2), Ok(Some(CT_2))); assert_eq!(1u64.opt_checked_mul(Some(CT_2)), Ok(Some(CT_2))); assert_eq!(P_CT_1.checked_mul(2), Some(P_CT_2)); assert_eq!(P_CT_1.checked_mul(-2), Some(N_CT_2)); assert_eq!(N_CT_1.checked_mul(2), Some(N_CT_2)); assert_eq!(N_CT_1.checked_mul(-2), Some(P_CT_2)); assert_eq!(Some(P_CT_1).opt_checked_mul(-2i64), Ok(Some(N_CT_2))); assert_eq!(N_CT_1.opt_checked_mul(2u64), Ok(Some(N_CT_2))); assert_eq!((-2i64).opt_checked_mul(Some(P_CT_1)), Ok(Some(N_CT_2))); assert_eq!(P_CT_1.checked_mul_unsigned(2u64), Some(P_CT_2)); assert_eq!(N_CT_1.checked_mul_unsigned(2u64), Some(N_CT_2)); assert_eq!(CT_3.checked_div(3), Some(CT_1)); assert_eq!(P_CT_3.checked_div(3), Some(P_CT_1)); assert_eq!(P_CT_3.checked_div(-3), Some(N_CT_1)); assert_eq!(N_CT_3.checked_div(3), Some(N_CT_1)); assert_eq!(N_CT_3.checked_div(-3), Some(P_CT_1)); assert_eq!(Some(CT_3).opt_checked_div(CT_3), Ok(Some(1))); assert_eq!(Some(P_CT_3).opt_checked_div(-3i64), Ok(Some(N_CT_1))); assert_eq!(N_CT_3.opt_checked_div(3u64), Ok(Some(N_CT_1))); assert_eq!(P_CT_3.checked_div_unsigned(3u64), Some(P_CT_1)); assert_eq!(N_CT_3.checked_div_unsigned(3u64), Some(N_CT_1)); } #[test] fn overflowing_ops() { assert_eq!(CT_1.overflowing_add(CT_2), (CT_3, false)); assert_eq!(CT_1.opt_overflowing_add(Some(CT_2)), Some((CT_3, false))); assert_eq!(Some(CT_1).opt_overflowing_add(CT_2), Some((CT_3, false))); assert_eq!( Some(CT_1).opt_overflowing_add(Some(CT_2)), Some((CT_3, false)) ); assert_eq!(ClockTime::NONE.opt_overflowing_add(CT_2), None); assert_eq!(CT_1.opt_overflowing_add(ClockTime::NONE), None); assert_eq!( ClockTime::MAX.overflowing_add(CT_1), (ClockTime::ZERO, true) ); assert_eq!( Some(ClockTime::MAX).opt_overflowing_add(Some(CT_1)), Some((ClockTime::ZERO, true)), ); assert_eq!(CT_3.overflowing_sub(CT_2), (CT_1, false)); assert_eq!(CT_3.opt_overflowing_sub(Some(CT_2)), Some((CT_1, false))); assert_eq!(Some(CT_3).opt_overflowing_sub(CT_2), Some((CT_1, false))); assert_eq!( Some(CT_3).opt_overflowing_sub(Some(CT_2)), Some((CT_1, false)) ); assert_eq!( Some(CT_3).opt_overflowing_sub(&Some(CT_2)), Some((CT_1, false)) ); assert_eq!(ClockTime::NONE.opt_overflowing_sub(CT_2), None); assert_eq!(CT_2.opt_overflowing_sub(ClockTime::NONE), None); assert_eq!(CT_1.overflowing_sub(CT_2), (ClockTime::MAX, true)); assert_eq!( Some(CT_1).opt_overflowing_sub(CT_2), Some((ClockTime::MAX, true)) ); } #[test] fn saturating_ops() { let p_ct_max: Signed = ClockTime::MAX.into_positive(); let n_ct_max: Signed = ClockTime::MAX.into_negative(); assert_eq!(CT_1.saturating_add(CT_2), CT_3); assert_eq!(P_CT_1.saturating_add(P_CT_2), P_CT_3); assert_eq!(P_CT_2.saturating_add(N_CT_3), N_CT_1); assert_eq!(P_CT_3.saturating_add(N_CT_2), P_CT_1); assert_eq!(N_CT_3.saturating_add(P_CT_1), N_CT_2); assert_eq!(N_CT_2.saturating_add(P_CT_3), P_CT_1); assert_eq!(N_CT_2.saturating_add(N_CT_1), N_CT_3); assert_eq!(CT_1.opt_saturating_add(Some(CT_2)), Some(CT_3)); assert_eq!(Some(CT_1).opt_saturating_add(Some(CT_2)), Some(CT_3)); assert_eq!(Some(CT_1).opt_saturating_add(ClockTime::NONE), None); assert_eq!(P_CT_1.opt_saturating_add(Some(CT_2)), Some(P_CT_3)); assert_eq!(Some(CT_1).opt_saturating_add(P_CT_2), Some(P_CT_3)); assert_eq!(ClockTime::MAX.saturating_add(CT_1), ClockTime::MAX); assert_eq!( Some(ClockTime::MAX).opt_saturating_add(Some(CT_1)), Some(ClockTime::MAX) ); assert_eq!(p_ct_max.saturating_add(P_CT_1), p_ct_max); assert_eq!(CT_3.saturating_sub(CT_2), CT_1); assert_eq!(P_CT_3.saturating_sub(P_CT_2), P_CT_1); assert_eq!(P_CT_2.saturating_sub(P_CT_3), N_CT_1); assert_eq!(P_CT_2.saturating_sub(N_CT_1), P_CT_3); assert_eq!(N_CT_2.saturating_sub(P_CT_1), N_CT_3); assert_eq!(N_CT_3.saturating_sub(N_CT_1), N_CT_2); assert_eq!(N_CT_2.saturating_sub(N_CT_3), P_CT_1); assert_eq!(CT_3.opt_saturating_sub(Some(CT_2)), Some(CT_1)); assert_eq!(Some(CT_3).opt_saturating_sub(Some(CT_2)), Some(CT_1)); assert_eq!(Some(CT_3).opt_saturating_sub(ClockTime::NONE), None); assert_eq!(P_CT_2.opt_saturating_sub(Some(CT_3)), Some(N_CT_1)); assert_eq!(Some(CT_3).opt_saturating_sub(P_CT_2), Some(P_CT_1)); assert!(CT_1.saturating_sub(CT_2).is_zero()); assert_eq!(P_CT_1.saturating_sub(P_CT_2), N_CT_1); assert_eq!( Some(CT_1).opt_saturating_sub(Some(CT_2)), Some(ClockTime::ZERO) ); assert_eq!(CT_1.saturating_mul(2), CT_2); assert_eq!(ClockTime::MAX.saturating_mul(2), ClockTime::MAX); assert_eq!(P_CT_1.saturating_mul(2), P_CT_2); assert_eq!(P_CT_1.saturating_mul(-2), N_CT_2); assert_eq!(N_CT_1.saturating_mul(2), N_CT_2); assert_eq!(N_CT_1.saturating_mul(-2), P_CT_2); assert_eq!(Some(N_CT_1).opt_saturating_mul(-2i64), Some(P_CT_2)); assert_eq!((-2i64).opt_saturating_mul(Some(N_CT_1)), Some(P_CT_2)); assert_eq!(P_CT_1.saturating_mul_unsigned(2u64), P_CT_2); assert_eq!(N_CT_1.saturating_mul_unsigned(2u64), N_CT_2); assert_eq!(p_ct_max.saturating_mul(2), p_ct_max); assert_eq!(n_ct_max.saturating_mul(2), n_ct_max); assert_eq!(Some(2i64).opt_saturating_mul(p_ct_max), Some(p_ct_max)); assert_eq!(2u64.opt_saturating_mul(Some(n_ct_max)), Some(n_ct_max)); assert_eq!(p_ct_max.saturating_mul_unsigned(2u64), p_ct_max); assert_eq!(n_ct_max.saturating_mul_unsigned(2u64), n_ct_max); } #[test] fn wrapping_ops() { assert_eq!(CT_1.wrapping_add(CT_2), CT_3); assert_eq!(CT_1.opt_wrapping_add(CT_2), Some(CT_3)); assert_eq!(Some(CT_1).opt_wrapping_add(CT_2), Some(CT_3)); assert_eq!(Some(CT_1).opt_wrapping_add(Some(CT_2)), Some(CT_3)); assert_eq!(Some(CT_1).opt_wrapping_add(None), None); assert_eq!(ClockTime::MAX.wrapping_add(CT_1), ClockTime::ZERO); assert_eq!( Some(ClockTime::MAX).opt_wrapping_add(Some(CT_1)), Some(ClockTime::ZERO) ); assert_eq!(CT_3.wrapping_sub(CT_2), CT_1); assert_eq!(CT_3.opt_wrapping_sub(CT_2), Some(CT_1)); assert_eq!(Some(CT_3).opt_wrapping_sub(CT_2), Some(CT_1)); assert_eq!(Some(CT_3).opt_wrapping_sub(Some(CT_2)), Some(CT_1)); assert_eq!(Some(CT_3).opt_wrapping_sub(ClockTime::NONE), None); assert_eq!(CT_1.wrapping_sub(CT_2), ClockTime::MAX); assert_eq!( Some(CT_1).opt_wrapping_sub(Some(CT_2)), Some(ClockTime::MAX) ); } #[test] fn mul_div_ops() { use muldiv::MulDiv; assert_eq!(CT_1.mul_div_floor(7, 3), Some(CT_2)); assert_eq!(P_CT_1.mul_div_floor(7u64, 3), Some(P_CT_2)); assert_eq!(P_CT_1.mul_div_floor(-7i64, 3), Some(N_CT_2)); assert_eq!(P_CT_1.mul_div_floor(7i64, -3), Some(N_CT_2)); assert_eq!(P_CT_1.mul_div_floor(-7i64, -3), Some(P_CT_2)); assert_eq!(N_CT_1.mul_div_floor(7u64, 3), Some(N_CT_2)); assert_eq!(N_CT_1.mul_div_floor(-7i64, 3), Some(P_CT_2)); assert_eq!(N_CT_1.mul_div_floor(7i64, -3), Some(P_CT_2)); assert_eq!(N_CT_1.mul_div_floor(-7i64, -3), Some(N_CT_2)); assert_eq!(CT_1.mul_div_round(10, 3), Some(CT_3)); assert_eq!(CT_1.mul_div_round(8, 3), Some(CT_3)); assert_eq!(P_CT_1.mul_div_round(10u64, 3), Some(P_CT_3)); assert_eq!(P_CT_1.mul_div_round(8u64, 3), Some(P_CT_3)); assert_eq!(P_CT_1.mul_div_round(-10i64, 3), Some(N_CT_3)); assert_eq!(P_CT_1.mul_div_round(-8i64, 3), Some(N_CT_3)); assert_eq!(P_CT_1.mul_div_round(10i64, -3), Some(N_CT_3)); assert_eq!(P_CT_1.mul_div_round(-10i64, -3), Some(P_CT_3)); assert_eq!(N_CT_1.mul_div_round(10u64, 3), Some(N_CT_3)); assert_eq!(N_CT_1.mul_div_round(-10i64, 3), Some(P_CT_3)); assert_eq!(N_CT_1.mul_div_round(10i64, -3), Some(P_CT_3)); assert_eq!(N_CT_1.mul_div_round(-10i64, -3), Some(N_CT_3)); assert_eq!(CT_1.mul_div_ceil(7, 3), Some(CT_3)); assert_eq!(P_CT_1.mul_div_ceil(7u64, 3), Some(P_CT_3)); assert_eq!(P_CT_1.mul_div_ceil(-7i64, 3), Some(N_CT_3)); assert_eq!(P_CT_1.mul_div_ceil(7i64, -3), Some(N_CT_3)); assert_eq!(P_CT_1.mul_div_ceil(-7i64, -3), Some(P_CT_3)); assert_eq!(N_CT_1.mul_div_ceil(7u64, 3), Some(N_CT_3)); assert_eq!(N_CT_1.mul_div_ceil(-7i64, 3), Some(P_CT_3)); assert_eq!(N_CT_1.mul_div_ceil(7i64, -3), Some(P_CT_3)); assert_eq!(N_CT_1.mul_div_ceil(-7i64, -3), Some(N_CT_3)); } #[test] #[allow(clippy::nonminimal_bool)] fn comp() { assert!(ClockTime::ZERO < CT_2); assert!(Some(ClockTime::ZERO) < Some(CT_2)); assert!(CT_2 < CT_3); assert!(Some(CT_2) < Some(CT_3)); assert!(ClockTime::ZERO < CT_3); assert!(Some(ClockTime::ZERO) < Some(CT_3)); assert_eq!(CT_2, CT_2); assert_ne!(CT_3, CT_2); assert!(ClockTime::ZERO.into_positive() < P_CT_1); assert!(ClockTime::ZERO.into_positive() > N_CT_1); assert!(P_CT_1 < P_CT_2); assert!(P_CT_1 > N_CT_2); assert!(N_CT_1 < P_CT_2); assert!(N_CT_3 < N_CT_2); assert!(P_CT_1 < CT_2); assert!(CT_1 < P_CT_2); assert!(N_CT_2 < CT_1); assert!(CT_1 > N_CT_2); assert_eq!(CT_2, P_CT_2); assert_ne!(N_CT_3, CT_3); assert_eq!(Some(CT_2).opt_lt(Some(CT_3)), Some(true)); assert_eq!(Some(CT_3).opt_lt(CT_2), Some(false)); assert_eq!(Some(CT_2).opt_le(Some(CT_3)), Some(true)); assert_eq!(Some(CT_3).opt_le(CT_3), Some(true)); assert_eq!(Some(P_CT_2).opt_lt(Some(P_CT_3)), Some(true)); assert_eq!(Some(P_CT_3).opt_lt(P_CT_2), Some(false)); assert_eq!(Some(P_CT_2).opt_le(Some(P_CT_3)), Some(true)); assert_eq!(Some(P_CT_3).opt_le(P_CT_3), Some(true)); assert_eq!(Some(P_CT_0).opt_lt(P_CT_NONE), None); assert_eq!(P_CT_NONE.opt_lt(P_CT_0), None); assert_eq!(Some(N_CT_3).opt_lt(Some(N_CT_2)), Some(true)); assert_eq!(Some(N_CT_2).opt_lt(N_CT_3), Some(false)); assert_eq!(Some(N_CT_3).opt_le(Some(N_CT_2)), Some(true)); assert_eq!(Some(N_CT_3).opt_le(N_CT_3), Some(true)); assert_eq!(Some(P_CT_2).opt_lt(N_CT_3), Some(false)); assert_eq!(Some(N_CT_3).opt_lt(Some(P_CT_2)), Some(true)); assert!(CT_3 > CT_2); assert!(Some(CT_3) > Some(CT_2)); assert!(CT_2 > ClockTime::ZERO); assert!(Some(CT_2) > Some(ClockTime::ZERO)); assert!(CT_3 > ClockTime::ZERO); assert!(Some(CT_3) > Some(ClockTime::ZERO)); assert!(!(ClockTime::NONE > None)); // This doesn't work due to the `PartialOrd` impl on `Option` //assert_eq!(Some(ClockTime::ZERO) > ClockTime::ZERO, false); assert!(!(Some(ClockTime::ZERO) < ClockTime::NONE)); assert_eq!(Some(CT_3).opt_gt(Some(CT_2)), Some(true)); assert_eq!(Some(CT_3).opt_ge(Some(CT_2)), Some(true)); assert_eq!(Some(CT_3).opt_ge(CT_3), Some(true)); assert_eq!(Some(P_CT_3).opt_gt(Some(P_CT_2)), Some(true)); assert_eq!(Some(P_CT_3).opt_ge(Some(P_CT_2)), Some(true)); assert_eq!(Some(P_CT_3).opt_ge(P_CT_3), Some(true)); assert_eq!(Some(P_CT_0).opt_gt(P_CT_NONE), None); assert_eq!(P_CT_NONE.opt_gt(P_CT_0), None); assert_eq!(Some(N_CT_3).opt_gt(Some(N_CT_2)), Some(false)); assert_eq!(Some(N_CT_3).opt_ge(Some(N_CT_2)), Some(false)); assert_eq!(Some(N_CT_3).opt_ge(N_CT_3), Some(true)); assert_eq!(Some(P_CT_2).opt_gt(N_CT_3), Some(true)); assert_eq!(Some(N_CT_3).opt_gt(Some(P_CT_2)), Some(false)); assert!(!(ClockTime::NONE < None)); assert!(!(ClockTime::NONE > None)); // This doesn't work due to the `PartialOrd` impl on `Option` //assert!(Some(ClockTime::ZERO) > ClockTime::NONE, false); // Use opt_gt instead. assert_eq!(Some(ClockTime::ZERO).opt_gt(ClockTime::NONE), None); assert_eq!(ClockTime::ZERO.opt_gt(ClockTime::NONE), None); assert_eq!(ClockTime::ZERO.opt_ge(ClockTime::NONE), None); assert_eq!(ClockTime::NONE.opt_gt(Some(ClockTime::ZERO)), None); assert_eq!(ClockTime::NONE.opt_gt(ClockTime::ZERO), None); assert_eq!(ClockTime::NONE.opt_ge(ClockTime::ZERO), None); assert!(!(Some(ClockTime::ZERO) < ClockTime::NONE)); assert_eq!(Some(ClockTime::ZERO).opt_lt(ClockTime::NONE), None); assert_eq!(Some(ClockTime::ZERO).opt_le(ClockTime::NONE), None); assert_eq!(CT_3.opt_min(CT_2), Some(CT_2)); assert_eq!(CT_3.opt_min(Some(CT_2)), Some(CT_2)); assert_eq!(Some(CT_3).opt_min(Some(CT_2)), Some(CT_2)); assert_eq!(ClockTime::NONE.opt_min(Some(CT_2)), None); assert_eq!(Some(CT_3).opt_min(ClockTime::NONE), None); assert_eq!(P_CT_3.opt_min(P_CT_2), Some(P_CT_2)); assert_eq!(P_CT_2.opt_min(P_CT_3), Some(P_CT_2)); assert_eq!(N_CT_3.opt_min(N_CT_2), Some(N_CT_3)); assert_eq!(N_CT_2.opt_min(N_CT_3), Some(N_CT_3)); assert_eq!(P_CT_2.opt_min(N_CT_3), Some(N_CT_3)); assert_eq!(CT_3.opt_max(CT_2), Some(CT_3)); assert_eq!(CT_3.opt_max(Some(CT_2)), Some(CT_3)); assert_eq!(Some(CT_3).opt_max(Some(CT_2)), Some(CT_3)); assert_eq!(ClockTime::NONE.opt_max(Some(CT_2)), None); assert_eq!(Some(CT_3).opt_max(ClockTime::NONE), None); assert_eq!(P_CT_3.opt_max(P_CT_2), Some(P_CT_3)); assert_eq!(P_CT_2.opt_max(P_CT_3), Some(P_CT_3)); assert_eq!(N_CT_3.opt_max(N_CT_2), Some(N_CT_2)); assert_eq!(N_CT_2.opt_max(N_CT_3), Some(N_CT_2)); assert_eq!(P_CT_2.opt_max(N_CT_3), Some(P_CT_2)); } #[test] fn display() { let none = Option::::None; let some = Some(45_834_908_569_837 * ClockTime::NSECOND); let lots = ClockTime::from_nseconds(u64::MAX - 1); // Simple assert_eq!(format!("{:.0}", DisplayableOptClockTime(none)), "--:--:--"); assert_eq!( format!("{:.3}", DisplayableOptClockTime(none)), "--:--:--.---" ); assert_eq!( format!("{}", DisplayableOptClockTime(none)), "--:--:--.---------" ); assert_eq!(format!("{:.0}", DisplayableOptClockTime(some)), "12:43:54"); assert_eq!( format!("{:.3}", DisplayableOptClockTime(some)), "12:43:54.908" ); assert_eq!( format!("{}", DisplayableOptClockTime(some)), "12:43:54.908569837" ); assert_eq!(format!("{lots:.0}"), "5124095:34:33"); assert_eq!(format!("{lots:.3}"), "5124095:34:33.709"); assert_eq!(format!("{lots}"), "5124095:34:33.709551614"); // Precision caps at 9 assert_eq!( format!("{:.10}", DisplayableOptClockTime(none)), "--:--:--.---------" ); assert_eq!( format!("{:.10}", DisplayableOptClockTime(some)), "12:43:54.908569837" ); assert_eq!(format!("{lots:.10}"), "5124095:34:33.709551614"); // Short width assert_eq!(format!("{:4.0}", DisplayableOptClockTime(none)), "--:--:--"); assert_eq!( format!("{:4.3}", DisplayableOptClockTime(none)), "--:--:--.---" ); assert_eq!( format!("{:4}", DisplayableOptClockTime(none)), "--:--:--.---------" ); assert_eq!(format!("{:4.0}", DisplayableOptClockTime(some)), "12:43:54"); assert_eq!( format!("{:4.3}", DisplayableOptClockTime(some)), "12:43:54.908" ); assert_eq!( format!("{:4}", DisplayableOptClockTime(some)), "12:43:54.908569837" ); assert_eq!(format!("{lots:4.0}"), "5124095:34:33"); assert_eq!(format!("{lots:4.3}"), "5124095:34:33.709"); assert_eq!(format!("{lots:4}"), "5124095:34:33.709551614"); // Simple padding assert_eq!( format!("{:>9.0}", DisplayableOptClockTime(none)), " --:--:--" ); assert_eq!( format!("{:<9.0}", DisplayableOptClockTime(none)), "--:--:-- " ); assert_eq!( format!("{:^10.0}", DisplayableOptClockTime(none)), " --:--:-- " ); assert_eq!( format!("{:>13.3}", DisplayableOptClockTime(none)), " --:--:--.---" ); assert_eq!( format!("{:<13.3}", DisplayableOptClockTime(none)), "--:--:--.--- " ); assert_eq!( format!("{:^14.3}", DisplayableOptClockTime(none)), " --:--:--.--- " ); assert_eq!( format!("{:>19}", DisplayableOptClockTime(none)), " --:--:--.---------" ); assert_eq!( format!("{:<19}", DisplayableOptClockTime(none)), "--:--:--.--------- " ); assert_eq!( format!("{:^20}", DisplayableOptClockTime(none)), " --:--:--.--------- " ); assert_eq!( format!("{:>9.0}", DisplayableOptClockTime(some)), " 12:43:54" ); assert_eq!( format!("{:<9.0}", DisplayableOptClockTime(some)), "12:43:54 " ); assert_eq!( format!("{:^10.0}", DisplayableOptClockTime(some)), " 12:43:54 " ); assert_eq!( format!("{:>13.3}", DisplayableOptClockTime(some)), " 12:43:54.908" ); assert_eq!( format!("{:<13.3}", DisplayableOptClockTime(some)), "12:43:54.908 " ); assert_eq!( format!("{:^14.3}", DisplayableOptClockTime(some)), " 12:43:54.908 " ); assert_eq!( format!("{:>19}", DisplayableOptClockTime(some)), " 12:43:54.908569837" ); assert_eq!( format!("{:<19}", DisplayableOptClockTime(some)), "12:43:54.908569837 " ); assert_eq!( format!("{:^20}", DisplayableOptClockTime(some)), " 12:43:54.908569837 " ); assert_eq!(format!("{lots:>14.0}"), " 5124095:34:33"); assert_eq!(format!("{lots:<14.0}"), "5124095:34:33 "); assert_eq!(format!("{lots:^15.0}"), " 5124095:34:33 "); assert_eq!(format!("{lots:>18.3}"), " 5124095:34:33.709"); assert_eq!(format!("{lots:<18.3}"), "5124095:34:33.709 "); assert_eq!(format!("{lots:^19.3}"), " 5124095:34:33.709 "); assert_eq!(format!("{lots:>24}"), " 5124095:34:33.709551614"); assert_eq!(format!("{lots:<24}"), "5124095:34:33.709551614 "); assert_eq!(format!("{lots:^25}"), " 5124095:34:33.709551614 "); // Padding with sign or zero-extension assert_eq!( format!("{:+11.0}", DisplayableOptClockTime(none)), " --:--:--" ); assert_eq!( format!("{:011.0}", DisplayableOptClockTime(none)), "-----:--:--" ); assert_eq!( format!("{:+011.0}", DisplayableOptClockTime(none)), "-----:--:--" ); assert_eq!( format!("{:+15.3}", DisplayableOptClockTime(none)), " --:--:--.---" ); assert_eq!( format!("{:015.3}", DisplayableOptClockTime(none)), "-----:--:--.---" ); assert_eq!( format!("{:+015.3}", DisplayableOptClockTime(none)), "-----:--:--.---" ); assert_eq!( format!("{:+21}", DisplayableOptClockTime(none)), " --:--:--.---------" ); assert_eq!( format!("{:021}", DisplayableOptClockTime(none)), "-----:--:--.---------" ); assert_eq!( format!("{:+021}", DisplayableOptClockTime(none)), "-----:--:--.---------" ); assert_eq!( format!("{:+11.0}", DisplayableOptClockTime(some)), " +12:43:54" ); assert_eq!( format!("{:011.0}", DisplayableOptClockTime(some)), "00012:43:54" ); assert_eq!( format!("{:+011.0}", DisplayableOptClockTime(some)), "+0012:43:54" ); assert_eq!( format!("{:+15.3}", DisplayableOptClockTime(some)), " +12:43:54.908" ); assert_eq!( format!("{:015.3}", DisplayableOptClockTime(some)), "00012:43:54.908" ); assert_eq!( format!("{:+015.3}", DisplayableOptClockTime(some)), "+0012:43:54.908" ); assert_eq!( format!("{:+21}", DisplayableOptClockTime(some)), " +12:43:54.908569837" ); assert_eq!( format!("{:021}", DisplayableOptClockTime(some)), "00012:43:54.908569837" ); assert_eq!( format!("{:+021}", DisplayableOptClockTime(some)), "+0012:43:54.908569837" ); assert_eq!(format!("{lots:+16.0}"), " +5124095:34:33"); assert_eq!(format!("{lots:016.0}"), "0005124095:34:33"); assert_eq!(format!("{lots:+016.0}"), "+005124095:34:33"); assert_eq!(format!("{lots:+20.3}"), " +5124095:34:33.709"); assert_eq!(format!("{lots:020.3}"), "0005124095:34:33.709"); assert_eq!(format!("{lots:+020.3}"), "+005124095:34:33.709"); assert_eq!(format!("{lots:+26}"), " +5124095:34:33.709551614"); assert_eq!(format!("{lots:026}"), "0005124095:34:33.709551614"); assert_eq!(format!("{lots:+026}"), "+005124095:34:33.709551614"); } #[test] fn iter_sum() { let s: ClockTime = vec![ClockTime::from_seconds(1), ClockTime::from_seconds(2)] .into_iter() .sum(); assert_eq!(s, ClockTime::from_seconds(3)); } #[test] #[should_panic] fn attempt_to_build_from_clock_time_none() { let _ = ClockTime::from_nseconds(ffi::GST_CLOCK_TIME_NONE); } #[test] #[should_panic] fn attempt_to_build_from_u64max() { let _ = ClockTime::from_nseconds(u64::MAX); } #[test] fn try_into_signed() { let time = crate::Signed::Positive(ClockTime::from_nseconds(0)); assert_eq!(i64::try_from(time), Ok(0)); let time = crate::Signed::Positive(ClockTime::from_nseconds(123)); assert_eq!(i64::try_from(time), Ok(123)); let time = crate::Signed::Positive(ClockTime::from_nseconds(u64::MAX - 1)); assert!(i64::try_from(time).is_err()); let time = crate::Signed::Positive(ClockTime::from_nseconds(u64::MAX >> 1)); assert_eq!(i64::MAX as i128, (u64::MAX >> 1) as i128); assert_eq!(i64::try_from(time), Ok(i64::MAX)); let time = crate::Signed::Negative(ClockTime::from_nseconds(0)); assert_eq!(i64::try_from(time), Ok(0)); let time = crate::Signed::Negative(ClockTime::from_nseconds(123)); assert_eq!(i64::try_from(time), Ok(-123)); let time = crate::Signed::Negative(ClockTime::from_nseconds(u64::MAX - 1)); assert!(i64::try_from(time).is_err()); let time = crate::Signed::Negative(ClockTime::from_nseconds(u64::MAX >> 1)); assert_eq!(i64::MIN as i128 + 1, -((u64::MAX >> 1) as i128)); assert_eq!(i64::try_from(time), Ok(i64::MIN + 1)); let time = crate::Signed::Negative(ClockTime::from_nseconds((u64::MAX >> 1) + 1)); assert_eq!(i64::MIN as i128, -(((u64::MAX >> 1) + 1) as i128)); assert_eq!(i64::try_from(time), Ok(i64::MIN)); } #[test] fn properties_macro_usage() { use super::ClockTime; use glib::{prelude::*, subclass::prelude::*}; use std::cell::Cell; #[derive(Default, glib::Properties)] #[properties(wrapper_type = TestObject)] pub struct TestObjectImp { #[property(get, set)] clock_time: Cell, #[property(get, set)] optional_clock_time: Cell>, } #[glib::object_subclass] impl ObjectSubclass for TestObjectImp { const NAME: &'static str = "GstTestObject"; type Type = TestObject; } impl ObjectImpl for TestObjectImp { fn properties() -> &'static [glib::ParamSpec] { Self::derived_properties() } fn set_property(&self, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { self.derived_set_property(id, value, pspec); } fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value { self.derived_property(id, pspec) } } glib::wrapper! { pub struct TestObject(ObjectSubclass); } let obj: TestObject = glib::Object::new(); assert_eq!(obj.clock_time(), ClockTime::default()); obj.set_clock_time(ClockTime::MAX); assert_eq!(obj.clock_time(), ClockTime::MAX); assert_eq!(obj.optional_clock_time(), None); obj.set_optional_clock_time(ClockTime::MAX); assert_eq!(obj.optional_clock_time(), Some(ClockTime::MAX)); } #[test] fn seconds_float() { let res = ClockTime::ZERO; assert_eq!(res.seconds_f32(), 0.0); assert_eq!(res.seconds_f64(), 0.0); let res = ClockTime::from_nseconds(2_700_000_000); assert_eq!(res.seconds_f32(), 2.7); assert_eq!(res.seconds_f64(), 2.7); let res = ClockTime::MAX; assert_eq!(res.seconds_f32(), 18_446_744_073.709_553); assert_eq!(res.seconds_f64(), 18_446_744_073.709_553); } #[test] fn seconds_float_signed() { let pos = Signed::Positive(ClockTime::ZERO); assert_eq!(pos.seconds_f32(), 0.0); assert_eq!(pos.seconds_f64(), 0.0); let neg = Signed::Negative(ClockTime::ZERO); assert_eq!(neg.seconds_f32(), 0.0); assert_eq!(neg.seconds_f64(), 0.0); let pos = Signed::Positive(ClockTime::from_nseconds(2_700_000_000)); assert_eq!(pos.seconds_f32(), 2.7); assert_eq!(pos.seconds_f64(), 2.7); let neg = Signed::Negative(ClockTime::from_nseconds(2_700_000_000)); assert_eq!(neg.seconds_f32(), -2.7); assert_eq!(neg.seconds_f64(), -2.7); let pos = Signed::Positive(ClockTime::MAX); assert_eq!(pos.seconds_f32(), 18_446_744_073.709_553); assert_eq!(pos.seconds_f64(), 18_446_744_073.709_553); let neg = Signed::Negative(ClockTime::MAX); assert_eq!(neg.seconds_f32(), -18_446_744_073.709_553); assert_eq!(neg.seconds_f64(), -18_446_744_073.709_553); } #[test] fn try_from_seconds_f32() { let res = ClockTime::try_from_seconds_f32(0.0); assert_eq!(res, Ok(ClockTime::ZERO)); let res = ClockTime::try_from_seconds_f32(1e-20); assert_eq!(res, Ok(ClockTime::ZERO)); let res = ClockTime::try_from_seconds_f32(4.2e-7); assert_eq!(res, Ok(ClockTime::from_nseconds(420))); let res = ClockTime::try_from_seconds_f32(2.7); assert_eq!(res, Ok(ClockTime::from_nseconds(2_700_000_048))); // subnormal float: let res = ClockTime::try_from_seconds_f32(f32::from_bits(1)); assert_eq!(res, Ok(ClockTime::ZERO)); // the conversion uses rounding with tie resolution to even let res = ClockTime::try_from_seconds_f32(0.999e-9); assert_eq!(res, Ok(ClockTime::from_nseconds(1))); let res = ClockTime::try_from_seconds_f32(-5.0); assert!(res.is_err()); let res = ClockTime::try_from_seconds_f32(f32::NAN); assert!(res.is_err()); let res = ClockTime::try_from_seconds_f32(2e19); assert!(res.is_err()); // this float represents exactly 976562.5e-9 let val = f32::from_bits(0x3A80_0000); let res = ClockTime::try_from_seconds_f32(val); assert_eq!(res, Ok(ClockTime::from_nseconds(976_562))); // this float represents exactly 2929687.5e-9 let val = f32::from_bits(0x3B40_0000); let res = ClockTime::try_from_seconds_f32(val); assert_eq!(res, Ok(ClockTime::from_nseconds(2_929_688))); // this float represents exactly 1.000_976_562_5 let val = f32::from_bits(0x3F802000); let res = ClockTime::try_from_seconds_f32(val); assert_eq!(res, Ok(ClockTime::from_nseconds(1_000_976_562))); // this float represents exactly 1.002_929_687_5 let val = f32::from_bits(0x3F806000); let res = ClockTime::try_from_seconds_f32(val); assert_eq!(res, Ok(ClockTime::from_nseconds(1_002_929_688))); } #[test] fn try_from_seconds_f64() { let res = ClockTime::try_from_seconds_f64(0.0); assert_eq!(res, Ok(ClockTime::ZERO)); let res = ClockTime::try_from_seconds_f64(1e-20); assert_eq!(res, Ok(ClockTime::ZERO)); let res = ClockTime::try_from_seconds_f64(4.2e-7); assert_eq!(res, Ok(ClockTime::from_nseconds(420))); let res = ClockTime::try_from_seconds_f64(2.7); assert_eq!(res, Ok(ClockTime::from_nseconds(2_700_000_000))); // subnormal float: let res = ClockTime::try_from_seconds_f64(f64::from_bits(1)); assert_eq!(res, Ok(ClockTime::ZERO)); // the conversion uses rounding with tie resolution to even let res = ClockTime::try_from_seconds_f64(0.999e-9); assert_eq!(res, Ok(ClockTime::from_nseconds(1))); let res = ClockTime::try_from_seconds_f64(0.999_999_999_499); assert_eq!(res, Ok(ClockTime::from_nseconds(999_999_999))); let res = ClockTime::try_from_seconds_f64(0.999_999_999_501); assert_eq!(res, Ok(ClockTime::from_seconds(1))); let res = ClockTime::try_from_seconds_f64(42.999_999_999_499); assert_eq!(res, Ok(ClockTime::from_nseconds(42_999_999_999))); let res = ClockTime::try_from_seconds_f64(42.999_999_999_501); assert_eq!(res, Ok(ClockTime::from_seconds(43))); let res = ClockTime::try_from_seconds_f64(-5.0); assert!(res.is_err()); let res = ClockTime::try_from_seconds_f64(f64::NAN); assert!(res.is_err()); let res = ClockTime::try_from_seconds_f64(2e19); assert!(res.is_err()); // this float represents exactly 976562.5e-9 let val = f64::from_bits(0x3F50_0000_0000_0000); let res = ClockTime::try_from_seconds_f64(val); assert_eq!(res, Ok(ClockTime::from_nseconds(976_562))); // this float represents exactly 2929687.5e-9 let val = f64::from_bits(0x3F68_0000_0000_0000); let res = ClockTime::try_from_seconds_f64(val); assert_eq!(res, Ok(ClockTime::from_nseconds(2_929_688))); // this float represents exactly 1.000_976_562_5 let val = f64::from_bits(0x3FF0_0400_0000_0000); let res = ClockTime::try_from_seconds_f64(val); assert_eq!(res, Ok(ClockTime::from_nseconds(1_000_976_562))); // this float represents exactly 1.002_929_687_5 let val = f64::from_bits(0x3FF0_0C00_0000_0000); let res = ClockTime::try_from_seconds_f64(val); assert_eq!(res, Ok(ClockTime::from_nseconds(1_002_929_688))); } #[test] fn try_from_seconds_f32_signed() { let pos = Signed::::from_seconds_f32(5.0); assert!(pos.is_positive()); let neg = Signed::::from_seconds_f32(-5.0); assert!(neg.is_negative()); } #[test] fn try_from_seconds_f64_signed() { let pos = Signed::::from_seconds_f64(5.0); assert!(pos.is_positive()); let neg = Signed::::from_seconds_f64(-5.0); assert!(neg.is_negative()); } #[test] fn absdiff() { let t1 = ClockTime::from_seconds(10); let t2 = ClockTime::from_seconds(4); let d = ClockTime::from_seconds(6); assert_eq!(t1.absdiff(t2), d); assert_eq!(t2.absdiff(t1), d); } } gstreamer-0.23.5/src/format/clock_time_serde.rs000064400000000000000000000102141046102023000176220ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use serde::{ de::{Deserialize, Deserializer}, ser::{Serialize, Serializer}, }; use crate::ClockTime; impl Serialize for ClockTime { fn serialize(&self, serializer: S) -> Result { use std::ops::Deref; self.deref().serialize(serializer) } } impl<'de> Deserialize<'de> for ClockTime { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); u64::deserialize(deserializer).and_then(|value| { ClockTime::try_from(value).map_err(|_| { use serde::de::{Error, Unexpected}; D::Error::invalid_value(Unexpected::Unsigned(value), &"valid `ClockTime`") }) }) } } #[cfg(test)] mod tests { use crate::ClockTime; #[test] fn test_serialize() { crate::init().unwrap(); // Some let clocktime = Some(ClockTime::from_nseconds(42_123_456_789)); let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string()); let res = ron::ser::to_string_pretty(&clocktime, pretty_config.clone()); assert_eq!(Ok("Some(42123456789)".to_owned()), res); let res = serde_json::to_string(&clocktime).unwrap(); assert_eq!("42123456789".to_owned(), res); // None let clocktime = ClockTime::NONE; let res = ron::ser::to_string_pretty(&clocktime, pretty_config); assert_eq!(Ok("None".to_owned()), res); let res = serde_json::to_string(&clocktime).unwrap(); assert_eq!("null".to_owned(), res); } #[test] fn test_deserialize() { crate::init().unwrap(); // Some let clocktime_ron = "Some(42123456789)"; let clocktime: Option = ron::de::from_str(clocktime_ron).unwrap(); let clocktime = clocktime.unwrap(); assert_eq!(clocktime.seconds(), 42); assert_eq!(clocktime.mseconds(), 42_123); assert_eq!(clocktime.useconds(), 42_123_456); assert_eq!(clocktime.nseconds(), 42_123_456_789); let clocktime_json = "42123456789"; let clocktime: Option = serde_json::from_str(clocktime_json).unwrap(); let clocktime = clocktime.unwrap(); assert_eq!(clocktime.seconds(), 42); assert_eq!(clocktime.mseconds(), 42_123); assert_eq!(clocktime.useconds(), 42_123_456); assert_eq!(clocktime.nseconds(), 42_123_456_789); // None let clocktime_ron = "None"; let clocktime: Option = ron::de::from_str(clocktime_ron).unwrap(); assert!(clocktime.is_none()); let clocktime_json = "null"; let clocktime: Option = serde_json::from_str(clocktime_json).unwrap(); assert!(clocktime.is_none()); assert!(clocktime.is_none()); } #[test] fn test_serde_roundtrip() { crate::init().unwrap(); // Direct let clocktime = ClockTime::from_nseconds(42_123_456_789); let clocktime_ser = ron::ser::to_string(&clocktime).unwrap(); let clocktime: ClockTime = ron::de::from_str(clocktime_ser.as_str()).unwrap(); assert_eq!(clocktime.seconds(), 42); assert_eq!(clocktime.mseconds(), 42_123); assert_eq!(clocktime.useconds(), 42_123_456); assert_eq!(clocktime.nseconds(), 42_123_456_789); // Some let clocktime = Some(ClockTime::from_nseconds(42_123_456_789)); let clocktime_ser = ron::ser::to_string(&clocktime).unwrap(); let clocktime: Option = ron::de::from_str(clocktime_ser.as_str()).unwrap(); let clocktime = clocktime.unwrap(); assert_eq!(clocktime.seconds(), 42); assert_eq!(clocktime.mseconds(), 42_123); assert_eq!(clocktime.useconds(), 42_123_456); assert_eq!(clocktime.nseconds(), 42_123_456_789); // None let clocktime = ClockTime::NONE; let clocktime_ser = ron::ser::to_string(&clocktime).unwrap(); let clocktime: Option = ron::de::from_str(clocktime_ser.as_str()).unwrap(); assert!(clocktime.is_none()); } } gstreamer-0.23.5/src/format/compatible.rs000064400000000000000000000142211046102023000164500ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use super::{ Format, FormattedValue, FormattedValueError, GenericFormattedValue, SpecificFormattedValue, }; // rustdoc-stripper-ignore-next /// A trait implemented on types which can hold [`FormattedValue`]s compatible with parameter `F`. /// /// This trait is auto-implemented based on [`FormattedValue`]s additional traits /// such as [`SpecificFormattedValue`]. /// /// # Example /// /// Consider the following function: /// /// ```rust /// # use gstreamer::format::{ClockTime, CompatibleFormattedValue, FormattedValue, GenericFormattedValue}; /// fn with_compatible_formats( /// arg1: V, /// arg2: impl CompatibleFormattedValue, /// ) { /// // This is required to access arg2 as a FormattedValue: /// let _arg2 = arg2.try_into_checked(arg1).unwrap(); /// } /// /// // This is Ok because arg1 is a ClockTime and arg2 is /// // an Option which are compatible format-wise. /// with_compatible_formats(ClockTime::ZERO, ClockTime::NONE); /// /// // This is Ok because arg1 is a ClockTime and arg2 is /// // a GenericFormattedValue which are compatible format-wise. /// with_compatible_formats( /// ClockTime::ZERO, /// GenericFormattedValue::Time(None), /// ); /// ``` /// /// Users are able to call the function with arguments: /// /// 1. of the same type (e.g. `ClockTime`), /// 2. of different types, but able to hold a value of the same [`Format`] /// (e.g. `ClockTime` and `Option`). /// 3. One of a Formatted Value (specific or generic), the other being /// a `GenericFormattedValue`. /// /// Format compatibility for cases 1 and 2 is enforced by /// the type system, while case 3 will be checked at runtime time. /// /// ```compile_fail /// # use gstreamer::{ClockTime, CompatibleFormattedValue, FormattedValue, format::Bytes}; /// # fn with_compatible_formats( /// # arg1: V, /// # arg2: impl CompatibleFormattedValue, /// # ) {} /// // This doesn't compile because the arguments are not compatible: /// let _ = with_compatible_formats(ClockTime::ZERO, Bytes(Some(42))); /// ``` /// /// Note: users will not be able use `arg2` directly unless format /// check succeeds: /// /// ```compile_fail /// # use gstreamer::{CompatibleFormattedValue, FormattedValue}; /// fn with_compatible_formats( /// arg1: V, /// arg2: impl CompatibleFormattedValue, /// ) { /// // This doesn't compile because arg2 hasn't been checked: /// let _format = arg2.format(); /// } /// ``` pub trait CompatibleFormattedValue { type Original: FormattedValue; // rustdoc-stripper-ignore-next /// Returns `Ok(self)` with its type restored if it is compatible with the format of `other`. /// /// When used with compatible [`SpecificFormattedValue`]s, checks /// are enforced by the type system, no runtime checks are performed. /// /// When used with [`FormattedValue`] / [`GenericFormattedValue`] and /// vice versa, a runtime format check is performed. If the check fails, /// `Err(FormattedValueError)` is returned. fn try_into_checked(self, other: V) -> Result; // rustdoc-stripper-ignore-next /// Returns `Ok(self)` with its type restored if it is compatible with the format of `V`. /// /// When possible, prefer using [`Self::try_into_checked`] which /// reduces the risk of misuse. /// /// When used with compatible [`SpecificFormattedValue`]s, checks /// are enforced by the type system, no runtime checks are performed. /// /// When used with [`SpecificFormattedValue`] as a parameter and /// a [`GenericFormattedValue`] as `Self`, a runtime check is performed /// against the default format of the parameter. If the check fails, /// `Err(FormattedValueError)` is returned. /// /// When used with [`GenericFormattedValue`] as a parameter and /// a [`SpecificFormattedValue`] as `Self`, the `format` argument /// used. If the check fails, `Err(FormattedValueError)` is returned. fn try_into_checked_explicit( self, format: Format, ) -> Result; } impl CompatibleFormattedValue for T where V: SpecificFormattedValue, T: SpecificFormattedValue, { type Original = Self; #[inline] fn try_into_checked(self, _other: V) -> Result { skip_assert_initialized!(); Ok(self) } #[inline] fn try_into_checked_explicit( self, _format: Format, ) -> Result { skip_assert_initialized!(); Ok(self) } } impl CompatibleFormattedValue for T { type Original = Self; #[inline] fn try_into_checked(self, other: GenericFormattedValue) -> Result { skip_assert_initialized!(); if self.format() == other.format() { Ok(self) } else { Err(FormattedValueError(self.format())) } } #[inline] fn try_into_checked_explicit( self, format: Format, ) -> Result { skip_assert_initialized!(); if self.format() == format { Ok(self) } else { Err(FormattedValueError(self.format())) } } } impl CompatibleFormattedValue for GenericFormattedValue { type Original = Self; #[inline] fn try_into_checked(self, _other: V) -> Result { skip_assert_initialized!(); if self.format() == V::default_format() { Ok(self) } else { Err(FormattedValueError(self.format())) } } #[inline] fn try_into_checked_explicit( self, _format: Format, ) -> Result { skip_assert_initialized!(); if self.format() == V::default_format() { Ok(self) } else { Err(FormattedValueError(self.format())) } } } gstreamer-0.23.5/src/format/format_serde.rs000064400000000000000000000163661046102023000170170ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use serde::{ de::{Deserialize, Deserializer}, ser::{Serialize, Serializer}, }; use crate::format::{Buffers, Bytes, Default, Other, Percent, Undefined}; // FIXME: the ser/de impl assumed `GenericFormattedValue` was always used. // When serializing a `SpecificFormattedValue`, we loose the type and only // serialize the inner value in parenthesis. // Manual implementation for some types that would otherwise yield representations such as: // "Default(Some((42)))" macro_rules! impl_serde( ($t:ident, $inner:ty) => { impl Serialize for $t { fn serialize(&self, serializer: S) -> Result { use std::ops::Deref; self.deref().serialize(serializer) } } impl<'de> Deserialize<'de> for $t { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); <$inner>::deserialize(deserializer) .and_then(|value| { $t::try_from(value).map_err(|_| { use serde::de::{Error, Unexpected}; D::Error::invalid_value( Unexpected::Unsigned(value.into()), &concat!("valid ", stringify!($t)), ) }) }) } } } ); impl_serde!(Buffers, u64); impl_serde!(Bytes, u64); impl_serde!(Default, u64); impl_serde!(Other, u64); impl_serde!(Percent, u32); impl Serialize for Undefined { fn serialize(&self, serializer: S) -> Result { use std::ops::Deref; self.deref().serialize(serializer) } } impl<'de> Deserialize<'de> for Undefined { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); i64::deserialize(deserializer).map(Into::into) } } #[cfg(test)] mod tests { use crate::{ format::{prelude::*, Default, Other, Undefined}, ClockTime, Format, GenericFormattedValue, }; #[test] fn test_serialize() { let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string()); let value = GenericFormattedValue::from(Undefined::from(42)); let res = ron::ser::to_string_pretty(&value, pretty_config.clone()); assert_eq!(Ok("Undefined(42)".to_owned()), res); let res = serde_json::to_string(&value).unwrap(); assert_eq!("{\"Undefined\":42}".to_owned(), res); let value = GenericFormattedValue::from(42.default_format()); let res = ron::ser::to_string_pretty(&value, pretty_config.clone()); assert_eq!(Ok("Default(Some(42))".to_owned()), res); let res = serde_json::to_string(&value).unwrap(); assert_eq!("{\"Default\":42}".to_owned(), res); let value = GenericFormattedValue::from(Default::NONE); let res = ron::ser::to_string_pretty(&value, pretty_config.clone()); assert_eq!(Ok("Default(None)".to_owned()), res); let res = serde_json::to_string(&value).unwrap(); assert_eq!("{\"Default\":null}".to_owned(), res); let value = GenericFormattedValue::from(42.bytes()); let res = ron::ser::to_string_pretty(&value, pretty_config.clone()); assert_eq!(Ok("Bytes(Some(42))".to_owned()), res); let res = serde_json::to_string(&value).unwrap(); assert_eq!("{\"Bytes\":42}".to_owned(), res); let value = GenericFormattedValue::from(ClockTime::from_nseconds(42_123_456_789)); let res = ron::ser::to_string_pretty(&value, pretty_config.clone()); assert_eq!(Ok("Time(Some(42123456789))".to_owned()), res); let res = serde_json::to_string(&value).unwrap(); assert_eq!("{\"Time\":42123456789}".to_owned(), res); let value = GenericFormattedValue::from(42.buffers()); let res = ron::ser::to_string_pretty(&value, pretty_config.clone()); assert_eq!(Ok("Buffers(Some(42))".to_owned()), res); let res = serde_json::to_string(&value).unwrap(); assert_eq!("{\"Buffers\":42}".to_owned(), res); let percent = 0.42.percent_ratio(); let value = GenericFormattedValue::from(percent); let res = ron::ser::to_string_pretty(&value, pretty_config.clone()); assert_eq!(Ok("Percent(Some(420000))".to_owned()), res); let res = serde_json::to_string(&value).unwrap(); assert_eq!("{\"Percent\":420000}".to_owned(), res); let other = Other::try_from(42).ok(); let value = GenericFormattedValue::Other(Format::Default, other); let res = ron::ser::to_string_pretty(&value, pretty_config.clone()); assert_eq!(Ok("Other(Default, Some(42))".to_owned()), res); let res = serde_json::to_string(&value).unwrap(); assert_eq!("{\"Other\":[\"Default\",42]}".to_owned(), res); let value = GenericFormattedValue::new(Format::__Unknown(7), 42); let res = ron::ser::to_string_pretty(&value, pretty_config); assert_eq!(Ok("Other(__Unknown(7), Some(42))".to_owned()), res); let res = serde_json::to_string(&value).unwrap(); assert_eq!("{\"Other\":[{\"__Unknown\":7},42]}".to_owned(), res); } #[test] fn test_deserialize() { let value_ron = "Default(Some(42))"; let value_de: GenericFormattedValue = ron::de::from_str(value_ron).unwrap(); assert_eq!(value_de, GenericFormattedValue::from(42.default_format())); let value_json = "{\"Default\":42}"; let value_de: GenericFormattedValue = serde_json::from_str(value_json).unwrap(); assert_eq!(value_de, GenericFormattedValue::from(Default::from_u64(42))); let value_ron = "Other(Buffers, Some(42))"; let gfv_value = GenericFormattedValue::Other(Format::Buffers, Some(42 * Other::ONE)); let value_de: GenericFormattedValue = ron::de::from_str(value_ron).unwrap(); assert_eq!(value_de, gfv_value); let value_json = "{\"Other\":[\"Buffers\",42]}"; let value_de: GenericFormattedValue = serde_json::from_str(value_json).unwrap(); assert_eq!(value_de, gfv_value); } #[test] fn test_serde_roundtrip() { macro_rules! test_roundrip( ($value:expr) => { let value_ser = ron::ser::to_string(&$value).unwrap(); let value_de: GenericFormattedValue = ron::de::from_str(value_ser.as_str()).unwrap(); assert_eq!(value_de, $value); } ); test_roundrip!(GenericFormattedValue::Undefined(Undefined::from(42))); test_roundrip!(GenericFormattedValue::from(Default::from_u64(42))); test_roundrip!(GenericFormattedValue::from(42.bytes())); test_roundrip!(GenericFormattedValue::from(ClockTime::from_nseconds( 42_123_456_789 ))); test_roundrip!(GenericFormattedValue::from(42.buffers())); test_roundrip!(GenericFormattedValue::from(42.percent())); let gfv_value = GenericFormattedValue::Other(Format::Default, Other::try_from(42).ok()); test_roundrip!(gfv_value); test_roundrip!(GenericFormattedValue::new(Format::__Unknown(7), 42)); } } gstreamer-0.23.5/src/format/generic.rs000064400000000000000000000422571046102023000157570ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::fmt; use glib::translate::{FromGlib, GlibNoneError, IntoGlib, OptionIntoGlib, TryFromGlib}; use super::{ Buffers, Bytes, ClockTime, CompatibleFormattedValue, Default, Format, FormattedValue, FormattedValueError, FormattedValueFullRange, FormattedValueIntrinsic, FormattedValueNoneBuilder, Percent, Signed, SignedIntrinsic, Undefined, UnsignedIntoSigned, }; use crate::utils::Displayable; #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Other(u64); impl Other { pub const MAX: Self = Self(u64::MAX - 1); } impl Other { // rustdoc-stripper-ignore-next /// Builds a new `Other` value with the provided quantity. /// /// # Panics /// /// Panics if the provided quantity equals `u64::MAX`, /// which is reserved for `None` in C. #[track_caller] #[inline] pub const fn from_u64(quantity: u64) -> Self { if quantity == u64::MAX { panic!("`Other` value out of range"); } Other(quantity) } // rustdoc-stripper-ignore-next /// Builds a new `Other` value with the provided quantity. /// /// # Panics /// /// Panics if the provided quantity equals `u64::MAX`, /// which is reserved for `None` in C. #[track_caller] #[inline] pub fn from_usize(quantity: usize) -> Self { // FIXME can't use `try_into` in `const` (rustc 1.64.0) Other::from_u64(quantity.try_into().unwrap()) } } impl_common_ops_for_newtype_uint!(Other, u64); impl_signed_div_mul!(Other, u64); impl_signed_int_into_signed!(Other, u64); option_glib_newtype_from_to!(Other, u64::MAX); glib_newtype_display!(Other, DisplayableOptionOther); impl TryFrom for Other { type Error = GlibNoneError; #[inline] fn try_from(val: u64) -> Result { skip_assert_initialized!(); unsafe { Self::try_from_glib(val) } } } impl TryFromGlib for Other { type Error = GlibNoneError; #[inline] unsafe fn try_from_glib(val: i64) -> Result { skip_assert_initialized!(); Self::try_from_glib(val as u64) } } impl TryFrom for usize { type Error = std::num::TryFromIntError; fn try_from(value: Other) -> Result { value.0.try_into() } } // FIXME `functions in traits cannot be const` (rustc 1.64.0) // rustdoc-stripper-ignore-next /// `Other` formatted value constructor trait. pub trait OtherFormatConstructor { // rustdoc-stripper-ignore-next /// Builds an `Other` formatted value from `self`. fn other_format(self) -> Other; } impl OtherFormatConstructor for u64 { #[track_caller] #[inline] fn other_format(self) -> Other { Other::from_u64(self) } } #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum GenericFormattedValue { Undefined(Undefined), Default(Option), Bytes(Option), Time(Option), Buffers(Option), Percent(Option), Other(Format, Option), } impl fmt::Display for GenericFormattedValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::Undefined(val) => val.fmt(f), Self::Default(val) => val.display().fmt(f), Self::Bytes(val) => val.display().fmt(f), Self::Time(val) => val.display().fmt(f), Self::Buffers(val) => val.display().fmt(f), Self::Percent(val) => val.display().fmt(f), Self::Other(format, val) => { val.display().fmt(f)?; fmt::Write::write_char(f, ' ')?; fmt::Display::fmt(&format, f) } } } } impl Displayable for GenericFormattedValue { type DisplayImpl = Self; fn display(self) -> Self { self } } impl GenericFormattedValue { #[inline] pub fn new(format: Format, value: i64) -> Self { skip_assert_initialized!(); match format { Format::Undefined => Self::Undefined(value.into()), Format::Default => Self::Default(unsafe { FromGlib::from_glib(value) }), Format::Bytes => Self::Bytes(unsafe { FromGlib::from_glib(value) }), Format::Time => Self::Time(unsafe { FromGlib::from_glib(value) }), Format::Buffers => Self::Buffers(unsafe { FromGlib::from_glib(value) }), Format::Percent => Self::Percent(unsafe { FromGlib::from_glib(value) }), Format::__Unknown(_) => Self::Other(format, unsafe { FromGlib::from_glib(value) }), } } #[doc(alias = "get_format")] #[inline] pub fn format(&self) -> Format { match *self { Self::Undefined(_) => Format::Undefined, Self::Default(_) => Format::Default, Self::Bytes(_) => Format::Bytes, Self::Time(_) => Format::Time, Self::Buffers(_) => Format::Buffers, Self::Percent(_) => Format::Percent, Self::Other(f, _) => f, } } #[doc(alias = "get_value")] #[inline] pub fn value(&self) -> i64 { unsafe { match *self { Self::Undefined(v) => *v, Self::Default(v) => v.into_raw_value(), Self::Bytes(v) => v.into_raw_value(), Self::Time(v) => v.into_raw_value(), Self::Buffers(v) => v.into_raw_value(), Self::Percent(v) => v.into_raw_value(), Self::Other(_, v) => v.into_glib() as i64, } } } } impl FormattedValue for GenericFormattedValue { // The intrinsic value for `GenericFormattedValue` is also // `GenericFormattedValue`. We can't dissociate the `Option` // from the variants' inner type since they are not all `Option`s. type FullRange = GenericFormattedValue; #[inline] fn default_format() -> Format { Format::Undefined } #[inline] fn format(&self) -> Format { self.format() } #[inline] fn is_some(&self) -> bool { match self { Self::Undefined(_) => true, Self::Default(v) => v.is_some(), Self::Bytes(v) => v.is_some(), Self::Time(v) => v.is_some(), Self::Buffers(v) => v.is_some(), Self::Percent(v) => v.is_some(), Self::Other(_, v) => v.is_some(), } } #[inline] unsafe fn into_raw_value(self) -> i64 { self.value() } } impl FormattedValueFullRange for GenericFormattedValue { #[inline] unsafe fn from_raw(format: Format, value: i64) -> Self { GenericFormattedValue::new(format, value) } } impl FormattedValueIntrinsic for GenericFormattedValue {} impl SignedIntrinsic for GenericFormattedValue {} impl FormattedValueNoneBuilder for GenericFormattedValue { #[track_caller] fn none() -> Self { panic!(concat!( "`GenericFormattedValue` can't build `None` without knowing", "the target format. Use `GenericFormattedValue::none_for_format`", )); } #[track_caller] #[inline] fn none_for_format(format: Format) -> Self { skip_assert_initialized!(); match format { Format::Undefined => panic!("`None` can't be represented by `Undefined`"), Format::Default => Self::Default(None), Format::Bytes => Self::Bytes(None), Format::Time => Self::Time(None), Format::Buffers => Self::Buffers(None), Format::Percent => Self::Percent(None), unknown => Self::Other(unknown, Other::NONE), } } } impl UnsignedIntoSigned for GenericFormattedValue { type Signed = GenericSignedFormattedValue; #[track_caller] #[inline] fn into_positive(self) -> Self::Signed { use Signed::Positive; match self { Self::Undefined(_) => { unimplemented!("`GenericFormattedValue::Undefined` is already signed") } Self::Default(val) => Self::Signed::Default(val.map(Positive)), Self::Bytes(val) => Self::Signed::Bytes(val.map(Positive)), Self::Time(val) => Self::Signed::Time(val.map(Positive)), Self::Buffers(val) => Self::Signed::Buffers(val.map(Positive)), Self::Percent(val) => Self::Signed::Percent(val.map(Positive)), Self::Other(format, val) => Self::Signed::Other(format, val.map(Positive)), } } #[track_caller] #[inline] fn into_negative(self) -> Self::Signed { use Signed::Negative; match self { Self::Undefined(_) => { unimplemented!("`GenericFormattedValue::Undefined` is already signed") } Self::Default(val) => Self::Signed::Default(val.map(Negative)), Self::Bytes(val) => Self::Signed::Bytes(val.map(Negative)), Self::Time(val) => Self::Signed::Time(val.map(Negative)), Self::Buffers(val) => Self::Signed::Buffers(val.map(Negative)), Self::Percent(val) => Self::Signed::Percent(val.map(Negative)), Self::Other(format, val) => Self::Signed::Other(format, val.map(Negative)), } } } impl CompatibleFormattedValue for GenericFormattedValue { type Original = Self; #[inline] fn try_into_checked(self, other: GenericFormattedValue) -> Result { skip_assert_initialized!(); if self.format() == other.format() { Ok(self) } else { Err(FormattedValueError(self.format())) } } #[inline] fn try_into_checked_explicit( self, format: Format, ) -> Result { skip_assert_initialized!(); if self.format() == format { Ok(self) } else { Err(FormattedValueError(self.format())) } } } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum GenericSignedFormattedValue { Default(Option>), Bytes(Option>), Time(Option>), Buffers(Option>), Percent(Option>), Other(Format, Option>), } impl GenericSignedFormattedValue { #[doc(alias = "get_format")] #[inline] pub fn format(&self) -> Format { match *self { Self::Default(_) => Format::Default, Self::Bytes(_) => Format::Bytes, Self::Time(_) => Format::Time, Self::Buffers(_) => Format::Buffers, Self::Percent(_) => Format::Percent, Self::Other(format, _) => format, } } #[inline] pub fn abs(self) -> GenericFormattedValue { use GenericFormattedValue as Unsigned; match self { Self::Default(opt_signed) => Unsigned::Default(opt_signed.map(Signed::abs)), Self::Bytes(opt_signed) => Unsigned::Bytes(opt_signed.map(Signed::abs)), Self::Time(opt_signed) => Unsigned::Time(opt_signed.map(Signed::abs)), Self::Buffers(opt_signed) => Unsigned::Buffers(opt_signed.map(Signed::abs)), Self::Percent(opt_signed) => Unsigned::Percent(opt_signed.map(Signed::abs)), Self::Other(format, opt_signed) => Unsigned::Other(format, opt_signed.map(Signed::abs)), } } #[inline] pub fn is_some(&self) -> bool { match self { Self::Default(v) => v.is_some(), Self::Bytes(v) => v.is_some(), Self::Time(v) => v.is_some(), Self::Buffers(v) => v.is_some(), Self::Percent(v) => v.is_some(), Self::Other(_, v) => v.is_some(), } } #[inline] pub fn is_none(&self) -> bool { !self.is_some() } #[track_caller] #[inline] pub fn none_for_format(format: Format) -> Self { skip_assert_initialized!(); match format { Format::Default => Self::Default(None), Format::Bytes => Self::Bytes(None), Format::Time => Self::Time(None), Format::Buffers => Self::Buffers(None), Format::Percent => Self::Percent(None), Format::Undefined => { panic!("`Undefined` is already signed, use `GenericFormattedValue`") } other => Self::Other(other, None), } } } macro_rules! impl_gsfv_fn_opt_ret( ($fn:ident(self) -> Option<$ret_ty:ty>) => { #[inline] pub fn $fn(self) -> Option<$ret_ty> { match self { Self::Default(opt_signed) => opt_signed.map(|signed| signed.$fn()), Self::Bytes(opt_signed) => opt_signed.map(|signed| signed.$fn()), Self::Time(opt_signed) => opt_signed.map(|signed| signed.$fn()), Self::Buffers(opt_signed) => opt_signed.map(|signed| signed.$fn()), Self::Percent(opt_signed) => opt_signed.map(|signed| signed.$fn()), Self::Other(_, opt_signed) => opt_signed.map(|signed| signed.$fn()), } } }; ); impl GenericSignedFormattedValue { impl_gsfv_fn_opt_ret!(is_positive(self) -> Option); impl_gsfv_fn_opt_ret!(is_negative(self) -> Option); impl_gsfv_fn_opt_ret!(signum(self) -> Option); } impl std::ops::Neg for GenericSignedFormattedValue { type Output = Self; #[inline] fn neg(self) -> Self { use std::ops::Neg; match self { Self::Default(opt_signed) => Self::Default(opt_signed.map(Neg::neg)), Self::Bytes(opt_signed) => Self::Bytes(opt_signed.map(Neg::neg)), Self::Time(opt_signed) => Self::Time(opt_signed.map(Neg::neg)), Self::Buffers(opt_signed) => Self::Buffers(opt_signed.map(Neg::neg)), Self::Percent(opt_signed) => Self::Percent(opt_signed.map(Neg::neg)), Self::Other(format, opt_signed) => Self::Other(format, opt_signed.map(Neg::neg)), } } } impl fmt::Display for GenericSignedFormattedValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::Default(opt_signed) => opt_signed.display().fmt(f), Self::Bytes(opt_signed) => opt_signed.display().fmt(f), Self::Time(opt_signed) => opt_signed.display().fmt(f), Self::Buffers(opt_signed) => opt_signed.display().fmt(f), Self::Percent(opt_signed) => opt_signed.display().fmt(f), Self::Other(format, opt_signed) => { opt_signed.display().fmt(f)?; fmt::Write::write_char(f, ' ')?; fmt::Display::fmt(&format, f) } } } } impl Displayable for GenericSignedFormattedValue { type DisplayImpl = Self; fn display(self) -> Self::DisplayImpl { self } } #[cfg(test)] mod tests { use super::*; #[test] #[allow(clippy::eq_op, clippy::op_ref)] fn other() { // Check a few ops on `Other`, better coverage for // the macro ops impl ensured as part of the `clock_time` module. use opt_ops::prelude::*; let other_none: Option = Other::try_from(u64::MAX).ok(); assert!(other_none.is_none()); let other_10 = Other::from_u64(10); let other_20 = Other::from_usize(20); let other_30 = 30.other_format(); assert_eq!(other_10 + other_20, other_30); assert_eq!(other_30 - other_20, other_10); assert!(other_10 < Other::MAX); assert_eq!(Some(other_10).opt_add(other_20), Some(other_30)); } #[test] #[allow(clippy::eq_op, clippy::op_ref)] fn generic_other() { let gen_other_42: GenericFormattedValue = GenericFormattedValue::new(Format::__Unknown(128), 42); assert_eq!( gen_other_42, GenericFormattedValue::Other(Format::__Unknown(128), Other::try_from(42).ok()) ); assert_eq!(gen_other_42.format(), Format::__Unknown(128)); assert_eq!(gen_other_42.value(), 42); assert!(gen_other_42.is_some()); let other_none: Option = Other::NONE; assert!(other_none.is_none()); let gen_other_none: GenericFormattedValue = GenericFormattedValue::none_for_format(Format::__Unknown(128)); assert!(gen_other_none.is_none()); assert_eq!( gen_other_none, GenericFormattedValue::Other(Format::__Unknown(128), None) ); } #[test] #[allow(clippy::eq_op, clippy::op_ref)] fn generic_signed_other() { let gen_other_42: GenericFormattedValue = GenericFormattedValue::new(Format::__Unknown(128), 42); let p_gen_other_42 = gen_other_42.into_positive(); assert_eq!( p_gen_other_42, GenericSignedFormattedValue::Other( Format::__Unknown(128), Some(Signed::Positive(42.other_format())), ), ); let n_gen_other_42 = gen_other_42.into_negative(); assert_eq!( n_gen_other_42, GenericSignedFormattedValue::Other( Format::__Unknown(128), Some(Signed::Negative(42.other_format())), ), ); } } gstreamer-0.23.5/src/format/macros.rs000064400000000000000000002004561046102023000156240ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. macro_rules! impl_trait_op_same( ($typ:ty, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident) => { impl std::ops::$op for $typ { type Output = Self; #[inline] fn $op_name(self, rhs: $typ) -> Self { Self(self.0.$op_name(rhs.0)) } } impl std::ops::$op_assign for $typ { #[inline] fn $op_assign_name(&mut self, rhs: $typ) { self.0.$op_assign_name(rhs.0) } } }; ); macro_rules! impl_non_trait_op_same( ($typ:ty, $inner:ty) => { impl $typ { #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub const fn checked_add(self, rhs: Self) -> Option { match self.0.checked_add(rhs.0) { Some(res) if res <= Self::MAX.0 => Some(Self(res)), _ => None, } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub const fn saturating_add(self, rhs: Self) -> Self { let res = self.0.saturating_add(rhs.0); if res < Self::MAX.0 { Self(res) } else { Self::MAX } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn overflowing_add(self, rhs: Self) -> (Self, bool) { let self_u128 = self.0 as u128; let rhs_128 = rhs.0 as u128; let res_u128 = self_u128 + rhs_128; if res_u128 <= Self::MAX.0 as u128 { (Self(<$inner>::try_from(res_u128).unwrap()), false) } else { (Self(<$inner>::try_from((res_u128 - Self::MAX.0 as u128 - 1) as u64).unwrap()), true) } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn wrapping_add(self, rhs: Self) -> Self { self.overflowing_add(rhs).0 } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] // FIXME Can't use `map` in a `const fn` as of rustc 1.53.0-beta.2 #[allow(clippy::manual_map)] pub const fn checked_sub(self, rhs: Self) -> Option { match self.0.checked_sub(rhs.0) { Some(res) => Some(Self(res)), None => None, } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub const fn saturating_sub(self, rhs: Self) -> Self { Self(self.0.saturating_sub(rhs.0)) } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { if self.0 >= rhs.0 { (Self(self.0 - rhs.0), false) } else { (Self(Self::MAX.0 - rhs.0 + self.0 + 1), true) } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub const fn wrapping_sub(self, rhs: Self) -> Self { self.overflowing_sub(rhs).0 } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn absdiff(self, rhs: Self) -> Self { if self > rhs { self - rhs } else { rhs - self } } } }; ); macro_rules! impl_trait_op_inner_type( ($typ:ty, $inner:ty, $op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident) => { impl std::ops::$op<$inner> for $typ { type Output = Self; #[inline] fn $op_name(self, rhs: $inner) -> Self { Self(self.0.$op_name(rhs)) } } impl std::ops::$op_assign<$inner> for $typ { #[inline] fn $op_assign_name(&mut self, rhs: $inner) { self.0.$op_assign_name(rhs) } } }; ); macro_rules! impl_non_trait_op_inner_type( ($typ:ty, $inner:ty) => { impl $typ { #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub const fn checked_div(self, rhs: $inner) -> Option { match self.0.checked_div(rhs) { Some(val) => Some(Self(val)), None => None, } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub const fn saturating_div(self, rhs: $inner) -> Self { Self(self.0.saturating_div(rhs)) } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub const fn checked_mul(self, rhs: $inner) -> Option { match self.0.checked_mul(rhs) { Some(res) if res <= Self::MAX.0 => Some(Self(res)), _ => None, } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub const fn saturating_mul(self, rhs: $inner) -> Self { let res = self.0.saturating_mul(rhs); if res < Self::MAX.0 { Self(res) } else { Self::MAX } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn overflowing_mul(self, rhs: $inner) -> (Self, bool) { let self_u128 = self.0 as u128; let rhs_128 = rhs as u128; let res_u128 = self_u128 * rhs_128; if res_u128 <= Self::MAX.0 as u128 { (Self(<$inner>::try_from(res_u128).unwrap()), false) } else { (Self(<$inner>::try_from((res_u128 - Self::MAX.0 as u128 - 1) as u64).unwrap()), true) } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn wrapping_mul(self, rhs: $inner) -> Self { self.overflowing_mul(rhs).0 } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub const fn checked_rem(self, rhs: $inner) -> Option { match self.0.checked_rem(rhs) { Some(val) => Some(Self(val)), None => None, } } } }; ); macro_rules! impl_unsigned_int_into_signed( ($typ:ty) => { impl crate::format::SignedIntrinsic for $typ {} impl crate::format::UnsignedIntoSigned for $typ { type Signed = crate::Signed<$typ>; #[inline] fn into_positive(self) -> Self::Signed { crate::Signed::Positive(self) } #[inline] fn into_negative(self) -> Self::Signed { crate::Signed::Negative(self) } } impl crate::format::UnsignedIntoSigned for Option<$typ> { type Signed = Option>; #[inline] fn into_positive(self) -> Self::Signed { Some(self?.into_positive()) } #[inline] fn into_negative(self) -> Self::Signed { Some(self?.into_negative()) } } impl From<$typ> for crate::Signed<$typ> { #[inline] fn from(v: $typ) -> crate::Signed<$typ> { crate::Signed::Positive(v) } } }; ($typ:ty, $inner:ty) => { impl_unsigned_int_into_signed!($typ); impl crate::Signed<$typ> { // rustdoc-stripper-ignore-next /// Returns a `Signed` containing the inner type of `self`. #[inline] pub fn into_inner_signed(self) -> crate::Signed<$inner> { use crate::Signed::*; match self { Positive(new_type) => Positive(*new_type), Negative(new_type) => Negative(*new_type), } } } }; ); macro_rules! impl_common_ops_for_newtype_uint( ($typ:ty, $inner:ty) => { impl_common_ops_for_newtype_uint!($typ, $inner, one: 1); }; ($typ:ty, $inner:ty, one: $one:expr$(,)?) => { impl $typ { pub const ZERO: Self = Self(0); pub const NONE: Option = None; // rustdoc-stripper-ignore-next /// The unitary value. pub const ONE: Self = Self($one); pub const MAX_SIGNED: crate::Signed::<$typ> = crate::Signed::Positive(Self::MAX); pub const MIN_SIGNED: crate::Signed::<$typ> = crate::Signed::Negative(Self::MAX); #[inline] pub const fn is_zero(self) -> bool { self.0 == Self::ZERO.0 } } impl std::ops::Deref for $typ { type Target = $inner; #[inline] fn deref(&self) -> &$inner { &self.0 } } impl AsRef<$inner> for $typ { #[inline] fn as_ref(&self) -> &$inner { &self.0 } } impl From<$typ> for $inner { fn from(v: $typ) -> $inner { v.0 } } impl_trait_op_same!($typ, Add, add, AddAssign, add_assign); impl_trait_op_same!($typ, Sub, sub, SubAssign, sub_assign); impl std::ops::Div for $typ { type Output = $inner; #[inline] fn div(self, rhs: $typ) -> $inner { self.0.div(rhs.0) } } impl std::ops::Rem for $typ { type Output = Self; #[inline] fn rem(self, rhs: Self) -> Self { Self(self.0.rem(rhs.0)) } } impl_non_trait_op_same!($typ, $inner); impl_trait_op_inner_type!($typ, $inner, Mul, mul, MulAssign, mul_assign); impl std::ops::Mul<$typ> for $inner { type Output = $typ; #[inline] fn mul(self, rhs: $typ) -> $typ { rhs.mul(self) } } impl_trait_op_inner_type!($typ, $inner, Div, div, DivAssign, div_assign); impl_trait_op_inner_type!($typ, $inner, Rem, rem, RemAssign, rem_assign); impl_non_trait_op_inner_type!($typ, $inner); impl_unsigned_int_into_signed!($typ, $inner); impl_signed_ops!($typ, $inner, <$typ>::ZERO); impl muldiv::MulDiv<$inner> for $typ { type Output = Self; #[inline] fn mul_div_floor(self, num: $inner, denom: $inner) -> Option { self.0 .mul_div_floor(num, denom) .map(Self) } #[inline] fn mul_div_round(self, num: $inner, denom: $inner) -> Option { self.0 .mul_div_round(num, denom) .map(Self) } #[inline] fn mul_div_ceil(self, num: $inner, denom: $inner) -> Option { self.0 .mul_div_ceil(num, denom) .map(Self) } } impl opt_ops::OptionOperations for $typ {} impl opt_ops::OptionCheckedAdd for $typ { type Output = Self; #[inline] fn opt_checked_add( self, rhs: Self, ) -> Result, opt_ops::Error> { self.checked_add(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionSaturatingAdd for $typ { type Output = Self; #[inline] fn opt_saturating_add(self, rhs: Self) -> Option { Some(self.saturating_add(rhs)) } } impl opt_ops::OptionOverflowingAdd for $typ { type Output = Self; #[inline] fn opt_overflowing_add(self, rhs: Self) -> Option<(Self, bool)> { let res = self.overflowing_add(rhs); Some((res.0, res.1)) } } impl opt_ops::OptionWrappingAdd for $typ { type Output = Self; #[inline] fn opt_wrapping_add(self, rhs: Self) -> Option { Some(self.wrapping_add(rhs)) } } impl opt_ops::OptionCheckedDiv<$inner> for $typ { type Output = Self; #[inline] fn opt_checked_div(self, rhs: $inner) -> Result, opt_ops::Error> { if rhs == 0 { return Err(opt_ops::Error::DivisionByZero); } self .checked_div(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionCheckedDiv for $typ { type Output = $inner; #[inline] fn opt_checked_div(self, rhs: Self) -> Result, opt_ops::Error> { if rhs.0 == 0 { return Err(opt_ops::Error::DivisionByZero); } self.0 .checked_div(rhs.0) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionCheckedMul<$inner> for $typ { type Output = Self; #[inline] fn opt_checked_mul( self, rhs: $inner, ) -> Result, opt_ops::Error> { self.checked_mul(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionCheckedMul<$typ> for $inner { type Output = $typ; #[inline] fn opt_checked_mul( self, rhs: $typ, ) -> Result, opt_ops::Error> { rhs.checked_mul(self) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionSaturatingMul<$inner> for $typ { type Output = Self; #[inline] fn opt_saturating_mul(self, rhs: $inner) -> Option { Some(self.saturating_mul(rhs)) } } impl opt_ops::OptionSaturatingMul<$typ> for $inner { type Output = $typ; #[inline] fn opt_saturating_mul(self, rhs: $typ) -> Option<$typ> { Some(rhs.saturating_mul(self)) } } impl opt_ops::OptionOverflowingMul<$inner> for $typ { type Output = Self; #[inline] fn opt_overflowing_mul(self, rhs: $inner) -> Option<(Self, bool)> { let res = self.overflowing_mul(rhs); Some((res.0, res.1)) } } impl opt_ops::OptionOverflowingMul<$typ> for $inner { type Output = $typ; #[inline] fn opt_overflowing_mul(self, rhs: $typ) -> Option<($typ, bool)> { let res = rhs.overflowing_mul(self); Some((res.0, res.1)) } } impl opt_ops::OptionWrappingMul<$inner> for $typ { type Output = Self; #[inline] fn opt_wrapping_mul(self, rhs: $inner) -> Option { Some(self.wrapping_mul(rhs)) } } impl opt_ops::OptionWrappingMul<$typ> for $inner { type Output = $typ; #[inline] fn opt_wrapping_mul(self, rhs: $typ) -> Option<$typ> { Some(rhs.wrapping_mul(self)) } } impl opt_ops::OptionCheckedRem<$inner> for $typ { type Output = Self; #[inline] fn opt_checked_rem(self, rhs: $inner) -> Result, opt_ops::Error> { if rhs == 0 { return Err(opt_ops::Error::DivisionByZero); } self.checked_rem(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionCheckedRem for $typ { type Output = Self; #[inline] fn opt_checked_rem(self, rhs: Self) -> Result, opt_ops::Error> { if rhs.0 == 0 { return Err(opt_ops::Error::DivisionByZero); } self.checked_rem(rhs.0) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionCheckedSub for $typ { type Output = Self; #[inline] fn opt_checked_sub( self, rhs: Self, ) -> Result, opt_ops::Error> { self.checked_sub(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionSaturatingSub for $typ { type Output = Self; #[inline] fn opt_saturating_sub(self, rhs: Self) -> Option { Some(self.saturating_sub(rhs)) } } impl opt_ops::OptionOverflowingSub for $typ { type Output = Self; #[inline] fn opt_overflowing_sub(self, rhs: Self) -> Option<(Self, bool)> { let res = self.overflowing_sub(rhs); Some((res.0, res.1)) } } impl opt_ops::OptionWrappingSub for $typ { type Output = Self; #[inline] fn opt_wrapping_sub(self, rhs: Self) -> Option { Some(self.wrapping_sub(rhs)) } } }; ); macro_rules! impl_signed_ops( (u64) => { impl_signed_ops!(u64, u64, 0); }; (u32) => { impl_signed_ops!(u32, u32, 0); }; (usize) => { impl_signed_ops!(usize, usize, 0); }; ($typ:ty, $inner:ty, $zero:expr) => { impl crate::Signed<$typ> { // rustdoc-stripper-ignore-next /// Returns the signum for this `Signed`. /// /// Returns: /// /// - `0` if the number is zero. /// - `1` if the value must be considered as positive. /// - `-1` if the value must be considered as negative. #[inline] pub fn signum(self) -> i32 { use crate::Signed::*; match self { Positive(val) | Negative(val) if val == $zero => 0i32, Positive(_) => 1i32, Negative(_) => -1i32, } } // rustdoc-stripper-ignore-next /// Returns the checked subtraction `self - other`. #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn checked_sub(self, other: Self) -> Option { use crate::Signed::*; match (self, other) { (Positive(a), Positive(b)) if a >= b => Some(Positive(a - b)), (Positive(a), Positive(b)) => Some(Negative(b - a)), (Negative(a), Negative(b)) if a >= b => Some(Negative(a - b)), (Negative(a), Negative(b)) => Some(Positive(b - a)), (Positive(a), Negative(b)) => a.checked_add(b).map(Positive), (Negative(a), Positive(b)) => a.checked_add(b).map(Negative), } } // rustdoc-stripper-ignore-next /// Returns the checked subtraction `self - other`. #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn checked_sub_unsigned(self, other: $typ) -> Option { self.checked_sub(crate::Signed::Positive(other)) } // rustdoc-stripper-ignore-next /// Returns the checked addition `self + other`. #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn checked_add(self, other: Self) -> Option { use crate::Signed::*; match (self, other) { (Positive(a), Positive(b)) => a.checked_add(b).map(Positive), (Negative(a), Negative(b)) => a.checked_add(b).map(Negative), (Positive(_), Negative(_)) => self.checked_sub(-other), (Negative(_), Positive(_)) => Some(-((-self).checked_sub(other)?)) } } // rustdoc-stripper-ignore-next /// Returns the checked addition `self + other`. #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn checked_add_unsigned(self, other: $typ) -> Option { self.checked_add(crate::Signed::Positive(other)) } // rustdoc-stripper-ignore-next /// Returns the saturating subtraction `self - other`. #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn saturating_sub(self, other: Self) -> Self { use crate::Signed::*; match (self, other) { (Positive(a), Positive(b)) if a >= b => Positive(a - b), (Positive(a), Positive(b)) => Negative(b - a), (Negative(a), Negative(b)) if a >= b => Negative(a - b), (Negative(a), Negative(b)) => Positive(b - a), (Positive(a), Negative(b)) => Positive(a.saturating_add(b)), (Negative(a), Positive(b)) => Negative(a.saturating_add(b)), } } // rustdoc-stripper-ignore-next /// Returns the saturating subtraction `self - other`. #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn saturating_sub_unsigned(self, other: $typ) -> Self { self.saturating_sub(crate::Signed::Positive(other)) } // rustdoc-stripper-ignore-next /// Returns the saturating addition `self + other`. #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn saturating_add(self, other: Self) -> Self { use crate::Signed::*; match (self, other) { (Positive(a), Positive(b)) => Positive(a.saturating_add(b)), (Negative(a), Negative(b)) => Negative(a.saturating_add(b)), (Positive(_), Negative(_)) => self.saturating_sub(-other), (Negative(_), Positive(_)) => -((-self).saturating_sub(other)), } } // rustdoc-stripper-ignore-next /// Returns the saturating addition `self + other`. #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn saturating_add_unsigned(self, other: $typ) -> Self { self.saturating_add(crate::Signed::Positive(other)) } } impl std::ops::Add for crate::Signed<$typ> { type Output = Self; #[inline] fn add(self, other: Self) -> Self { self.checked_add(other).expect("Overflowing addition") } } impl std::ops::AddAssign for crate::Signed<$typ> { #[inline] fn add_assign(&mut self, other: Self) { *self = self.checked_add(other).expect("Overflowing addition") } } impl std::ops::Sub for crate::Signed<$typ> { type Output = Self; #[inline] fn sub(self, other: Self) -> Self { self.checked_sub(other).expect("Overflowing subtraction") } } impl std::ops::SubAssign for crate::Signed<$typ> { #[inline] fn sub_assign(&mut self, other: Self) { *self = self.checked_sub(other).expect("Overflowing subtraction") } } impl std::ops::Add<$typ> for crate::Signed<$typ> { type Output = Self; #[inline] fn add(self, other: $typ) -> Self { self.checked_add(crate::Signed::Positive(other)).expect("Overflowing addition") } } impl std::ops::AddAssign<$typ> for crate::Signed<$typ> { #[inline] fn add_assign(&mut self, other: $typ) { *self = self.checked_add(crate::Signed::Positive(other)).expect("Overflowing addition") } } impl std::ops::Sub<$typ> for crate::Signed<$typ> { type Output = Self; #[inline] fn sub(self, other: $typ) -> Self { self.checked_sub(crate::Signed::Positive(other)).expect("Overflowing subtraction") } } impl std::ops::SubAssign<$typ> for crate::Signed<$typ> { #[inline] fn sub_assign(&mut self, other: $typ) { *self = self.checked_sub(crate::Signed::Positive(other)).expect("Overflowing subtraction") } } impl std::ops::Add> for $typ { type Output = crate::Signed<$typ>; #[inline] fn add(self, other: crate::Signed<$typ>) -> crate::Signed<$typ> { crate::Signed::Positive(self).checked_add(other).expect("Overflowing addition") } } impl std::ops::Sub> for $typ { type Output = crate::Signed<$typ>; #[inline] fn sub(self, other: crate::Signed<$typ>) -> crate::Signed<$typ> { crate::Signed::Positive(self).checked_sub(other).expect("Overflowing subtraction") } } impl std::cmp::PartialOrd for crate::Signed<$typ> { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl std::cmp::PartialEq<$typ> for crate::Signed<$typ> { #[inline] fn eq(&self, other: &$typ) -> bool { self.eq(&crate::Signed::Positive(*other)) } } impl std::cmp::PartialEq> for $typ { #[inline] fn eq(&self, other: &crate::Signed<$typ>) -> bool { crate::Signed::Positive(*self).eq(other) } } impl std::cmp::PartialOrd<$typ> for crate::Signed<$typ> { #[inline] fn partial_cmp(&self, other: &$typ) -> Option { Some(self.cmp(&crate::Signed::Positive(*other))) } } impl std::cmp::PartialOrd> for $typ { #[inline] fn partial_cmp(&self, other: &crate::Signed<$typ>) -> Option { Some(crate::Signed::Positive(*self).cmp(other)) } } impl std::cmp::Ord for crate::Signed<$typ> { #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { use crate::Signed::*; match (self, other) { (Positive(a), Positive(b)) => a.cmp(b), (Negative(a), Negative(b)) => b.cmp(a), (Positive(_), Negative(_)) => std::cmp::Ordering::Greater, (Negative(_), Positive(_)) => std::cmp::Ordering::Less, } } } impl opt_ops::OptionOperations for crate::Signed<$typ> {} impl opt_ops::OptionCheckedAdd for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_add( self, rhs: Self, ) -> Result, opt_ops::Error> { self.checked_add(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionSaturatingAdd for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_saturating_add(self, rhs: Self) -> Option { Some(self.saturating_add(rhs)) } } impl opt_ops::OptionCheckedSub for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_sub( self, rhs: Self, ) -> Result, opt_ops::Error> { self.checked_sub(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionSaturatingSub for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_saturating_sub(self, rhs: Self) -> Option { Some(self.saturating_sub(rhs)) } } impl opt_ops::OptionCheckedAdd<$typ> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_add( self, rhs: $typ, ) -> Result, opt_ops::Error> { self.opt_checked_add(crate::Signed::Positive(rhs)) } } impl opt_ops::OptionSaturatingAdd<$typ> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_saturating_add(self, rhs: $typ) -> Option { self.opt_saturating_add(crate::Signed::Positive(rhs)) } } impl opt_ops::OptionCheckedSub<$typ> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_sub( self, rhs: $typ, ) -> Result, opt_ops::Error> { self.opt_checked_sub(crate::Signed::Positive(rhs)) } } impl opt_ops::OptionSaturatingSub<$typ> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_saturating_sub(self, rhs: $typ) -> Option { self.opt_saturating_sub(crate::Signed::Positive(rhs)) } } impl opt_ops::OptionCheckedAdd> for $typ { type Output = crate::Signed<$typ>; #[inline] fn opt_checked_add( self, rhs: crate::Signed<$typ>, ) -> Result, opt_ops::Error> { crate::Signed::Positive(self).opt_checked_add(rhs) } } impl opt_ops::OptionSaturatingAdd> for $typ { type Output = crate::Signed<$typ>; #[inline] fn opt_saturating_add( self, rhs: crate::Signed<$typ> ) -> Option { crate::Signed::Positive(self).opt_saturating_add(rhs) } } impl opt_ops::OptionCheckedSub> for $typ { type Output = crate::Signed<$typ>; #[inline] fn opt_checked_sub( self, rhs: crate::Signed<$typ>, ) -> Result, opt_ops::Error> { crate::Signed::Positive(self).opt_checked_sub(rhs) } } impl opt_ops::OptionSaturatingSub> for $typ { type Output = crate::Signed<$typ>; #[inline] fn opt_saturating_sub( self, rhs: crate::Signed<$typ> ) -> Option { crate::Signed::Positive(self).opt_saturating_sub(rhs) } } }; ); macro_rules! impl_signed_div_mul( (u64) => { impl_signed_div_mul!(u64, u64, i64, |val: u64| val); impl_signed_extra_div_mul!(u64, i64); impl_signed_div_mul_trait!(u64, u64, i64, |val: u64| val); }; (usize) => { impl_signed_div_mul!(usize, usize, isize, |val: usize| val); impl_signed_extra_div_mul!(usize, isize); // `MulDiv` not available for usize }; (u32) => { impl_signed_div_mul!(u32, u32, i32, |val: u32| val); impl_signed_extra_div_mul!(u32, i32); impl_signed_div_mul_trait!(u32, u32, i32, |val: u32| val); }; ($newtyp:ty, u64) => { impl_signed_div_mul!($newtyp, u64, i64, |val: $newtyp| *val); impl_signed_extra_div_mul!($newtyp, u64, i64); impl_signed_div_mul_trait!($newtyp, u64, i64, |val: $newtyp| *val); }; ($newtyp:ty, u32) => { impl_signed_div_mul!($newtyp, u32, i32, |val: $newtyp| *val); impl_signed_extra_div_mul!($newtyp, u32, i32); impl_signed_div_mul_trait!($newtyp, u32, i32, |val: $newtyp| *val); }; ($typ:ty, $inner:ty, $signed_rhs:ty, $into_inner:expr) => { impl crate::Signed<$typ> { #[allow(dead_code)] #[inline] fn signed_from_inner(val: $inner, sign: $signed_rhs) -> Option> { skip_assert_initialized!(); if sign.is_positive() { Self::positive_from_inner(val) } else { Self::negative_from_inner(val) } } #[inline] fn positive_from_inner(val: $inner) -> Option { skip_assert_initialized!(); <$typ>::try_from(val).ok().map(crate::Signed::Positive) } #[inline] fn negative_from_inner(val: $inner) -> Option { skip_assert_initialized!(); <$typ>::try_from(val).ok().map(crate::Signed::Negative) } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn checked_div(self, rhs:$signed_rhs) -> Option { use crate::Signed::*; match self { Positive(lhs) => { if rhs.is_positive() { lhs.checked_div(rhs as $inner).map(Positive) } else { lhs.checked_div(-rhs as $inner).map(Negative) } } Negative(lhs) => { if rhs.is_positive() { lhs.checked_div(rhs as $inner).map(Negative) } else { lhs.checked_div(-rhs as $inner).map(Positive) } } } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn checked_div_unsigned(self, rhs:$inner) -> Option { use crate::Signed::*; match self { Positive(lhs) => lhs.checked_div(rhs).map(Positive), Negative(lhs) => lhs.checked_div(rhs).map(Negative), } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn checked_rem(self, rhs:$signed_rhs) -> Option { use crate::Signed::*; match self { Positive(lhs) => { if rhs.is_positive() { lhs.checked_rem(rhs as $inner).map(Positive) } else { lhs.checked_rem(-rhs as $inner).map(Positive) } } Negative(lhs) => { if rhs.is_positive() { lhs.checked_rem(rhs as $inner).map(Negative) } else { lhs.checked_rem(-rhs as $inner).map(Negative) } } } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn checked_rem_unsigned(self, rhs:$inner) -> Option { use crate::Signed::*; match self { Positive(lhs) => lhs.checked_rem(rhs).map(Positive), Negative(lhs) => lhs.checked_rem(rhs).map(Negative), } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn checked_mul(self, rhs:$signed_rhs) -> Option { use crate::Signed::*; match self { Positive(lhs) => { if rhs.is_positive() { lhs.checked_mul(rhs as $inner).map(Positive) } else { lhs.checked_mul(-rhs as $inner).map(Negative) } } Negative(lhs) => { if rhs.is_positive() { lhs.checked_mul(rhs as $inner).map(Negative) } else { lhs.checked_mul(-rhs as $inner).map(Positive) } } } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn checked_mul_unsigned(self, rhs:$inner) -> Option { use crate::Signed::*; match self { Positive(lhs) => lhs.checked_mul(rhs).map(Positive), Negative(lhs) => lhs.checked_mul(rhs).map(Negative), } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn saturating_mul(self, rhs:$signed_rhs) -> Self { use crate::Signed::*; match self { Positive(lhs) => { if rhs.is_positive() { Positive(lhs.saturating_mul(rhs as $inner)) } else { Negative(lhs.saturating_mul(-rhs as $inner)) } } Negative(lhs) => { if rhs.is_positive() { Negative(lhs.saturating_mul(rhs as $inner)) } else { Positive(lhs.saturating_mul(-rhs as $inner)) } } } } #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub fn saturating_mul_unsigned(self, rhs:$inner) -> Self { use crate::Signed::*; match self { Positive(lhs) => Positive(lhs.saturating_mul(rhs)), Negative(lhs) => Negative(lhs.saturating_mul(rhs)), } } } impl std::ops::Div<$signed_rhs> for crate::Signed<$typ> { type Output = Self; #[inline] fn div(self, rhs: $signed_rhs) -> Self { self.checked_div(rhs).expect("division overflowed") } } impl std::ops::DivAssign<$signed_rhs> for crate::Signed<$typ> { #[inline] fn div_assign(&mut self, rhs: $signed_rhs) { *self = std::ops::Div::div(*self, rhs); } } impl std::ops::Div<$inner> for crate::Signed<$typ> { type Output = Self; #[inline] fn div(self, rhs: $inner) -> Self { self.checked_div_unsigned(rhs).expect("division overflowed") } } impl std::ops::DivAssign<$inner> for crate::Signed<$typ> { #[inline] fn div_assign(&mut self, rhs: $inner) { *self = std::ops::Div::div(*self, rhs); } } impl std::ops::Rem<$signed_rhs> for crate::Signed<$typ> { type Output = Self; #[inline] fn rem(self, rhs: $signed_rhs) -> Self { self.checked_rem(rhs).expect("division overflowed") } } impl std::ops::RemAssign<$signed_rhs> for crate::Signed<$typ> { #[inline] fn rem_assign(&mut self, rhs: $signed_rhs) { *self = std::ops::Rem::rem(*self, rhs); } } impl std::ops::Rem<$inner> for crate::Signed<$typ> { type Output = Self; #[inline] fn rem(self, rhs: $inner) -> Self { self.checked_rem_unsigned(rhs).expect("division overflowed") } } impl std::ops::RemAssign<$inner> for crate::Signed<$typ> { #[inline] fn rem_assign(&mut self, rhs: $inner) { *self = std::ops::Rem::rem(*self, rhs); } } impl std::ops::Mul<$signed_rhs> for crate::Signed<$typ> { type Output = Self; #[inline] fn mul(self, rhs: $signed_rhs) -> Self { self.checked_mul(rhs).expect("multiplication overflowed") } } impl std::ops::MulAssign<$signed_rhs> for crate::Signed<$typ> { #[inline] fn mul_assign(&mut self, rhs: $signed_rhs) { *self = std::ops::Mul::mul(*self, rhs); } } impl std::ops::Mul<$inner> for crate::Signed<$typ> { type Output = Self; #[inline] fn mul(self, rhs: $inner) -> Self { self.checked_mul_unsigned(rhs).expect("multiplication overflowed") } } impl std::ops::MulAssign<$inner> for crate::Signed<$typ> { #[inline] fn mul_assign(&mut self, rhs: $inner) { *self = std::ops::Mul::mul(*self, rhs); } } impl opt_ops::OptionCheckedDiv<$signed_rhs> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_div(self, rhs: $signed_rhs) -> Result, opt_ops::Error> { if rhs == 0 { return Err(opt_ops::Error::DivisionByZero); } self.checked_div(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionCheckedMul<$signed_rhs> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_mul(self, rhs: $signed_rhs) -> Result, opt_ops::Error> { self.checked_mul(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionSaturatingMul<$signed_rhs> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_saturating_mul(self, rhs: $signed_rhs) -> Option { Some(self.saturating_mul(rhs)) } } impl opt_ops::OptionCheckedRem<$signed_rhs> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_rem(self, rhs: $signed_rhs) -> Result, opt_ops::Error> { if rhs == 0 { return Err(opt_ops::Error::DivisionByZero); } self.checked_rem(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionCheckedDiv<$inner> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_div(self, rhs: $inner) -> Result, opt_ops::Error> { if rhs == 0 { return Err(opt_ops::Error::DivisionByZero); } self.checked_div_unsigned(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionCheckedMul<$inner> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_mul(self, rhs: $inner) -> Result, opt_ops::Error> { self.checked_mul_unsigned(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } impl opt_ops::OptionSaturatingMul<$inner> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_saturating_mul(self, rhs: $inner) -> Option { Some(self.saturating_mul_unsigned(rhs)) } } impl opt_ops::OptionCheckedRem<$inner> for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_rem(self, rhs: $inner) -> Result, opt_ops::Error> { if rhs == 0 { return Err(opt_ops::Error::DivisionByZero); } self.checked_rem_unsigned(rhs) .ok_or(opt_ops::Error::Overflow) .map(Some) } } }; ); macro_rules! impl_signed_extra_div_mul( ($typ:ty, $signed:ty) => { impl std::ops::Div for crate::Signed<$typ> { type Output = Self; #[inline] fn div(self, rhs: Self) -> Self { match rhs { crate::Signed::Positive(rhs) => self.div(rhs), crate::Signed::Negative(rhs) => std::ops::Neg::neg(self.div(rhs)), } } } impl std::ops::Rem for crate::Signed<$typ> { type Output = Self; #[inline] fn rem(self, rhs: Self) -> Self { self.rem(rhs.abs()) } } impl opt_ops::OptionCheckedDiv for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_div(self, rhs: Self) -> Result, opt_ops::Error> { match rhs { crate::Signed::Positive(rhs) => self.opt_checked_div(rhs), crate::Signed::Negative(rhs) => { self.opt_checked_div(rhs) .map(|res| res.map(std::ops::Neg::neg)) } } } } impl opt_ops::OptionCheckedRem for crate::Signed<$typ> { type Output = Self; #[inline] fn opt_checked_rem(self, rhs: Self) -> Result, opt_ops::Error> { self.opt_checked_rem(rhs.abs()) } } }; ($newtyp:ty, $inner:ty, $signed_inner:ty) => { impl std::ops::Div for crate::Signed<$newtyp> { type Output = crate::Signed<$inner>; #[inline] fn div(self, rhs: Self) -> Self::Output { self.into_inner_signed().div(rhs.into_inner_signed()) } } impl std::ops::Rem for crate::Signed<$newtyp> { type Output = Self; #[inline] fn rem(self, rhs: Self) -> Self { self.rem(rhs.abs().0) } } impl std::ops::Mul> for $inner { type Output = crate::Signed<$newtyp>; #[inline] fn mul(self, rhs: crate::Signed<$newtyp>) -> Self::Output { rhs.mul(self) } } impl std::ops::Mul> for $signed_inner { type Output = crate::Signed<$newtyp>; #[inline] fn mul(self, rhs: crate::Signed<$newtyp>) -> Self::Output { rhs.mul(self) } } impl opt_ops::OptionCheckedDiv for crate::Signed<$newtyp> { type Output = crate::Signed<$inner>; #[inline] fn opt_checked_div(self, rhs: Self) -> Result, opt_ops::Error> { self.into_inner_signed().opt_checked_div(rhs.into_inner_signed()) } } impl opt_ops::OptionCheckedRem for crate::Signed<$newtyp> { type Output = crate::Signed<$inner>; #[inline] fn opt_checked_rem(self, rhs: Self) -> Result, opt_ops::Error> { self.into_inner_signed().opt_checked_rem(rhs.abs().0) } } impl opt_ops::OptionCheckedMul> for $signed_inner { type Output = crate::Signed<$newtyp>; #[inline] fn opt_checked_mul(self, rhs: crate::Signed<$newtyp>) -> Result, opt_ops::Error> { rhs.opt_checked_mul(self) } } impl opt_ops::OptionSaturatingMul> for $signed_inner { type Output = crate::Signed<$newtyp>; #[inline] fn opt_saturating_mul(self, rhs: crate::Signed<$newtyp>) -> Option { rhs.opt_saturating_mul(self) } } impl opt_ops::OptionCheckedMul> for $inner { type Output = crate::Signed<$newtyp>; #[inline] fn opt_checked_mul(self, rhs: crate::Signed<$newtyp>) -> Result, opt_ops::Error> { rhs.opt_checked_mul(self) } } impl opt_ops::OptionSaturatingMul> for $inner { type Output = crate::Signed<$newtyp>; #[inline] fn opt_saturating_mul(self, rhs: crate::Signed<$newtyp>) -> Option { rhs.opt_saturating_mul(self) } } }; ); macro_rules! impl_signed_div_mul_trait( ($typ:ty, $inner:ty, $signed_rhs:ty, $into_inner:expr) => { #[allow(clippy::redundant_closure_call)] impl muldiv::MulDiv<$signed_rhs> for crate::Signed<$typ> { type Output = Self; #[inline] fn mul_div_floor(self, num: $signed_rhs, denom: $signed_rhs) -> Option { use crate::Signed::*; match self { Positive(lhs) => { $into_inner(lhs) .mul_div_floor(num.unsigned_abs(), denom.unsigned_abs()) .and_then(|val| Self::signed_from_inner(val, num.signum() * denom.signum())) } Negative(lhs) => { $into_inner(lhs) .mul_div_floor(num.unsigned_abs(), denom.unsigned_abs()) .and_then(|val| Self::signed_from_inner(val, -num.signum() * denom.signum())) } } } #[inline] fn mul_div_round(self, num: $signed_rhs, denom: $signed_rhs) -> Option { use crate::Signed::*; match self { Positive(lhs) => { $into_inner(lhs) .mul_div_round(num.unsigned_abs(), denom.unsigned_abs()) .and_then(|val| Self::signed_from_inner(val, num.signum() * denom.signum())) } Negative(lhs) => { $into_inner(lhs) .mul_div_round(num.unsigned_abs(), denom.unsigned_abs()) .and_then(|val| Self::signed_from_inner(val, -num.signum() * denom.signum())) } } } #[inline] fn mul_div_ceil(self, num: $signed_rhs, denom: $signed_rhs) -> Option { use crate::Signed::*; match self { Positive(lhs) => { $into_inner(lhs) .mul_div_ceil(num.unsigned_abs(), denom.unsigned_abs()) .and_then(|val| Self::signed_from_inner(val, num.signum() * denom.signum())) } Negative(lhs) => { $into_inner(lhs) .mul_div_ceil(num.unsigned_abs(), denom.unsigned_abs()) .and_then(|val| Self::signed_from_inner(val, -num.signum() * denom.signum())) } } } } #[allow(clippy::redundant_closure_call)] impl muldiv::MulDiv<$inner> for crate::Signed<$typ> { type Output = Self; #[inline] fn mul_div_floor(self, num: $inner, denom: $inner) -> Option { use crate::Signed::*; match self { Positive(lhs) => { $into_inner(lhs) .mul_div_floor(num, denom) .and_then(Self::positive_from_inner) } Negative(lhs) => { $into_inner(lhs) .mul_div_floor(num, denom) .and_then(Self::negative_from_inner) } } } #[inline] fn mul_div_round(self, num: $inner, denom: $inner) -> Option { use crate::Signed::*; match self { Positive(lhs) => { $into_inner(lhs) .mul_div_round(num, denom) .and_then(Self::positive_from_inner) } Negative(lhs) => { $into_inner(lhs) .mul_div_round(num, denom) .and_then(Self::negative_from_inner) } } } #[inline] fn mul_div_ceil(self, num: $inner, denom: $inner) -> Option { use crate::Signed::*; match self { Positive(lhs) => { $into_inner(lhs) .mul_div_ceil(num, denom) .and_then(Self::positive_from_inner) } Negative(lhs) => { $into_inner(lhs) .mul_div_ceil(num, denom) .and_then(Self::negative_from_inner) } } } } }; ); macro_rules! impl_format_value_traits( ($typ:ty, $format:ident, $format_value:ident, $inner:ty) => { impl FormattedValue for Option<$typ> { type FullRange = Self; #[inline] fn default_format() -> Format { Format::$format } #[inline] fn format(&self) -> Format { Format::$format } #[inline] fn is_some(&self) -> bool { Option::is_some(self) } #[inline] unsafe fn into_raw_value(self) -> i64 { IntoGlib::into_glib(self) as i64 } } impl FormattedValueFullRange for Option<$typ> { #[inline] unsafe fn from_raw(format: Format, value: i64) -> Self { debug_assert_eq!(format, Format::$format); FromGlib::from_glib(value as u64) } } impl FormattedValueNoneBuilder for Option<$typ> { #[inline] fn none() -> Option<$typ> { None } } impl From> for GenericFormattedValue { #[inline] fn from(v: Option<$typ>) -> Self { skip_assert_initialized!(); Self::$format_value(v) } } impl From<$typ> for GenericFormattedValue { #[inline] fn from(v: $typ) -> Self { skip_assert_initialized!(); Self::$format_value(Some(v)) } } impl FormattedValue for $typ { type FullRange = Option<$typ>; #[inline] fn default_format() -> Format { Format::$format } #[inline] fn format(&self) -> Format { Format::$format } #[inline] fn is_some(&self) -> bool { true } #[inline] unsafe fn into_raw_value(self) -> i64 { IntoGlib::into_glib(self) as i64 } } impl SpecificFormattedValue for Option<$typ> {} impl SpecificFormattedValueFullRange for Option<$typ> {} impl SpecificFormattedValue for $typ {} impl FormattedValueIntrinsic for $typ {} impl SpecificFormattedValueIntrinsic for $typ {} impl TryFrom for Option<$typ> { type Error = FormattedValueError; #[inline] fn try_from(v: GenericFormattedValue) -> Result { skip_assert_initialized!(); if let GenericFormattedValue::$format_value(v) = v { Ok(v) } else { Err(FormattedValueError(v.format())) } } } impl TryFrom<$inner> for $typ { type Error = GlibNoneError; #[inline] fn try_from(v: $inner) -> Result { skip_assert_initialized!(); unsafe { Self::try_from_glib(v as i64) } } } impl TryFromGlib for $typ { type Error = GlibNoneError; #[inline] unsafe fn try_from_glib(val: i64) -> Result { skip_assert_initialized!(); <$typ as TryFromGlib>::try_from_glib(val as u64) } } }; ); macro_rules! option_glib_newtype_from_to { ($typ:ident, $none_value:expr) => { #[doc(hidden)] impl IntoGlib for $typ { type GlibType = u64; #[inline] fn into_glib(self) -> u64 { assert_ne!( self.0, $none_value, concat!( "attempt to build a `None` glib variant", "from a non-`Option` type ", stringify!($typ), ), ); self.0 } } #[doc(hidden)] impl OptionIntoGlib for $typ { const GLIB_NONE: u64 = $none_value; } #[doc(hidden)] impl TryFromGlib for $typ { type Error = GlibNoneError; #[inline] unsafe fn try_from_glib(val: u64) -> Result { skip_assert_initialized!(); if val == $none_value { return Err(GlibNoneError); } Ok($typ(val)) } } }; } // FIXME we could automatically build `$displayable_option_name` // if `concat_idents!` was stable. // See: https://doc.rust-lang.org/std/macro.concat_idents.html macro_rules! glib_newtype_display { ($typ:ty) => { impl std::fmt::Display for $typ { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { std::fmt::Display::fmt(&self.0, f) } } impl crate::utils::Displayable for $typ { type DisplayImpl = Self; fn display(self) -> Self { self } } }; ($typ:ty, Format::$format:ident) => { impl std::fmt::Display for $typ { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { std::fmt::Display::fmt(&self.0, f)?; std::fmt::Write::write_char(f, ' ')?; std::fmt::Display::fmt(&Format::$format, f) } } impl crate::utils::Displayable for $typ { type DisplayImpl = Self; fn display(self) -> Self { self } } }; ($typ:ty, $displayable_option_name:ident) => { glib_newtype_display!($typ); pub struct $displayable_option_name(Option<$typ>); impl std::fmt::Display for $displayable_option_name { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { if let Some(val) = self.0.as_ref() { std::fmt::Display::fmt(val, f) } else { f.write_str("undef.") } } } impl crate::utils::Displayable for Option<$typ> { type DisplayImpl = $displayable_option_name; fn display(self) -> Self::DisplayImpl { $displayable_option_name(self) } } }; ($typ:ty, $displayable_option_name:ident, Format::$format:ident) => { glib_newtype_display!($typ, Format::$format); pub struct $displayable_option_name(Option<$typ>); impl std::fmt::Display for $displayable_option_name { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { if let Some(val) = self.0.as_ref() { std::fmt::Display::fmt(val, f) } else { write!(f, "undef. {}", Format::$format) } } } impl crate::utils::Displayable for Option<$typ> { type DisplayImpl = $displayable_option_name; fn display(self) -> Self::DisplayImpl { $displayable_option_name(self) } } }; } macro_rules! impl_signed_int_into_signed( (u64) => { impl_signed_int_into_signed!(u64, u64, i64, |val: u64| val); }; (usize) => { impl_signed_int_into_signed!(usize, usize, isize, |val: usize| val); }; (u32) => { impl_signed_int_into_signed!(u32, u32, i32, |val: u32| val); }; ($newtyp:ty, u64) => { impl_signed_int_into_signed!($newtyp, u64, i64, |val: $newtyp| *val); }; ($newtyp:ty, u32) => { impl_signed_int_into_signed!($newtyp, u32, i32, |val: $newtyp| *val); }; ($typ:ty, $inner:ty, $signed:ty, $into_inner:expr) => { #[allow(clippy::redundant_closure_call)] impl TryFrom> for $signed { type Error = std::num::TryFromIntError; #[inline] fn try_from(value: crate::Signed<$typ>) -> Result<$signed, Self::Error> { assert_eq!(::std::mem::size_of::<$inner>(), ::std::mem::size_of::<$signed>()); match value { crate::Signed::Positive(value) => <$signed>::try_from($into_inner(value)), crate::Signed::Negative(value) => { let inner = $into_inner(value); // `$signed::MIN.abs()` can't be represented as an `$signed` if inner == (<$inner>::MAX >> 1) + 1 { Ok(<$signed>::MIN) } else { Ok(-<$signed>::try_from(inner)?) } }, } } } impl From<$signed> for crate::Signed<$typ> { #[inline] fn from(value: $signed) -> crate::Signed<$typ> { let abs = value.unsigned_abs(); if value.signum() >= 0 { Self::positive_from_inner(abs).unwrap() } else { Self::negative_from_inner(abs).unwrap() } } } }; ); gstreamer-0.23.5/src/format/mod.rs000064400000000000000000001074671046102023000151270ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. // rustdoc-stripper-ignore-next //! This module gathers GStreamer's formatted value concepts together. //! //! GStreamer uses formatted values to differentiate value units in some APIs. //! In C this is done by qualifying an integer value by a companion enum //! [`GstFormat`]. In Rust, most APIs can use a specific type for each format. //! Each format type embeds the actual value using the new type pattern. //! //! # Specific Formatted Values //! //! Examples of specific formatted values include [`ClockTime`], [`Buffers`], etc. //! These types represent both the quantity and the unit making it possible for Rust //! to perform runtime and, to a certain extent, compile time invariants enforcement. //! //! Specific formatted values are also guaranteed to always represent a valid value. //! For instance: //! //! - [`Percent`] only allows values in the integer range [0, 1_000_000] or //! float range [0.0, 1.0]. //! - [`ClockTime`] can use all `u64` values except `u64::MAX` which is reserved by //! the C constant `GST_CLOCK_TIME_NONE`. //! //! ## Examples //! //! ### Querying the pipeline for a time position //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::ElementExtManual; //! # gst::init(); //! # let pipeline = gst::Pipeline::new(); //! let res = pipeline.query_position::(); //! ``` //! //! ## Seeking to a specific time position //! //! ``` //! # use gstreamer as gst; //! # use gst::{format::prelude::*, prelude::ElementExtManual}; //! # gst::init(); //! # let pipeline = gst::Pipeline::new(); //! # let seek_flags = gst::SeekFlags::FLUSH | gst::SeekFlags::KEY_UNIT; //! let seek_pos = gst::ClockTime::from_seconds(10); //! let res = pipeline.seek_simple(seek_flags, seek_pos); //! ``` //! //! ### Downcasting a `Segment` for specific formatted value use //! //! ``` //! # use gstreamer as gst; //! # use gst::format::FormattedValue; //! # gst::init(); //! # let segment = gst::FormattedSegment::::new().upcast(); //! // Downcasting the generic `segment` for `gst::ClockTime` use. //! let time_segment = segment.downcast_ref::().expect("time segment"); //! // Setters and getters conform to `gst::ClockTime`. //! // This is enforced at compilation time. //! let start = time_segment.start(); //! assert_eq!(start.format(), gst::Format::Time); //! ``` //! //! ### Building a specific formatted value //! //! ``` //! # use gstreamer as gst; //! use gst::prelude::*; //! use gst::format::{Buffers, Bytes, ClockTime, Default, Percent}; //! //! // Specific formatted values implement the faillible `try_from` constructor: //! let default = Default::try_from(42).unwrap(); //! assert_eq!(*default, 42); //! assert_eq!(Default::try_from(42), Ok(default)); //! assert_eq!(Default::try_from(42).ok(), Some(default)); //! //! // `ClockTime` provides specific `const` constructors, //! // which can panic if the requested value is out of range. //! let time = ClockTime::from_nseconds(45_834_908_569_837); //! let time = ClockTime::from_seconds(20); //! //! // Other formatted values also come with (panicking) `const` constructors: //! let buffers_nb = Buffers::from_u64(512); //! let received = Bytes::from_u64(64); //! let quantity = Default::from_u64(42); //! //! // `Bytes` can be built from an `usize` too (not `const`): //! let sample_size = Bytes::from_usize([0u8; 4].len()); //! //! // This can be convenient (not `const`): //! assert_eq!( //! 7.seconds() + 250.mseconds(), //! ClockTime::from_nseconds(7_250_000_000), //! ); //! //! // Those too (not `const`): //! assert_eq!(512.buffers(), Buffers::from_u64(512)); //! assert_eq!(64.bytes(), Bytes::from_u64(64)); //! assert_eq!(42.default_format(), Default::from_u64(42)); //! //! // The `ZERO` and `NONE` constants can come in handy sometimes: //! assert_eq!(*Buffers::ZERO, 0); //! assert!(ClockTime::NONE.is_none()); //! //! // Specific formatted values provide the constant `ONE` value: //! assert_eq!(*Buffers::ONE, 1); //! //! // `Bytes` also comes with usual multipliers (not `const`): //! assert_eq!(*(512.kibibytes()), 512 * 1024); //! assert_eq!(*(8.mebibytes()), 8 * 1024 * 1024); //! assert_eq!(*(4.gibibytes()), 4 * 1024 * 1024 * 1024); //! //! // ... and the matching constants: //! assert_eq!(512 * Bytes::KiB, 512.kibibytes()); //! //! // `Percent` can be built from a percent integer value: //! let a_quarter = 25.percent(); //! assert_eq!(a_quarter.percent(), 25); //! assert_eq!(a_quarter.ppm(), 250000); //! assert_eq!(a_quarter.ratio(), 0.25); //! // ... from a floating point ratio: //! let a_quarter_from_ratio = 0.25.percent_ratio(); //! assert_eq!(a_quarter, a_quarter_from_ratio); //! // ... from a part per million integer value: //! let a_quarter_from_ppm = (25 * 10_000).ppm(); //! assert_eq!(a_quarter, a_quarter_from_ppm); //! // ... `MAX` which represents 100%: //! assert_eq!(Percent::MAX / 4, a_quarter); //! // ... `ONE` which is 1%: //! assert_eq!(25 * Percent::ONE, a_quarter); //! // ... and `SCALE` which is 1% in ppm: //! assert_eq!(Percent::SCALE, 10_000.ppm()); //! ``` //! //! ### Displaying a formatted value //! //! Formatted values implement the [`Display`] trait which allows getting //! human readable representations. //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::*; //! let time = 45_834_908_569_837.nseconds(); //! //! assert_eq!(format!("{time}"), "12:43:54.908569837"); //! assert_eq!(format!("{time:.0}"), "12:43:54"); //! //! let percent = 0.1234.percent_ratio(); //! assert_eq!(format!("{percent}"), "12.34 %"); //! assert_eq!(format!("{percent:5.1}"), " 12.3 %"); //! ``` //! //! ## Some operations available on specific formatted values //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::*; //! let cur_pos = gst::ClockTime::ZERO; //! //! // All four arithmetic operations can be used: //! let fwd = cur_pos + 2.seconds() / 3 - 5.mseconds(); //! //! // Examples of operations which make sure not to overflow: //! let bwd = cur_pos.saturating_sub(2.seconds()); //! let further = cur_pos.checked_mul(2).expect("Overflowed"); //! //! // Specific formatted values can be compared: //! assert!(fwd > bwd); //! assert_ne!(fwd, cur_pos); //! //! # fn next() -> gst::ClockTime { gst::ClockTime::ZERO }; //! // Use `gst::ClockTime::MAX` for the maximum valid value: //! let mut min_pos = gst::ClockTime::MAX; //! for _ in 0..4 { //! min_pos = min_pos.min(next()); //! } //! //! // And `gst::ClockTime::ZERO` for the minimum value: //! let mut max_pos = gst::ClockTime::ZERO; //! for _ in 0..4 { //! max_pos = max_pos.max(next()); //! } //! //! // Specific formatted values implement the `MulDiv` trait: //! # use gst::prelude::MulDiv; //! # let (samples, rate) = (1024u64, 48_000u64); //! let duration = samples //! .mul_div_round(*gst::ClockTime::SECOND, rate) //! .map(gst::ClockTime::from_nseconds); //! ``` //! //! ## Types in operations //! //! Additions and substractions are available with the specific formatted value type //! as both left and right hand side operands. //! //! On the other hand, multiplications are only available with plain integers. //! This is because multiplying a `ClockTime` by a `ClockTime` would result in //! `ClockTime²`, whereas a `u64 * ClockTime` (or `ClockTime * u64`) still //! results in `ClockTime`. //! //! Divisions are available with both the specific formatted value and plain //! integers as right hand side operands. The difference is that //! `ClockTime / ClockTime` results in `u64` and `ClockTime / u64` results in //! `ClockTime`. //! //! # Optional specific formatted values //! //! Optional specific formatted values are represented as a standard Rust //! `Option`. This departs from the C APIs which use a sentinel that must //! be checked in order to figure out whether the value is defined. //! //! Besides giving access to the usual `Option` features, this ensures the APIs //! enforce mandatory or optional variants whenever possible. //! //! Note: for each specific formatted value `F`, the constant `F::NONE` is defined //! as a shortcut for `Option::::None`. For `gst::ClockTime`, this constant is //! equivalent to the C constant `GST_CLOCK_TIME_NONE`. //! //! ## Examples //! //! ### Building a seek `Event` with undefined `stop` time //! //! ``` //! # use gstreamer as gst; //! # use gst::format::prelude::*; //! # gst::init(); //! # let seek_flags = gst::SeekFlags::FLUSH | gst::SeekFlags::KEY_UNIT; //! let seek_evt = gst::event::Seek::new( //! 1.0f64, //! seek_flags, //! gst::SeekType::Set, //! 10.seconds(), // start at 10s //! gst::SeekType::Set, //! gst::ClockTime::NONE, // stop is undefined //! ); //! ``` //! //! ### Displaying an optional formatted value //! //! Optional formatted values can take advantage of the [`Display`] implementation //! of the base specific formatted value. We have to workaround the [orphan rule] //! that forbids the implementation of [`Display`] for `Option` //! though. This is why displaying an optional formatted value necessitates calling //! [`display()`]. //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::*; //! let opt_time = Some(45_834_908_569_837.nseconds()); //! //! assert_eq!(format!("{}", opt_time.display()), "12:43:54.908569837"); //! assert_eq!(format!("{:.0}", opt_time.display()), "12:43:54"); //! assert_eq!(format!("{:.0}", gst::ClockTime::NONE.display()), "--:--:--"); //! ``` //! //! ### Some operations available on optional formatted values //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::*; //! let pts = Some(gst::ClockTime::ZERO); //! assert!(pts.is_some()); //! //! // All four arithmetic operations can be used. Ex.: //! let fwd = pts.opt_add(2.seconds()); //! // `pts` is defined, so `fwd` will contain the addition result in `Some`, //! assert!(fwd.is_some()); //! // otherwise `fwd` would be `None`. //! //! // Examples of operations which make sure not to overflow: //! let bwd = pts.opt_saturating_sub(2.seconds()); //! let further = pts.opt_checked_mul(2).expect("Overflowed"); //! //! // Optional specific formatted values can be compared: //! assert_eq!(fwd.opt_gt(bwd), Some(true)); //! assert_ne!(fwd, pts); //! assert_eq!(fwd.opt_min(bwd), bwd); //! //! // Optional specific formatted values operations also apply to non-optional values: //! assert_eq!(fwd.opt_lt(gst::ClockTime::SECOND), Some(false)); //! assert_eq!(gst::ClockTime::SECOND.opt_lt(fwd), Some(true)); //! //! // Comparing a defined values to an undefined value results in `None`: //! assert_eq!(bwd.opt_gt(gst::ClockTime::NONE), None); //! assert_eq!(gst::ClockTime::ZERO.opt_lt(gst::ClockTime::NONE), None); //! ``` //! //! # Signed formatted values //! //! Some APIs can return a signed formatted value. See [`Segment::to_running_time_full`] //! for an example. In Rust, we use the [`Signed`] enum wrapper around the actual //! formatted value. //! //! For each signed specific formatted value `F`, the constants `F::MIN_SIGNED` and //! `F::MAX_SIGNED` represent the minimum and maximum signed values for `F`. //! //! ## Examples //! //! ### Handling a signed formatted value //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::*; //! # gst::init(); //! # let segment = gst::FormattedSegment::::new(); //! use gst::Signed::*; //! match segment.to_running_time_full(2.seconds()) { //! Some(Positive(pos_rtime)) => println!("positive rtime {pos_rtime}"), //! Some(Negative(neg_rtime)) => println!("negative rtime {neg_rtime}"), //! None => println!("undefined rtime"), //! } //! ``` //! //! ### Converting a formatted value into a signed formatted value //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::*; //! let step = 10.mseconds(); //! //! let positive_step = step.into_positive(); //! assert!(positive_step.is_positive()); //! //! let negative_step = step.into_negative(); //! assert!(negative_step.is_negative()); //! ``` //! //! ### Handling one sign only //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::*; //! # struct NegativeError; //! let pos_step = 10.mseconds().into_positive(); //! assert!(pos_step.is_positive()); //! //! let abs_step_or_panic = pos_step.positive().expect("positive"); //! let abs_step_or_zero = pos_step.positive().unwrap_or(gst::ClockTime::ZERO); //! //! let abs_step_or_err = pos_step.positive_or(NegativeError); //! let abs_step_or_else_err = pos_step.positive_or_else(|step| { //! println!("{step} is negative"); //! NegativeError //! }); //! ``` //! //! ### Displaying a signed formatted value //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::*; //! # gst::init(); //! # let mut segment = gst::FormattedSegment::::new(); //! # segment.set_start(10.seconds()); //! let start = segment.start().unwrap(); //! assert_eq!(format!("{start:.0}"), "0:00:10"); //! //! let p_rtime = segment.to_running_time_full(20.seconds()); //! // Use `display()` with optional signed values. //! assert_eq!(format!("{:.0}", p_rtime.display()), "+0:00:10"); //! //! let p_rtime = segment.to_running_time_full(gst::ClockTime::ZERO); //! assert_eq!(format!("{:.0}", p_rtime.display()), "-0:00:10"); //! //! let p_rtime = segment.to_running_time_full(gst::ClockTime::NONE); //! assert_eq!(format!("{:.0}", p_rtime.display()), "--:--:--"); //! ``` //! //! ## Some operations available for signed formatted values //! //! All the operations available for formatted values can be used with //! signed formatted values. //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::*; //! let p_one_sec = gst::ClockTime::SECOND.into_positive(); //! let p_two_sec = 2.seconds().into_positive(); //! let n_one_sec = gst::ClockTime::SECOND.into_negative(); //! //! assert_eq!(p_one_sec + p_one_sec, p_two_sec); //! assert_eq!(p_two_sec - p_one_sec, p_one_sec); //! assert_eq!(gst::ClockTime::ZERO - p_one_sec, n_one_sec); //! assert_eq!(p_one_sec * 2u64, p_two_sec); //! assert_eq!(n_one_sec * -1i64, p_one_sec); //! assert_eq!(p_two_sec / 2u64, p_one_sec); //! assert_eq!(p_two_sec / p_one_sec, 2); //! //! // Examples of operations which make sure not to overflow: //! assert_eq!(p_one_sec.saturating_sub(p_two_sec), n_one_sec); //! assert_eq!(p_one_sec.checked_mul(2), Some(p_two_sec)); //! //! // Signed formatted values can be compared: //! assert!(p_one_sec > n_one_sec); //! //! # fn next() -> gst::Signed { gst::ClockTime::ZERO.into_positive() }; //! // Use `gst::ClockTime::MAX_SIGNED` for the maximum valid signed value: //! let mut min_signed_pos = gst::ClockTime::MAX_SIGNED; //! for _ in 0..4 { //! min_signed_pos = min_signed_pos.min(next()); //! } //! //! // And `gst::ClockTime::MIN_SIGNED` for the minimum valid signed value: //! let mut max_signed_pos = gst::ClockTime::MIN_SIGNED; //! for _ in 0..4 { //! max_signed_pos = max_signed_pos.max(next()); //! } //! //! // Signed formatted values implement the `MulDiv` trait: //! # use gst::prelude::*; //! # let rate = 48_000u64; //! let samples = 1024.default_format().into_negative(); //! let duration = samples //! .mul_div_round(*gst::ClockTime::SECOND, rate) //! .map(|signed_default| { //! let signed_u64 = signed_default.into_inner_signed(); //! gst::Signed::::from_nseconds(signed_u64) //! }) //! .unwrap(); //! assert!(duration.is_negative()); //! ``` //! //! ### Some operations available for optional signed formatted values //! //! All the operations available for optional formatted values can be used //! with signed formatted values. //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::*; //! let p_one_sec = 1.seconds().into_positive(); //! let p_two_sec = 2.seconds().into_positive(); //! let n_one_sec = 1.seconds().into_negative(); //! //! // Signed `ClockTime` addition with optional and non-optional operands. //! assert_eq!(Some(p_one_sec).opt_add(p_one_sec), Some(p_two_sec)); //! assert_eq!(p_two_sec.opt_add(Some(n_one_sec)), Some(p_one_sec)); //! //! // This can also be used with unsigned formatted values. //! assert_eq!(Some(p_one_sec).opt_add(gst::ClockTime::SECOND), Some(p_two_sec)); //! //! // Etc... //! ``` //! //! # Generic Formatted Values //! //! Sometimes, generic code can't assume a specific format will be used. For such //! use cases, the [`GenericFormattedValue`] enum makes it possible to select //! the appropriate behaviour at runtime. //! //! Most variants embed an optional specific formatted value. //! //! ## Example //! //! ### Generic handling of the position from a `SegmentDone` event //! //! ``` //! # use gstreamer as gst; //! # use gst::prelude::*; //! # gst::init(); //! # let event = gst::event::SegmentDone::new(512.buffers()); //! if let gst::EventView::SegmentDone(seg_done_evt) = event.view() { //! use gst::GenericFormattedValue::*; //! match seg_done_evt.get() { //! Buffers(buffers) => println!("Segment done @ {}", buffers.display()), //! Bytes(bytes) => println!("Segment done @ {}", bytes.display()), //! Time(time) => println!("Segment done @ {}", time.display()), //! other => println!("Unexpected format for Segment done position {other:?}"), //! } //! } //! ``` //! //! [`GstFormat`]: https://gstreamer.freedesktop.org/documentation/gstreamer/gstformat.html?gi-language=c //! [`ClockTime`]: struct.ClockTime.html //! [`Buffers`]: struct.Buffers.html //! [`Percent`]: struct.Percent.html //! [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html //! [`display()`]: ../prelude/trait.Displayable.html //! [orphan rule]: https://doc.rust-lang.org/book/ch10-02-traits.html?highlight=orphan#implementing-a-trait-on-a-type //! [`Segment::to_running_time_full`]: ../struct.FormattedSegment.html#method.to_running_time_full //! [`Signed`]: enum.Signed.html //! [`GenericFormattedValue`]: generic/enum.GenericFormattedValue.html use thiserror::Error; #[macro_use] mod macros; mod clock_time; pub use clock_time::*; #[cfg(feature = "serde")] mod clock_time_serde; mod compatible; pub use compatible::*; #[cfg(feature = "serde")] mod format_serde; mod generic; pub use generic::*; mod signed; pub use signed::*; mod specific; pub use specific::*; mod undefined; pub use undefined::*; pub mod prelude { pub use super::{ BuffersFormatConstructor, BytesFormatConstructor, DefaultFormatConstructor, FormattedValue, FormattedValueNoneBuilder, NoneSignedBuilder, OtherFormatConstructor, PercentFormatFloatConstructor, PercentFormatIntegerConstructor, TimeFormatConstructor, UndefinedFormatConstructor, UnsignedIntoSigned, }; } use crate::Format; #[derive(Clone, Copy, Debug, PartialEq, Eq, Error)] #[error("invalid formatted value format {:?}", .0)] pub struct FormattedValueError(Format); pub trait FormattedValue: Copy + Clone + Sized + Into + 'static { // rustdoc-stripper-ignore-next /// Type which allows building a `FormattedValue` of this format from any raw value. type FullRange: FormattedValueFullRange + From; #[doc(alias = "get_default_format")] fn default_format() -> Format; #[doc(alias = "get_format")] fn format(&self) -> Format; // rustdoc-stripper-ignore-next /// Returns `true` if this `FormattedValue` represents a defined value. fn is_some(&self) -> bool; // rustdoc-stripper-ignore-next /// Returns `true` if this `FormattedValue` represents an undefined value. fn is_none(&self) -> bool { !self.is_some() } unsafe fn into_raw_value(self) -> i64; } // rustdoc-stripper-ignore-next /// A [`FormattedValue`] which can be built from any raw value. /// /// # Examples: /// /// - `GenericFormattedValue` is the `FormattedValueFullRange` type for `GenericFormattedValue`. /// - `Undefined` is the `FormattedValueFullRange` type for `Undefined`. /// - `Option` is the `FormattedValueFullRange` type for `Percent`. pub trait FormattedValueFullRange: FormattedValue + TryFrom { unsafe fn from_raw(format: Format, value: i64) -> Self; } // rustdoc-stripper-ignore-next /// A trait implemented on the intrinsic type of a `FormattedValue`. /// /// # Examples /// /// - `GenericFormattedValue` is the intrinsic type for `GenericFormattedValue`. /// - `Undefined` is the intrinsic type for `Undefined`. /// - `Bytes` is the intrinsic type for `Option`. pub trait FormattedValueIntrinsic: FormattedValue {} pub trait FormattedValueNoneBuilder: FormattedValueFullRange { // rustdoc-stripper-ignore-next /// Returns the `None` value for `Self` as a `FullRange` if such a value can be represented. /// /// - For `SpecificFormattedValue`s, this results in `Option::::None`. /// - For `GenericFormattedValue`, this can only be obtained using [`Self::none_for_format`] /// because the `None` is an inner value of some of the variants. /// /// # Panics /// /// Panics if `Self` is `GenericFormattedValue` in which case, the `Format` must be known. fn none() -> Self; // rustdoc-stripper-ignore-next /// Returns the `None` value for `Self` if such a value can be represented. /// /// - For `SpecificFormattedValue`s, this is the same as `Self::none()` /// if the `format` matches the `SpecificFormattedValue`'s format. /// - For `GenericFormattedValue` this is the variant for the specified `format`, /// initialized with `None` as a value, if the `format` can represent that value. /// /// # Panics /// /// Panics if `None` can't be represented by `Self` for `format` or by the requested /// `GenericFormattedValue` variant. #[track_caller] #[inline] fn none_for_format(format: Format) -> Self { skip_assert_initialized!(); // This is the default impl. `GenericFormattedValue` must override. if Self::default_format() != format { panic!( "Expected: {:?}, requested {format:?}", Self::default_format() ); } Self::none() } } use std::fmt; impl fmt::Display for Format { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::Undefined => f.write_str("undefined"), Self::Default => f.write_str("default"), Self::Bytes => f.write_str("bytes"), Self::Time => f.write_str("time"), Self::Buffers => f.write_str("buffers"), Self::Percent => f.write_str("%"), Self::__Unknown(format) => write!(f, "(format: {format})"), } } } #[cfg(test)] mod tests { use super::*; use crate::utils::Displayable; fn with_compatible_formats( arg1: V1, arg2: V2, ) -> Result where V1: FormattedValue, V2: CompatibleFormattedValue, { skip_assert_initialized!(); arg2.try_into_checked(arg1) } #[test] fn compatible() { assert_eq!( with_compatible_formats(ClockTime::ZERO, ClockTime::ZERO), Ok(ClockTime::ZERO), ); assert_eq!( with_compatible_formats(ClockTime::ZERO, ClockTime::NONE), Ok(ClockTime::NONE), ); assert_eq!( with_compatible_formats(ClockTime::NONE, ClockTime::ZERO), Ok(ClockTime::ZERO), ); assert_eq!( with_compatible_formats( ClockTime::ZERO, GenericFormattedValue::Time(Some(ClockTime::ZERO)), ), Ok(GenericFormattedValue::Time(Some(ClockTime::ZERO))), ); assert_eq!( with_compatible_formats( GenericFormattedValue::Time(Some(ClockTime::ZERO)), ClockTime::NONE, ), Ok(ClockTime::NONE), ); } #[test] fn incompatible() { with_compatible_formats( ClockTime::ZERO, GenericFormattedValue::Buffers(Some(42.buffers())), ) .unwrap_err(); with_compatible_formats( GenericFormattedValue::Buffers(Some(42.buffers())), ClockTime::NONE, ) .unwrap_err(); } fn with_compatible_explicit(arg: V, f: Format) -> Result where T: FormattedValue, V: CompatibleFormattedValue, { skip_assert_initialized!(); arg.try_into_checked_explicit(f) } #[test] fn compatible_explicit() { assert_eq!( with_compatible_explicit::(ClockTime::ZERO, Format::Time), Ok(ClockTime::ZERO), ); assert_eq!( with_compatible_explicit::(ClockTime::NONE, Format::Time), Ok(ClockTime::NONE), ); assert_eq!( with_compatible_explicit::(ClockTime::ZERO, Format::Time), Ok(ClockTime::ZERO), ); assert_eq!( with_compatible_explicit::( GenericFormattedValue::Time(None), Format::Time ), Ok(GenericFormattedValue::Time(None)), ); assert_eq!( with_compatible_explicit::(ClockTime::NONE, Format::Time), Ok(ClockTime::NONE), ); } #[test] fn incompatible_explicit() { with_compatible_explicit::(GenericFormattedValue::Time(None), Format::Buffers) .unwrap_err(); with_compatible_explicit::(Buffers::ZERO, Format::Time) .unwrap_err(); with_compatible_explicit::( GenericFormattedValue::Time(None), Format::Buffers, ) .unwrap_err(); } #[test] fn none_builder() { let ct_none: Option = Option::::none(); assert!(ct_none.is_none()); let ct_none: Option = Option::::none_for_format(Format::Time); assert!(ct_none.is_none()); let gen_ct_none: GenericFormattedValue = GenericFormattedValue::none_for_format(Format::Time); assert!(gen_ct_none.is_none()); assert!(ClockTime::ZERO.is_some()); assert!(!ClockTime::ZERO.is_none()); } #[test] #[should_panic] fn none_for_inconsistent_format() { let _ = Option::::none_for_format(Format::Percent); } #[test] #[should_panic] fn none_for_unsupported_format() { let _ = GenericFormattedValue::none_for_format(Format::Undefined); } #[test] fn none_signed_builder() { let ct_none: Option> = Option::::none_signed(); assert!(ct_none.is_none()); let ct_none: Option> = Option::::none_signed_for_format(Format::Time); assert!(ct_none.is_none()); let gen_ct_none: GenericSignedFormattedValue = GenericFormattedValue::none_signed_for_format(Format::Time); assert!(gen_ct_none.abs().is_none()); } #[test] fn signed_optional() { let ct_1 = Some(ClockTime::SECOND); let signed = ct_1.into_positive().unwrap(); assert_eq!(signed, Signed::Positive(ClockTime::SECOND)); assert!(signed.is_positive()); assert_eq!(signed.positive_or(()).unwrap(), ClockTime::SECOND); assert_eq!(signed.positive_or_else(|_| ()).unwrap(), ClockTime::SECOND); signed.negative_or(()).unwrap_err(); assert_eq!( signed.negative_or_else(|val| val).unwrap_err(), ClockTime::SECOND ); let signed = ct_1.into_negative().unwrap(); assert_eq!(signed, Signed::Negative(ClockTime::SECOND)); assert!(signed.is_negative()); assert_eq!(signed.negative_or(()).unwrap(), ClockTime::SECOND); assert_eq!(signed.negative_or_else(|_| ()).unwrap(), ClockTime::SECOND); signed.positive_or(()).unwrap_err(); assert_eq!( signed.positive_or_else(|val| val).unwrap_err(), ClockTime::SECOND ); let ct_none = ClockTime::NONE; assert!(ct_none.into_positive().is_none()); assert!(ct_none.into_negative().is_none()); } #[test] fn signed_mandatory() { let ct_1 = ClockTime::SECOND; let signed = ct_1.into_positive(); assert_eq!(signed, Signed::Positive(ct_1)); assert!(signed.is_positive()); assert_eq!(signed.positive(), Some(ct_1)); assert!(!signed.is_negative()); assert!(signed.negative().is_none()); assert_eq!(signed.signum(), 1); let signed = ct_1.into_negative(); assert_eq!(signed, Signed::Negative(ct_1)); assert!(signed.is_negative()); assert_eq!(signed.negative(), Some(ct_1)); assert!(!signed.is_positive()); assert!(signed.positive().is_none()); assert_eq!(signed.signum(), -1); let signed = Default::ONE.into_positive(); assert_eq!(signed, Signed::Positive(Default::ONE)); assert!(signed.is_positive()); assert_eq!(signed.positive(), Some(Default::ONE)); assert!(!signed.is_negative()); assert!(signed.negative().is_none()); assert_eq!(signed.signum(), 1); let signed = Default::ONE.into_negative(); assert_eq!(signed, Signed::Negative(Default::ONE)); assert!(signed.is_negative()); assert_eq!(signed.negative(), Some(Default::ONE)); assert!(!signed.is_positive()); assert!(signed.positive().is_none()); assert_eq!(signed.signum(), -1); let ct_zero = ClockTime::ZERO; let p_ct_zero = ct_zero.into_positive(); assert!(p_ct_zero.is_positive()); assert!(!p_ct_zero.is_negative()); assert_eq!(p_ct_zero.signum(), 0); let n_ct_zero = ct_zero.into_negative(); assert!(n_ct_zero.is_negative()); assert!(!n_ct_zero.is_positive()); assert_eq!(n_ct_zero.signum(), 0); } #[test] fn signed_generic() { let ct_1 = GenericFormattedValue::Time(Some(ClockTime::SECOND)); assert!(ct_1.is_some()); let signed = ct_1.into_positive(); assert_eq!( signed, GenericSignedFormattedValue::Time(Some(Signed::Positive(ClockTime::SECOND))), ); assert_eq!(signed.is_positive(), Some(true)); assert_eq!(signed.is_negative(), Some(false)); assert_eq!(signed.signum(), Some(1)); let signed = ct_1.into_negative(); assert_eq!( signed, GenericSignedFormattedValue::Time(Some(Signed::Negative(ClockTime::SECOND))), ); assert_eq!(signed.is_negative(), Some(true)); assert_eq!(signed.is_positive(), Some(false)); assert_eq!(signed.signum(), Some(-1)); let ct_none = GenericFormattedValue::Time(ClockTime::NONE); assert!(ct_none.is_none()); let signed = ct_none.into_positive(); assert_eq!(signed, GenericSignedFormattedValue::Time(None),); assert!(signed.is_positive().is_none()); assert!(signed.is_negative().is_none()); assert!(signed.signum().is_none()); let signed = ct_none.into_negative(); assert_eq!(signed, GenericSignedFormattedValue::Time(None),); assert!(signed.is_negative().is_none()); assert!(signed.is_positive().is_none()); assert!(signed.signum().is_none()); let ct_zero = GenericFormattedValue::Time(Some(ClockTime::ZERO)); assert!(ct_zero.is_some()); let signed = ct_zero.into_positive(); assert_eq!( signed, GenericSignedFormattedValue::Time(Some(Signed::Positive(ClockTime::ZERO))), ); assert_eq!(signed.is_positive(), Some(true)); assert_eq!(signed.is_negative(), Some(false)); assert_eq!(signed.signum(), Some(0)); } #[test] fn signed_roundtrip() { let ct_1 = Some(ClockTime::SECOND); let raw_ct_1 = unsafe { ct_1.into_raw_value() }; let signed = unsafe { Option::::from_raw(Format::Time, raw_ct_1) } .into_signed(1) .unwrap(); assert_eq!(signed, Signed::Positive(ClockTime::SECOND)); assert!(signed.is_positive()); let signed = unsafe { Option::::from_raw(Format::Time, raw_ct_1) } .into_signed(-1) .unwrap(); assert_eq!(signed, Signed::Negative(ClockTime::SECOND)); assert!(signed.is_negative()); let ct_none = ClockTime::NONE; let raw_ct_none = unsafe { ct_none.into_raw_value() }; let signed = unsafe { Option::::from_raw(Format::Time, raw_ct_none) }.into_signed(1); assert!(signed.is_none()); let signed = unsafe { Option::::from_raw(Format::Time, raw_ct_none) }.into_signed(-1); assert!(signed.is_none()); } #[test] fn display_new_types() { let bytes = 42.bytes(); assert_eq!(&format!("{bytes}"), "42 bytes"); assert_eq!(&format!("{}", bytes.display()), "42 bytes"); assert_eq!(&format!("{}", Some(bytes).display()), "42 bytes"); assert_eq!(&format!("{}", Bytes::NONE.display()), "undef. bytes"); let gv_1 = GenericFormattedValue::Percent(Some(42.percent())); assert_eq!(&format!("{gv_1}"), "42 %"); assert_eq!( &format!("{}", GenericFormattedValue::Percent(None)), "undef. %" ); let percent = Percent::try_from(0.1234).unwrap(); assert_eq!(&format!("{percent}"), "12.34 %"); assert_eq!(&format!("{percent:5.1}"), " 12.3 %"); let other: Other = 42.try_into().unwrap(); assert_eq!(&format!("{other}"), "42"); let g_other = GenericFormattedValue::new(Format::__Unknown(128), 42); assert_eq!(&format!("{g_other}"), "42 (format: 128)"); assert_eq!(&format!("{}", g_other.display()), "42 (format: 128)"); let g_other_none = GenericFormattedValue::Other(Format::__Unknown(128), None); assert_eq!(&format!("{g_other_none}"), "undef. (format: 128)"); assert_eq!( &format!("{}", g_other_none.display()), "undef. (format: 128)" ); } #[test] fn display_signed() { let bytes_42 = 42.bytes(); let p_bytes = bytes_42.into_positive(); assert_eq!(&format!("{p_bytes}"), "+42 bytes"); assert_eq!(&format!("{}", p_bytes.display()), "+42 bytes"); let some_p_bytes = Some(p_bytes); assert_eq!(&format!("{}", some_p_bytes.display()), "+42 bytes"); let p_some_bytes = Signed::Positive(Some(bytes_42)); assert_eq!(&format!("{}", p_some_bytes.display()), "+42 bytes"); let n_bytes = bytes_42.into_negative(); assert_eq!(&format!("{n_bytes}"), "-42 bytes"); assert_eq!(&format!("{}", n_bytes.display()), "-42 bytes"); let some_n_bytes = Some(n_bytes); assert_eq!(&format!("{}", some_n_bytes.display()), "-42 bytes"); let n_some_bytes = Signed::Negative(Some(bytes_42)); assert_eq!(&format!("{}", n_some_bytes.display()), "-42 bytes"); let p_none_bytes = Signed::Positive(Bytes::NONE); assert_eq!(&format!("{}", p_none_bytes.display()), "undef. bytes"); let n_none_bytes = Signed::Negative(Bytes::NONE); assert_eq!(&format!("{}", n_none_bytes.display()), "undef. bytes"); let none_s_bytes = Option::>::None; assert_eq!(&format!("{}", none_s_bytes.display()), "undef. bytes"); let ct_1 = 45_834_908_569_837 * ClockTime::NSECOND; assert_eq!(&format!("{ct_1}"), "12:43:54.908569837"); assert_eq!(&format!("{}", ct_1.display()), "12:43:54.908569837"); let g_ct_1 = GenericFormattedValue::Time(Some(ct_1)); assert_eq!(&format!("{g_ct_1}"), "12:43:54.908569837"); assert_eq!(&format!("{}", g_ct_1.display()), "12:43:54.908569837"); let p_g_ct1 = g_ct_1.into_positive(); assert_eq!(&format!("{p_g_ct1}"), "+12:43:54.908569837"); assert_eq!(&format!("{}", p_g_ct1.display()), "+12:43:54.908569837"); let n_g_ct1 = g_ct_1.into_negative(); assert_eq!(&format!("{n_g_ct1}"), "-12:43:54.908569837"); assert_eq!(&format!("{}", n_g_ct1.display()), "-12:43:54.908569837"); } } gstreamer-0.23.5/src/format/signed.rs000064400000000000000000000175051046102023000156120ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::fmt; use super::{Format, FormattedValueNoneBuilder}; use crate::utils::Displayable; // rustdoc-stripper-ignore-next /// A signed wrapper. /// /// This wrapper allows representing a signed value from a type /// which is originally unsigned. In C APIs, this is represented /// by a tuple with a signed integer positive or negative and /// the absolute value. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Signed { Negative(T), Positive(T), } impl Signed { #[inline] pub fn is_positive(self) -> bool { matches!(self, Signed::Positive(_)) } // rustdoc-stripper-ignore-next /// Returns `Some(value)`, where `value` is the inner value, /// if `self` is positive. #[inline] pub fn positive(self) -> Option { match self { Signed::Positive(val) => Some(val), Signed::Negative(_) => None, } } // rustdoc-stripper-ignore-next /// Transforms the `Signed` into a `Result`, /// mapping `Positive(v)` to `Ok(v)` and `Negative(_)` to `Err(err)`. #[inline] pub fn positive_or(self, err: E) -> Result { match self { Signed::Positive(val) => Ok(val), Signed::Negative(_) => Err(err), } } // rustdoc-stripper-ignore-next /// Transforms the `Signed` into a `Result`, /// mapping `Positive(v)` to `Ok(v)` and `Negative(v)` to `Err(err(v))`. #[inline] pub fn positive_or_else E>(self, err: F) -> Result { match self { Signed::Positive(val) => Ok(val), Signed::Negative(val) => Err(err(val)), } } #[inline] pub fn is_negative(self) -> bool { matches!(self, Signed::Negative(_)) } // rustdoc-stripper-ignore-next /// Returns `Some(value)`, where `value` is the inner value, /// if `self` is negative. #[inline] pub fn negative(self) -> Option { match self { Signed::Negative(val) => Some(val), Signed::Positive(_) => None, } } // rustdoc-stripper-ignore-next /// Transforms the `Signed` into a `Result`, /// mapping `Negative(v)` to `Ok(v)` and `Positive(_)` to `Err(err)`. #[inline] pub fn negative_or(self, err: E) -> Result { match self { Signed::Negative(val) => Ok(val), Signed::Positive(_) => Err(err), } } // rustdoc-stripper-ignore-next /// Transforms the `Signed` into a `Result`, /// mapping `Negative(v)` to `Ok(v)` and `Positive(_)` to `Err(err(v))`. #[inline] pub fn negative_or_else E>(self, err: F) -> Result { match self { Signed::Negative(val) => Ok(val), Signed::Positive(val) => Err(err(val)), } } // rustdoc-stripper-ignore-next /// Returns the absolute value of `self`. #[inline] pub fn abs(self) -> T { match self { Signed::Positive(val) | Signed::Negative(val) => val, } } } impl std::ops::Neg for Signed { type Output = Signed; #[inline] fn neg(self) -> Self { match self { Signed::Positive(val) => Signed::Negative(val), Signed::Negative(val) => Signed::Positive(val), } } } pub trait SignedIntrinsic {} impl fmt::Display for Signed where T: fmt::Display + SignedIntrinsic, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use std::fmt::Write; let (sign, val) = match self { Signed::Positive(val) => ('+', val), Signed::Negative(val) => ('-', val), }; f.write_char(sign)?; fmt::Display::fmt(&val, f) } } impl Displayable for Signed where T: fmt::Display + SignedIntrinsic, { type DisplayImpl = Signed; fn display(self) -> Self::DisplayImpl { self } } impl Signed> { // rustdoc-stripper-ignore-next /// Transposes a `Signed` `Option` into an `Option` of a `Signed`. /// /// Note that if the inner value was `None`, the sign is lost. #[inline] pub fn transpose(self) -> Option> { use Signed::*; match self { Positive(Some(val)) => Some(Positive(val)), Negative(Some(val)) => Some(Negative(val)), _ => None, } } } pub struct DisplayableOptionSigned(Option>); impl fmt::Display for DisplayableOptionSigned where T: fmt::Display + SignedIntrinsic, Option: Displayable, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.0 { Some(ref signed) => fmt::Display::fmt(signed, f), None => fmt::Display::fmt(&Option::::None.display(), f), } } } impl Displayable for Option> where T: fmt::Display + SignedIntrinsic, Option: Displayable, { type DisplayImpl = DisplayableOptionSigned; fn display(self) -> Self::DisplayImpl { DisplayableOptionSigned(self) } } impl Displayable for Signed> where T: fmt::Display + SignedIntrinsic, Option: Displayable, { type DisplayImpl = DisplayableOptionSigned; fn display(self) -> Self::DisplayImpl { DisplayableOptionSigned(self.transpose()) } } // rustdoc-stripper-ignore-next /// A trait implemented on unsigned types which can be converted into [`crate::Signed`]s. pub trait UnsignedIntoSigned: Copy + Sized { type Signed; // rustdoc-stripper-ignore-next /// Converts `self` into a `Signed` matching the given `sign`. fn into_signed(self, sign: i32) -> Self::Signed { if sign.is_positive() { self.into_positive() } else { self.into_negative() } } // rustdoc-stripper-ignore-next /// Converts `self` into a `Signed::Positive`. fn into_positive(self) -> Self::Signed; // rustdoc-stripper-ignore-next /// Converts `self` into a `Signed::Negative`. fn into_negative(self) -> Self::Signed; } impl_unsigned_int_into_signed!(u64); impl_signed_ops!(u64); impl_signed_div_mul!(u64); impl_signed_int_into_signed!(u64); impl_unsigned_int_into_signed!(u32); impl_signed_ops!(u32); impl_signed_div_mul!(u32); impl_signed_int_into_signed!(u32); impl_unsigned_int_into_signed!(usize); impl_signed_ops!(usize); impl_signed_div_mul!(usize); impl_signed_int_into_signed!(usize); pub trait NoneSignedBuilder: FormattedValueNoneBuilder { type Signed; // rustdoc-stripper-ignore-next /// Returns the `None` value for `Self` as a `Signed` if such a value can be represented. /// /// See details in [`FormattedValueNoneBuilder::none`]. /// /// # Panics /// /// Panics if `Self` is `GenericFormattedValue` in which case, the `Format` must be known. fn none_signed() -> Self::Signed; // rustdoc-stripper-ignore-next /// Returns the `None` value for `Self` as a `Signed`, if such a value can be represented. /// /// See details in [`FormattedValueNoneBuilder::none_for_format`]. /// /// # Panics /// /// Panics if `None` can't be represented by `Self` for `format` or by the requested /// `GenericFormattedValue` variant. fn none_signed_for_format(format: Format) -> Self::Signed; } impl NoneSignedBuilder for T where T: UnsignedIntoSigned + FormattedValueNoneBuilder, { type Signed = ::Signed; #[inline] fn none_signed() -> Self::Signed { Self::none().into_positive() } #[inline] fn none_signed_for_format(format: Format) -> Self::Signed { skip_assert_initialized!(); Self::none_for_format(format).into_positive() } } gstreamer-0.23.5/src/format/specific.rs000064400000000000000000000414441046102023000161250ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::translate::{FromGlib, GlibNoneError, IntoGlib, OptionIntoGlib, TryFromGlib}; use super::{ Format, FormattedValue, FormattedValueError, FormattedValueFullRange, FormattedValueIntrinsic, FormattedValueNoneBuilder, GenericFormattedValue, }; use crate::ffi; pub trait SpecificFormattedValue: FormattedValue {} pub trait SpecificFormattedValueFullRange: FormattedValueFullRange {} // rustdoc-stripper-ignore-next /// A trait implemented on the intrinsic type of a `SpecificFormattedValue`. /// /// # Examples /// /// - `Undefined` is the intrinsic type for `Undefined`. /// - `Bytes` is the intrinsic type for `Option`. pub trait SpecificFormattedValueIntrinsic: TryFromGlib + FormattedValueIntrinsic {} #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Buffers(u64); impl Buffers { #[doc(alias = "GST_BUFFER_OFFSET_NONE")] pub const OFFSET_NONE: u64 = ffi::GST_BUFFER_OFFSET_NONE; pub const MAX: Self = Self(Self::OFFSET_NONE - 1); } impl Buffers { // rustdoc-stripper-ignore-next /// Builds a new `Buffers` formatted value with the provided buffers count. /// /// # Panics /// /// Panics if the provided count equals `u64::MAX`, /// which is reserved for `None` in C. #[track_caller] #[inline] pub const fn from_u64(buffers: u64) -> Self { if buffers == ffi::GST_BUFFER_OFFSET_NONE { panic!("`Buffers` value out of range"); } Buffers(buffers) } // rustdoc-stripper-ignore-next /// Builds a new `Buffers` formatted value with the provided buffers count. /// /// # Panics /// /// Panics if the provided count equals `u64::MAX`, /// which is reserved for `None` in C. #[track_caller] #[inline] pub fn from_usize(buffers: usize) -> Self { Buffers::from_u64(buffers.try_into().unwrap()) } } impl_common_ops_for_newtype_uint!(Buffers, u64); impl_signed_div_mul!(Buffers, u64); impl_signed_int_into_signed!(Buffers, u64); impl_format_value_traits!(Buffers, Buffers, Buffers, u64); option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE); glib_newtype_display!(Buffers, DisplayableOptionBuffers, Format::Buffers); impl TryFrom for usize { type Error = std::num::TryFromIntError; fn try_from(value: Buffers) -> Result { value.0.try_into() } } // FIXME `functions in traits cannot be const` (rustc 1.64.0) // rustdoc-stripper-ignore-next /// `Buffers` formatted value constructor trait. pub trait BuffersFormatConstructor { // rustdoc-stripper-ignore-next /// Builds a `Buffers` formatted value from `self`. fn buffers(self) -> Buffers; } impl BuffersFormatConstructor for u64 { #[track_caller] #[inline] fn buffers(self) -> Buffers { Buffers::from_u64(self) } } #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Bytes(u64); impl Bytes { #[allow(non_upper_case_globals)] // rustdoc-stripper-ignore-next /// 1 kibibyte (1024). #[allow(non_upper_case_globals)] pub const KiB: Self = Self(1024); // rustdoc-stripper-ignore-next /// 1 mebibyte (1024 * 1024). #[allow(non_upper_case_globals)] pub const MiB: Self = Self(1024 * 1024); // rustdoc-stripper-ignore-next /// 1 gibibyte (1024 * 1024 * 1024). #[allow(non_upper_case_globals)] pub const GiB: Self = Self(1024 * 1024 * 1024); pub const MAX: Self = Self(u64::MAX - 1); } impl Bytes { // rustdoc-stripper-ignore-next /// Builds a new `Bytes` formatted value with the provided bytes count. /// /// # Panics /// /// Panics if the provided count equals `u64::MAX`, /// which is reserved for `None` in C. #[track_caller] #[inline] pub const fn from_u64(bytes: u64) -> Self { if bytes == u64::MAX { panic!("`Bytes` value out of range"); } Bytes(bytes) } // rustdoc-stripper-ignore-next /// Builds a new `Bytes` formatted value with the provided bytes count. /// /// # Panics /// /// Panics if the provided count equals `u64::MAX`, /// which is reserved for `None` in C. #[track_caller] #[inline] pub fn from_usize(bytes: usize) -> Self { // FIXME can't use `try_into` in `const` (rustc 1.64.0) Bytes::from_u64(bytes.try_into().unwrap()) } } impl_common_ops_for_newtype_uint!(Bytes, u64); impl_signed_div_mul!(Bytes, u64); impl_signed_int_into_signed!(Bytes, u64); impl_format_value_traits!(Bytes, Bytes, Bytes, u64); option_glib_newtype_from_to!(Bytes, u64::MAX); glib_newtype_display!(Bytes, DisplayableOptionBytes, Format::Bytes); impl TryFrom for usize { type Error = std::num::TryFromIntError; fn try_from(value: Bytes) -> Result { value.0.try_into() } } // FIXME `functions in traits cannot be const` (rustc 1.64.0) // rustdoc-stripper-ignore-next /// `Bytes` formatted value constructor trait. /// /// These constructors use the [unambiguous conventions] for byte units. /// /// [unambiguous conventions]: https://en.wikipedia.org/wiki/Byte#Multiple-byte_units pub trait BytesFormatConstructor { // rustdoc-stripper-ignore-next /// Builds a `Bytes` formatted value from `self`. fn bytes(self) -> Bytes; // rustdoc-stripper-ignore-next /// Builds a `Bytes` formatted value from `self` interpreted as kibibytes (1024). fn kibibytes(self) -> Bytes; // rustdoc-stripper-ignore-next /// Builds a `Bytes` formatted value from `self` interpreted as mebibytes (1024²). fn mebibytes(self) -> Bytes; // rustdoc-stripper-ignore-next /// Builds a `Bytes` formatted value from `self` interpreted as gibibytes (1024³). fn gibibytes(self) -> Bytes; } impl BytesFormatConstructor for u64 { #[track_caller] #[inline] fn bytes(self) -> Bytes { Bytes::from_u64(self) } #[track_caller] #[inline] fn kibibytes(self) -> Bytes { Bytes::from_u64(self * 1024) } #[track_caller] #[inline] fn mebibytes(self) -> Bytes { Bytes::from_u64(self * 1024 * 1024) } #[track_caller] #[inline] fn gibibytes(self) -> Bytes { Bytes::from_u64(self * 1024 * 1024 * 1024) } } #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Default(u64); impl Default { pub const MAX: Self = Self(u64::MAX - 1); } impl Default { // rustdoc-stripper-ignore-next /// Builds a new `Default` formatted value with the provided quantity. /// /// # Panics /// /// Panics if the provided quantity equals `u64::MAX`, /// which is reserved for `None` in C. #[track_caller] #[inline] pub const fn from_u64(quantity: u64) -> Self { if quantity == u64::MAX { panic!("`Default` value out of range"); } Default(quantity) } // rustdoc-stripper-ignore-next /// Builds a new `Default` formatted value with the provided quantity. /// /// # Panics /// /// Panics if the provided quantity equals `u64::MAX`, /// which is reserved for `None` in C. #[track_caller] #[inline] pub fn from_usize(quantity: usize) -> Self { // FIXME can't use `try_into` in `const` (rustc 1.64.0) Default::from_u64(quantity.try_into().unwrap()) } } impl_common_ops_for_newtype_uint!(Default, u64); impl_signed_div_mul!(Default, u64); impl_signed_int_into_signed!(Default, u64); impl_format_value_traits!(Default, Default, Default, u64); option_glib_newtype_from_to!(Default, u64::MAX); glib_newtype_display!(Default, DisplayableOptionDefault, Format::Default); impl TryFrom for usize { type Error = std::num::TryFromIntError; fn try_from(value: Default) -> Result { value.0.try_into() } } // FIXME `functions in traits cannot be const` (rustc 1.64.0) // rustdoc-stripper-ignore-next /// `Default` formatted value constructor trait. pub trait DefaultFormatConstructor { // rustdoc-stripper-ignore-next /// Builds a `Default` formatted value from `self`. fn default_format(self) -> Default; } impl DefaultFormatConstructor for u64 { #[track_caller] #[inline] fn default_format(self) -> Default { Default::from_u64(self) } } pub type Time = super::ClockTime; #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Percent(u32); impl Percent { #[doc(alias = "GST_FORMAT_PERCENT_MAX")] pub const MAX: Self = Self(ffi::GST_FORMAT_PERCENT_MAX as u32); #[doc(alias = "GST_FORMAT_PERCENT_SCALE")] pub const SCALE: Self = Self(ffi::GST_FORMAT_PERCENT_SCALE as u32); // rustdoc-stripper-ignore-next /// Builds a new `Percent` with the provided percent value. /// /// # Panics /// /// Panics if the provided value is larger than 100. #[track_caller] #[inline] pub const fn from_percent(percent: u32) -> Self { if percent > 100 { panic!("`Percent` value out of range"); } Percent(ffi::GST_FORMAT_PERCENT_SCALE as u32 * percent) } // rustdoc-stripper-ignore-next /// Builds a new `Percent` with the provided parts per million value. /// /// # Panics /// /// Panics if the provided value is larger than [`Self::MAX`]. #[track_caller] #[inline] pub const fn from_ppm(ppm: u32) -> Self { if ppm > ffi::GST_FORMAT_PERCENT_MAX as u32 { panic!("`Percent` ppm value out of range"); } Percent(ppm) } // rustdoc-stripper-ignore-next /// Builds a new `Percent` with the provided ratio. /// /// # Panics /// /// Panics if the provided radio is out of the range [0.0, 1.0]. #[track_caller] #[inline] pub fn from_ratio(ratio: f32) -> Self { // FIXME floating point arithmetic is not allowed in constant functions (rustc 1.64.0) Percent::try_from(ratio).expect("`Percent` ratio out of range") } // rustdoc-stripper-ignore-next /// The percent value in the range [0, 100]. #[track_caller] #[inline] pub fn percent(&self) -> u32 { self.0 / ffi::GST_FORMAT_PERCENT_SCALE as u32 } // rustdoc-stripper-ignore-next /// The per million value in the range [0, 1_000_000]. #[track_caller] #[inline] pub fn ppm(&self) -> u32 { self.0 } // rustdoc-stripper-ignore-next /// The ratio value in the range [0.0, 1.0]. #[track_caller] #[inline] pub fn ratio(&self) -> f32 { self.0 as f32 / ffi::GST_FORMAT_PERCENT_MAX as f32 } } impl_common_ops_for_newtype_uint!(Percent, u32, one: ffi::GST_FORMAT_PERCENT_SCALE as u32); impl_signed_div_mul!(Percent, u32); impl_signed_int_into_signed!(Percent, u32); impl FormattedValue for Option { type FullRange = Option; #[inline] fn default_format() -> Format { Format::Percent } #[inline] fn format(&self) -> Format { Format::Percent } #[inline] fn is_some(&self) -> bool { Option::is_some(self) } #[inline] unsafe fn into_raw_value(self) -> i64 { self.map_or(-1, |v| v.0 as i64) } } impl FormattedValueFullRange for Option { #[inline] unsafe fn from_raw(format: Format, value: i64) -> Self { debug_assert_eq!(format, Format::Percent); Percent::try_from_glib(value).ok() } } impl From> for GenericFormattedValue { #[inline] fn from(v: Option) -> Self { skip_assert_initialized!(); GenericFormattedValue::Percent(v) } } impl From for GenericFormattedValue { #[inline] fn from(v: Percent) -> Self { skip_assert_initialized!(); GenericFormattedValue::Percent(Some(v)) } } impl FormattedValue for Percent { type FullRange = Option; #[inline] fn default_format() -> Format { Format::Percent } #[inline] fn format(&self) -> Format { Format::Percent } #[inline] fn is_some(&self) -> bool { true } #[inline] unsafe fn into_raw_value(self) -> i64 { self.0 as i64 } } impl TryFrom for Percent { type Error = GlibNoneError; #[inline] fn try_from(v: u64) -> Result { skip_assert_initialized!(); unsafe { Self::try_from_glib(v as i64) } } } impl TryFromGlib for Percent { type Error = GlibNoneError; #[inline] unsafe fn try_from_glib(value: i64) -> Result { skip_assert_initialized!(); if value < 0 || value > ffi::GST_FORMAT_PERCENT_MAX { Err(GlibNoneError) } else { Ok(Percent(value as u32)) } } } impl TryFrom for Percent { type Error = FormattedValueError; #[inline] fn try_from(value: u32) -> Result { skip_assert_initialized!(); if value > ffi::GST_FORMAT_PERCENT_MAX as u32 { Err(FormattedValueError(Format::Percent)) } else { Ok(Percent(value)) } } } impl TryFrom for Option { type Error = FormattedValueError; #[inline] fn try_from(v: GenericFormattedValue) -> Result, Self::Error> { skip_assert_initialized!(); if let GenericFormattedValue::Percent(v) = v { Ok(v) } else { Err(FormattedValueError(v.format())) } } } impl FormattedValueIntrinsic for Percent {} impl SpecificFormattedValue for Option {} impl SpecificFormattedValueFullRange for Option {} impl SpecificFormattedValueIntrinsic for Percent {} impl FormattedValueNoneBuilder for Option { #[inline] fn none() -> Option { None } } #[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)] #[error("value out of range")] pub struct TryPercentFromFloatError(()); impl TryFrom for Percent { type Error = TryPercentFromFloatError; #[inline] fn try_from(v: f64) -> Result { skip_assert_initialized!(); if v < 0.0 || v > 1.0 { Err(TryPercentFromFloatError(())) } else { Ok(Percent( (v * ffi::GST_FORMAT_PERCENT_MAX as f64).round() as u32 )) } } } impl TryFrom for Percent { type Error = TryPercentFromFloatError; #[inline] fn try_from(v: f32) -> Result { skip_assert_initialized!(); if v < 0.0 || v > 1.0 { Err(TryPercentFromFloatError(())) } else { Ok(Percent( (v * ffi::GST_FORMAT_PERCENT_MAX as f32).round() as u32 )) } } } // FIXME `functions in traits cannot be const` (rustc 1.64.0) // rustdoc-stripper-ignore-next /// `Percent` formatted value from integer constructor trait. pub trait PercentFormatIntegerConstructor { // rustdoc-stripper-ignore-next /// Builds a `Percent` formatted value from `self` interpreted as a percent. fn percent(self) -> Percent; // rustdoc-stripper-ignore-next /// Builds a `Percent` formatted value from `self` interpreted as parts per million. fn ppm(self) -> Percent; } impl PercentFormatIntegerConstructor for u32 { #[track_caller] #[inline] fn percent(self) -> Percent { Percent::from_percent(self) } #[track_caller] #[inline] fn ppm(self) -> Percent { Percent::from_ppm(self) } } // FIXME `functions in traits cannot be const` (rustc 1.64.0) // rustdoc-stripper-ignore-next /// `Percent` formatted value from float constructor trait. pub trait PercentFormatFloatConstructor { // rustdoc-stripper-ignore-next /// Builds a `Percent` formatted value from `self` interpreted as a ratio. fn percent_ratio(self) -> Percent; } impl PercentFormatFloatConstructor for f32 { #[track_caller] #[inline] fn percent_ratio(self) -> Percent { Percent::try_from(self).unwrap() } } impl std::fmt::Display for Percent { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { std::fmt::Display::fmt(&(self.0 as f32 / (*Percent::SCALE) as f32), f)?; f.write_str(" %") } } impl crate::utils::Displayable for Percent { type DisplayImpl = Self; fn display(self) -> Self { self } } pub struct DisplayableOptionPercent(Option); impl std::fmt::Display for DisplayableOptionPercent { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { if let Some(val) = self.0.as_ref() { std::fmt::Display::fmt(val, f) } else { f.write_str("undef. %") } } } impl crate::utils::Displayable for Option { type DisplayImpl = DisplayableOptionPercent; fn display(self) -> Self::DisplayImpl { DisplayableOptionPercent(self) } } gstreamer-0.23.5/src/format/undefined.rs000064400000000000000000000062041046102023000162740ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ops::{Deref, DerefMut}; use glib::translate::TryFromGlib; use super::{ FormattedValue, FormattedValueError, FormattedValueFullRange, FormattedValueIntrinsic, GenericFormattedValue, Signed, }; use crate::Format; #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] pub struct Undefined(i64); impl Undefined { pub const ONE: Undefined = Undefined(1); } // FIXME `functions in traits cannot be const` (rustc 1.64.0) // rustdoc-stripper-ignore-next /// `Undefined` formatted value constructor trait. pub trait UndefinedFormatConstructor { // rustdoc-stripper-ignore-next /// Builds an `Undefined` formatted value from `self`. fn undefined_format(self) -> Undefined; } impl UndefinedFormatConstructor for i64 { #[track_caller] #[inline] fn undefined_format(self) -> Undefined { Undefined(self) } } impl FormattedValue for Undefined { type FullRange = Undefined; #[inline] fn default_format() -> Format { Format::Undefined } #[inline] fn format(&self) -> Format { Format::Undefined } #[inline] fn is_some(&self) -> bool { true } #[inline] unsafe fn into_raw_value(self) -> i64 { self.0 } } impl FormattedValueFullRange for Undefined { #[inline] unsafe fn from_raw(format: Format, value: i64) -> Self { debug_assert_eq!(format, Format::Undefined); Undefined(value) } } impl From for GenericFormattedValue { #[inline] fn from(v: Undefined) -> Self { skip_assert_initialized!(); GenericFormattedValue::Undefined(v) } } impl TryFrom for Undefined { type Error = FormattedValueError; #[inline] fn try_from(v: GenericFormattedValue) -> Result { skip_assert_initialized!(); if let GenericFormattedValue::Undefined(v) = v { Ok(v) } else { Err(FormattedValueError(v.format())) } } } impl FormattedValueIntrinsic for Undefined {} impl TryFromGlib for Undefined { type Error = std::convert::Infallible; #[inline] unsafe fn try_from_glib(v: i64) -> Result { skip_assert_initialized!(); Ok(Undefined(v)) } } impl From for Undefined { #[inline] fn from(v: i64) -> Self { skip_assert_initialized!(); Undefined(v) } } impl Deref for Undefined { type Target = i64; #[inline] fn deref(&self) -> &i64 { &self.0 } } impl DerefMut for Undefined { #[inline] fn deref_mut(&mut self) -> &mut i64 { &mut self.0 } } impl AsRef for Undefined { #[inline] fn as_ref(&self) -> &i64 { &self.0 } } impl AsMut for Undefined { #[inline] fn as_mut(&mut self) -> &mut i64 { &mut self.0 } } impl From for Signed { #[inline] fn from(val: Undefined) -> Signed { skip_assert_initialized!(); val.0.into() } } glib_newtype_display!(Undefined, Format::Undefined); gstreamer-0.23.5/src/functions.rs000064400000000000000000000062501046102023000150540ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ptr; use glib::translate::*; #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] use crate::Tracer; // import only functions which do not have their own module as namespace pub use crate::auto::functions::{ main_executable_path, util_get_timestamp as get_timestamp, version, version_string, }; use crate::ffi; #[doc(alias = "gst_calculate_linear_regression")] pub fn calculate_linear_regression( xy: &[(u64, u64)], temp: Option<&mut [(u64, u64)]>, ) -> Option<(u64, u64, u64, u64, f64)> { skip_assert_initialized!(); use std::mem; unsafe { assert_eq!(mem::size_of::() * 2, mem::size_of::<(u64, u64)>()); assert_eq!(mem::align_of::(), mem::align_of::<(u64, u64)>()); assert!( temp.as_ref() .map(|temp| temp.len()) .unwrap_or_else(|| xy.len()) >= xy.len() ); let mut m_num = mem::MaybeUninit::uninit(); let mut m_denom = mem::MaybeUninit::uninit(); let mut b = mem::MaybeUninit::uninit(); let mut xbase = mem::MaybeUninit::uninit(); let mut r_squared = mem::MaybeUninit::uninit(); let res = from_glib(ffi::gst_calculate_linear_regression( xy.as_ptr() as *const u64, temp.map(|temp| temp.as_mut_ptr() as *mut u64) .unwrap_or(ptr::null_mut()), xy.len() as u32, m_num.as_mut_ptr(), m_denom.as_mut_ptr(), b.as_mut_ptr(), xbase.as_mut_ptr(), r_squared.as_mut_ptr(), )); if res { Some(( m_num.assume_init(), m_denom.assume_init(), b.assume_init(), xbase.assume_init(), r_squared.assume_init(), )) } else { None } } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "gst_tracing_get_active_tracers")] pub fn active_tracers() -> glib::List { assert_initialized_main_thread!(); unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_tracing_get_active_tracers()) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_util_filename_compare")] pub fn filename_compare(a: &std::path::Path, b: &std::path::Path) -> std::cmp::Ordering { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_util_filename_compare( a.to_glib_none().0, b.to_glib_none().0, )) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_calculate_linear_regression() { crate::init().unwrap(); let values = [(0, 0), (1, 1), (2, 2), (3, 3)]; let (m_num, m_denom, b, xbase, _) = calculate_linear_regression(&values, None).unwrap(); assert_eq!((m_num, m_denom, b, xbase), (10, 10, 3, 3)); let mut temp = [(0, 0); 4]; let (m_num, m_denom, b, xbase, _) = calculate_linear_regression(&values, Some(&mut temp)).unwrap(); assert_eq!((m_num, m_denom, b, xbase), (10, 10, 3, 3)); } } gstreamer-0.23.5/src/ghost_pad.rs000064400000000000000000001124461046102023000150210ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::translate::*; use crate::{ ffi, prelude::*, FlowError, FlowSuccess, GhostPad, LoggableError, Pad, PadBuilder, PadFlags, PadGetRangeSuccess, PadMode, StaticPadTemplate, }; impl GhostPad { #[doc(alias = "gst_ghost_pad_activate_mode_default")] pub fn activate_mode_default>( pad: &P, parent: Option<&impl IsA>, mode: PadMode, active: bool, ) -> Result<(), glib::BoolError> { skip_assert_initialized!(); unsafe { glib::result_from_gboolean!( ffi::gst_ghost_pad_activate_mode_default( pad.to_glib_none().0 as *mut ffi::GstPad, parent.map(|p| p.as_ref()).to_glib_none().0, mode.into_glib(), active.into_glib(), ), "Failed to invoke the default activate mode function of the ghost pad" ) } } #[doc(alias = "gst_ghost_pad_internal_activate_mode_default")] pub fn internal_activate_mode_default>( pad: &P, parent: Option<&impl IsA>, mode: PadMode, active: bool, ) -> Result<(), glib::BoolError> { skip_assert_initialized!(); unsafe { glib::result_from_gboolean!( ffi::gst_ghost_pad_internal_activate_mode_default( pad.to_glib_none().0 as *mut ffi::GstPad, parent.map(|p| p.as_ref()).to_glib_none().0, mode.into_glib(), active.into_glib(), ), concat!( "Failed to invoke the default activate mode function of a proxy pad ", "that is owned by the ghost pad" ) ) } } // rustdoc-stripper-ignore-next /// Creates a new [`GhostPad`] with an automatically generated name. /// /// The [`Pad`] will be assigned the usual `gst::Object` generated unique name. /// /// Use [`GhostPad::builder_from_template()`] to get a [`PadBuilder`](crate::PadBuilder) /// and define options. #[doc(alias = "gst_ghost_pad_new_no_target")] pub fn new(direction: crate::PadDirection) -> Self { skip_assert_initialized!(); Self::builder(direction).build() } // rustdoc-stripper-ignore-next /// Creates a [`PadBuilder`](crate::PadBuilder) with the specified [`PadDirection`](crate::PadDirection). #[doc(alias = "gst_ghost_pad_new_no_target")] pub fn builder(direction: crate::PadDirection) -> PadBuilder { skip_assert_initialized!(); PadBuilder::new(direction) } // rustdoc-stripper-ignore-next /// Creates a new [`GhostPad`] from the [`StaticPadTemplate`](crate::StaticPadTemplate). /// /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `GhostPad` will automatically be named after the `name_template`. /// /// Use [`GhostPad::builder_from_template()`] to get a [`PadBuilder`](crate::PadBuilder) /// and define options. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. /// /// # Panics /// /// Panics if the `name_template` is a wildcard-name. #[doc(alias = "gst_ghost_pad_new_no_target_from_static_template")] pub fn from_static_template(templ: &StaticPadTemplate) -> Self { skip_assert_initialized!(); Self::builder_from_static_template(templ).build() } // rustdoc-stripper-ignore-next /// Creates a new [`PadBuilder`](crate::PadBuilder) for a [`GhostPad`] from the [`StaticPadTemplate`](crate::StaticPadTemplate). /// /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `GhostPad` will automatically be named after the `name_template`. /// /// Use [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::name_if_some`](crate::PadBuilder::name_if_some) /// to specify a different name. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. #[doc(alias = "gst_ghost_pad_new_no_target_from_static_template")] pub fn builder_from_static_template(templ: &StaticPadTemplate) -> PadBuilder { skip_assert_initialized!(); PadBuilder::from_static_template(templ) } // rustdoc-stripper-ignore-next /// Creates a new [`GhostPad`] from the [`PadTemplate`](crate::PadTemplate). /// /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `GhostPad` will automatically be named after the `name_template`. /// /// Use [`GhostPad::builder_from_template()`] to get a [`PadBuilder`](crate::PadBuilder) /// and define options. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. /// /// # Panics /// /// Panics if the `name_template` is a wildcard-name. #[doc(alias = "gst_ghost_pad_new_no_target_from_template")] pub fn from_template(templ: &crate::PadTemplate) -> Self { skip_assert_initialized!(); Self::builder_from_template(templ).build() } // rustdoc-stripper-ignore-next /// Creates a new [`PadBuilder`](crate::PadBuilder) for a [`GhostPad`] from the [`PadTemplate`](crate::PadTemplate). /// /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `GhostPad` will automatically be named after the `name_template`. /// /// Use [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::name_if_some`](crate::PadBuilder::name_if_some) /// to specify a different name. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. #[doc(alias = "gst_ghost_pad_new_no_target_from_template")] pub fn builder_from_template(templ: &crate::PadTemplate) -> PadBuilder { skip_assert_initialized!(); PadBuilder::from_template(templ) } // rustdoc-stripper-ignore-next /// Creates a new [`GhostPad`] from the specified `target` `Pad`. /// /// The `GhostPad` will automatically be named after the `target` `name`. /// /// Use [`GhostPad::builder_with_target()`] to get a [`PadBuilder`](crate::PadBuilder) /// and define options. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. #[doc(alias = "gst_ghost_pad_new")] pub fn with_target + IsA>( target: &P, ) -> Result { skip_assert_initialized!(); Ok(Self::builder_with_target(target)?.build()) } // rustdoc-stripper-ignore-next /// Creates a new [`PadBuilder`](crate::PadBuilder) for a [`GhostPad`] from the specified `target` `Pad`. /// /// The `GhostPad` will automatically be named after the `target` `name`. /// /// Use [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::name_if_some`](crate::PadBuilder::name_if_some) /// to specify a different name. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. #[doc(alias = "gst_ghost_pad_new_no_target_from_template")] pub fn builder_with_target + IsA>( target: &P, ) -> Result, glib::BoolError> { skip_assert_initialized!(); let builder = Self::builder(target.direction()); builder.with_target(target) } // rustdoc-stripper-ignore-next /// Creates a new [`GhostPad`] from the [`PadTemplate`](crate::PadTemplate) /// with the specified `target` `Pad`. /// /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `GhostPad` will automatically be named after the `name_template`. /// /// If the `name_template` is a wildcard-name, then the `target` `name` is used, /// if it is compatible. Otherwise, a specific name must be provided using /// [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::name_if_some`](crate::PadBuilder::name_if_some). /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. #[doc(alias = "gst_ghost_pad_new_from_template")] pub fn from_template_with_target + IsA>( templ: &crate::PadTemplate, target: &P, ) -> Result { skip_assert_initialized!(); Ok(Self::builder_from_template_with_target(templ, target)?.build()) } // rustdoc-stripper-ignore-next /// Creates a new [`PadBuilder`](crate::PadBuilder) for a [`GhostPad`] from the [`PadTemplate`](crate::PadTemplate) /// with the specified `target` `Pad`. /// /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `GhostPad` will automatically be named after the `name_template`. /// /// If the `name_template` is a wildcard-name, then the `target` `name` is used, /// if it is compatible. Otherwise, a specific name must be provided using /// [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::name_if_some`](crate::PadBuilder::name_if_some). /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. #[doc(alias = "gst_ghost_pad_new_from_template")] pub fn builder_from_template_with_target + IsA>( templ: &crate::PadTemplate, target: &P, ) -> Result, glib::BoolError> { skip_assert_initialized!(); if target.direction() != templ.direction() { return Err(glib::bool_error!( "Template and target have different directions" )); } Self::builder_from_template(templ).with_target(target) } } impl + IsA> PadBuilder { #[doc(alias = "gst_pad_set_activate_function")] pub fn proxy_pad_activate_function(self, func: F) -> Self where F: Fn(&crate::ProxyPad, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static, { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_activate_function(func); } self } #[doc(alias = "gst_pad_set_activate_function")] pub fn proxy_pad_activate_function_if_some(self, func: Option) -> Self where F: Fn(&crate::ProxyPad, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static, { if let Some(func) = func { self.proxy_pad_activate_function(func) } else { self } } #[doc(alias = "gst_pad_set_activatemode_function")] pub fn proxy_pad_activatemode_function(self, func: F) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, crate::PadMode, bool, ) -> Result<(), LoggableError> + Send + Sync + 'static, { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_activatemode_function(func); } self } #[doc(alias = "gst_pad_set_activatemode_function")] pub fn proxy_pad_activatemode_function_if_some(self, func: Option) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, crate::PadMode, bool, ) -> Result<(), LoggableError> + Send + Sync + 'static, { if let Some(func) = func { self.proxy_pad_activatemode_function(func) } else { self } } #[doc(alias = "gst_pad_set_chain_function")] pub fn proxy_pad_chain_function(self, func: F) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, crate::Buffer, ) -> Result + Send + Sync + 'static, { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_chain_function(func); } self } #[doc(alias = "gst_pad_set_chain_function")] pub fn proxy_pad_chain_function_if_some(self, func: Option) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, crate::Buffer, ) -> Result + Send + Sync + 'static, { if let Some(func) = func { self.proxy_pad_chain_function(func) } else { self } } #[doc(alias = "gst_pad_set_chain_list_function")] pub fn proxy_pad_chain_list_function(self, func: F) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, crate::BufferList, ) -> Result + Send + Sync + 'static, { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_chain_list_function(func); } self } #[doc(alias = "gst_pad_set_chain_list_function")] pub fn proxy_pad_chain_list_function_if_some(self, func: Option) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, crate::BufferList, ) -> Result + Send + Sync + 'static, { if let Some(func) = func { self.proxy_pad_chain_list_function(func) } else { self } } #[doc(alias = "gst_pad_set_event_function")] pub fn proxy_pad_event_function(self, func: F) -> Self where F: Fn(&crate::ProxyPad, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static, { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_event_function(func); } self } #[doc(alias = "gst_pad_set_event_function")] pub fn proxy_pad_event_function_if_some(self, func: Option) -> Self where F: Fn(&crate::ProxyPad, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static, { if let Some(func) = func { self.proxy_pad_event_function(func) } else { self } } #[doc(alias = "gst_pad_set_event_full_function")] pub fn proxy_pad_event_full_function(self, func: F) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, crate::Event, ) -> Result + Send + Sync + 'static, { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_event_full_function(func); } self } #[doc(alias = "gst_pad_set_event_full_function")] pub fn proxy_pad_event_full_function_if_some(self, func: Option) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, crate::Event, ) -> Result + Send + Sync + 'static, { if let Some(func) = func { self.proxy_pad_event_full_function(func) } else { self } } #[doc(alias = "gst_pad_set_getrange_function")] pub fn proxy_pad_getrange_function(self, func: F) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, u64, Option<&mut crate::BufferRef>, u32, ) -> Result + Send + Sync + 'static, { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_getrange_function(func); } self } #[doc(alias = "gst_pad_set_getrange_function")] pub fn proxy_pad_getrange_function_if_some(self, func: Option) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, u64, Option<&mut crate::BufferRef>, u32, ) -> Result + Send + Sync + 'static, { if let Some(func) = func { self.proxy_pad_getrange_function(func) } else { self } } #[doc(alias = "gst_pad_set_iterate_internal_links_function")] pub fn proxy_pad_iterate_internal_links_function(self, func: F) -> Self where F: Fn(&crate::ProxyPad, Option<&crate::Object>) -> crate::Iterator + Send + Sync + 'static, { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_iterate_internal_links_function(func); } self } #[doc(alias = "gst_pad_set_iterate_internal_links_function")] pub fn proxy_pad_iterate_internal_links_function_if_some(self, func: Option) -> Self where F: Fn(&crate::ProxyPad, Option<&crate::Object>) -> crate::Iterator + Send + Sync + 'static, { if let Some(func) = func { self.proxy_pad_iterate_internal_links_function(func) } else { self } } #[doc(alias = "gst_pad_set_link_function")] pub fn proxy_pad_link_function(self, func: F) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, &Pad, ) -> Result + Send + Sync + 'static, { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_link_function(func); } self } #[doc(alias = "gst_pad_set_link_function")] pub fn proxy_pad_link_function_if_some(self, func: Option) -> Self where F: Fn( &crate::ProxyPad, Option<&crate::Object>, &Pad, ) -> Result + Send + Sync + 'static, { if let Some(func) = func { self.proxy_pad_link_function(func) } else { self } } #[doc(alias = "gst_pad_set_query_function")] pub fn proxy_pad_query_function(self, func: F) -> Self where F: Fn(&crate::ProxyPad, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static, { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_query_function(func); } self } #[doc(alias = "gst_pad_set_query_function")] pub fn proxy_pad_query_function_if_some(self, func: Option) -> Self where F: Fn(&crate::ProxyPad, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static, { if let Some(func) = func { self.proxy_pad_query_function(func) } else { self } } #[doc(alias = "gst_pad_set_unlink_function")] pub fn proxy_pad_unlink_function(self, func: F) -> Self where F: Fn(&crate::ProxyPad, Option<&crate::Object>) + Send + Sync + 'static, { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_unlink_function(func); } self } #[doc(alias = "gst_pad_set_unlink_function")] pub fn proxy_pad_unlink_function_if_some(self, func: Option) -> Self where F: Fn(&crate::ProxyPad, Option<&crate::Object>) + Send + Sync + 'static, { if let Some(func) = func { self.proxy_pad_unlink_function(func) } else { self } } pub fn proxy_pad_flags(self, flags: PadFlags) -> Self { unsafe { let proxy = self .pad .unsafe_cast_ref::() .internal() .unwrap(); proxy.set_pad_flags(flags); } self } pub fn proxy_pad_flags_if_some(self, flags: Option) -> Self { if let Some(flags) = flags { self.proxy_pad_flags(flags) } else { self } } // rustdoc-stripper-ignore-next /// Specifies a `target` [`Pad`](crate::Pad) for the [`GhostPad`]. /// /// If the [`PadBuilder`](crate::PadBuilder) was created from /// a [`PadTemplate`](crate::PadTemplate) and the `PadTemplate` has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `GhostPad` will automatically be named after the `name_template`. /// /// If the `name_template` is a wildcard-name, then the `target` `name` is used, /// if it is compatible. Otherwise, a specific name must be provided using /// [`PadBuilder::name`](crate::PadBuilder::name) or [`PadBuilder::name_if_some`](crate::PadBuilder::name_if_some). /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. pub fn with_target + IsA>( mut self, target: &P, ) -> Result { assert_eq!(self.pad.direction(), target.direction()); self.pad.set_target(Some(target))?; self.name = crate::pad::PadBuilderName::CandidateForWildcardTemplate(target.name().to_string()); Ok(self) } } #[cfg(test)] mod tests { use super::*; #[test] fn no_template_no_target() { crate::init().unwrap(); let ghost_pad = GhostPad::new(crate::PadDirection::Sink); assert!(ghost_pad.name().starts_with("ghostpad")); let ghost_pad = GhostPad::builder(crate::PadDirection::Sink).build(); assert!(ghost_pad.name().starts_with("ghostpad")); let ghost_pad = GhostPad::builder(crate::PadDirection::Sink) .name("sink") .build(); assert_eq!(ghost_pad.name(), "sink"); } #[test] fn from_template() { crate::init().unwrap(); let caps = crate::Caps::new_any(); let wildcard_templ = crate::PadTemplate::new( "sink_%u", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); let ghost_pad = GhostPad::builder_from_template(&wildcard_templ) .name("my-ghostpad") .build(); assert_eq!(ghost_pad.name(), "my-ghostpad"); let caps = crate::Caps::new_any(); let templ = crate::PadTemplate::new( "sink", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let ghost_pad = GhostPad::from_template(&templ); assert_eq!(ghost_pad.name(), "sink"); let ghost_pad = GhostPad::builder_from_template(&templ).build(); assert!(ghost_pad.name().starts_with("sink")); let ghost_pad = GhostPad::builder_from_template(&templ) .name("my-sink") .build(); assert_eq!(ghost_pad.name(), "my-sink"); } #[test] #[should_panic] fn from_template_missing_name() { crate::init().unwrap(); let caps = crate::Caps::new_any(); let templ = crate::PadTemplate::new( "audio_%u", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); // Panic: attempt to build from a wildcard-named template // without providing a name. let _ghost_pad = GhostPad::from_template(&templ); } #[test] #[should_panic] fn from_template_builder_missing_name() { crate::init().unwrap(); let caps = crate::Caps::new_any(); let templ = crate::PadTemplate::new( "audio_%u", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); // Panic: attempt to build from a wildcard-named template // without providing a name. let _ghost_pad = GhostPad::builder_from_template(&templ).build(); } #[test] fn with_target() { crate::init().unwrap(); let caps = crate::Caps::new_any(); let templ = crate::PadTemplate::new( "test", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let target = crate::Pad::builder_from_template(&templ).build(); let ghost_pad = GhostPad::with_target(&target).unwrap(); assert_eq!(ghost_pad.name(), "test"); let target = crate::Pad::from_template(&templ); let ghost_pad = GhostPad::builder_with_target(&target).unwrap().build(); assert_eq!(ghost_pad.name(), "test"); let target = crate::Pad::from_template(&templ); let ghost_pad = GhostPad::builder_with_target(&target) .unwrap() .name("ghost_test") .build(); assert_eq!(ghost_pad.name(), "ghost_test"); let target = crate::Pad::from_template(&templ); let ghost_pad = GhostPad::builder_with_target(&target) .unwrap() .generated_name() .build(); assert!(ghost_pad.name().starts_with("ghostpad")); } #[test] fn from_template_with_target() { crate::init().unwrap(); let caps = crate::Caps::new_any(); let sink_templ = crate::PadTemplate::new( "sink", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); // # No conversion specifier, Always template let ghost_templ = crate::PadTemplate::new( "ghost_sink", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let target = crate::Pad::from_template(&sink_templ); let ghost_pad = GhostPad::from_template_with_target(&ghost_templ, &target).unwrap(); assert_eq!(ghost_pad.name(), "ghost_sink"); let target = crate::Pad::from_template(&sink_templ); let ghost_pad = GhostPad::builder_from_template_with_target(&ghost_templ, &target) .unwrap() .build(); assert_eq!(ghost_pad.name(), "ghost_sink"); let target = crate::Pad::from_template(&sink_templ); let ghost_pad = GhostPad::builder_from_template_with_target(&ghost_templ, &target) .unwrap() .name("my-sink") .build(); assert_eq!(ghost_pad.name(), "my-sink"); let target = crate::Pad::from_template(&sink_templ); let ghost_pad = GhostPad::builder_from_template_with_target(&ghost_templ, &target) .unwrap() .generated_name() .build(); assert!(ghost_pad.name().starts_with("ghostpad")); // # Request template %u let wildcard_u_templ = crate::PadTemplate::new( "sink_%u", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); // ## Incompatible target but specific name let target = crate::Pad::from_template(&sink_templ); let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_u_templ, &target) .unwrap() .name("sink_0") .build(); assert_eq!(ghost_pad.name(), "sink_0"); // ## Compatible target let sink_0_templ = crate::PadTemplate::new( "sink_0", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let target = crate::Pad::from_template(&sink_0_templ); let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_u_templ, &target) .unwrap() .build(); assert_eq!(ghost_pad.name(), "sink_0"); let target = crate::Pad::from_template(&sink_0_templ); let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_u_templ, &target) .unwrap() .generated_name() .build(); assert!(ghost_pad.name().starts_with("ghostpad")); // # Request template %d_%u let wildcard_u_templ = crate::PadTemplate::new( "sink_%d_%u", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); // ## Incompatible target but specific name let target = crate::Pad::from_template(&sink_templ); let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_u_templ, &target) .unwrap() .name("sink_-1_0") .build(); assert_eq!(ghost_pad.name(), "sink_-1_0"); // ## Compatible target let sink_m2_0_templ = crate::PadTemplate::new( "sink_-2_0", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let target = crate::Pad::from_template(&sink_m2_0_templ); let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_u_templ, &target) .unwrap() .build(); assert_eq!(ghost_pad.name(), "sink_-2_0"); // # Request template %s let wildcard_s_templ = crate::PadTemplate::new( "sink_%s", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); // ## Incompatible target but specific name let target = crate::Pad::from_template(&sink_templ); let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_s_templ, &target) .unwrap() .name("sink_ghost_test") .build(); assert_eq!(ghost_pad.name(), "sink_ghost_test"); // ## Compatible target let sink_test_templ = crate::PadTemplate::new( "sink_test", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let target = crate::Pad::from_template(&sink_test_templ); let ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_s_templ, &target) .unwrap() .build(); assert_eq!(ghost_pad.name(), "sink_test"); } #[test] #[should_panic] fn from_template_with_target_incompatible_prefix() { crate::init().unwrap(); let caps = crate::Caps::new_any(); let wildcard_templ = crate::PadTemplate::new( "sink_%u", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); let templ = crate::PadTemplate::new( "audio_0", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let target = crate::Pad::from_template(&templ); // Panic: attempt to build from a wildcard-named template // with a target name with a different prefix // without providing a name. let _ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_templ, &target) .unwrap() .build(); } #[test] #[should_panic] fn from_template_with_target_missing_part() { crate::init().unwrap(); let caps = crate::Caps::new_any(); let wildcard_templ = crate::PadTemplate::new( "sink_%u_%s", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); let templ = crate::PadTemplate::new( "sink_0", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let target = crate::Pad::from_template(&templ); // Panic: attempt to build from a wildcard-named template // with a target name missing a part // without providing a name. let _ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_templ, &target) .unwrap() .build(); } #[test] #[should_panic] fn from_template_with_target_incompatible_conversion_unsigned() { crate::init().unwrap(); let caps = crate::Caps::new_any(); let wildcard_templ = crate::PadTemplate::new( "sink_%u", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); let templ = crate::PadTemplate::new( "sink_-1", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let target = crate::Pad::from_template(&templ); // Panic: attempt to build from a wildcard-named template // with a target name %d, expecting %u // without providing a name. let _ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_templ, &target) .unwrap() .build(); } #[test] #[should_panic] fn from_template_with_target_incompatible_conversion_decimal() { crate::init().unwrap(); let caps = crate::Caps::new_any(); let wildcard_templ = crate::PadTemplate::new( "sink_%u", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); let templ = crate::PadTemplate::new( "sink_test", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let target = crate::Pad::from_template(&templ); // Panic: attempt to build from a wildcard-named template // with a target name with %s, expecting %d // without providing a name. let _ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_templ, &target) .unwrap() .build(); } #[test] #[should_panic] fn from_template_with_target_incompatible_missing_decimal() { crate::init().unwrap(); let caps = crate::Caps::new_any(); let wildcard_templ = crate::PadTemplate::new( "sink_%d", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); let templ = crate::PadTemplate::new( "sink_", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let target = crate::Pad::from_template(&templ); // Panic: attempt to build from a wildcard-named template // with a target name missing a number, expecting %d // without providing a name. let _ghost_pad = GhostPad::builder_from_template_with_target(&wildcard_templ, &target) .unwrap() .build(); } } gstreamer-0.23.5/src/gobject.rs000064400000000000000000000043501046102023000144600ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::prelude::*; use crate::value::GstValueExt; mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait GObjectExtManualGst: sealed::Sealed + IsA + 'static { #[doc(alias = "gst_util_set_object_arg")] #[track_caller] fn set_property_from_str(&self, name: &str, value: &str) { let pspec = self.find_property(name).unwrap_or_else(|| { panic!("property '{}' of type '{}' not found", name, self.type_()); }); let value = { if pspec.value_type() == crate::Structure::static_type() && value == "NULL" { None::.to_value() } else { #[cfg(feature = "v1_20")] { glib::Value::deserialize_with_pspec(value, &pspec).unwrap_or_else(|_| { panic!( "property '{}' of type '{}' can't be set from string '{}'", name, self.type_(), value, ) }) } #[cfg(not(feature = "v1_20"))] { glib::Value::deserialize(value, pspec.value_type()).unwrap_or_else(|_| { panic!( "property '{}' of type '{}' can't be set from string '{}'", name, self.type_(), value, ) }) } } }; self.set_property(name, value) } } impl> GObjectExtManualGst for O {} #[cfg(test)] mod tests { use super::*; #[test] fn test_set_property_from_str() { crate::init().unwrap(); let fakesink = crate::ElementFactory::make("fakesink").build().unwrap(); fakesink.set_property_from_str("state-error", "ready-to-paused"); let v = fakesink.property_value("state-error"); let (_klass, e) = glib::EnumValue::from_value(&v).unwrap(); assert_eq!(e.nick(), "ready-to-paused"); } } gstreamer-0.23.5/src/gtype.rs000064400000000000000000000055571046102023000142050ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ffi::c_void; use crate::ffi; use glib::translate::*; pub trait PluginApiExt { #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "gst_type_mark_as_plugin_api")] fn mark_as_plugin_api(self, flags: crate::PluginAPIFlags); #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "gst_type_is_plugin_api")] fn plugin_api_flags(self) -> Option; #[doc(alias = "gst_element_type_set_skip_documentation")] fn set_skip_documentation(self); #[doc(alias = "gst_element_factory_get_skip_documentation")] fn skip_documentation(self) -> bool; } impl PluginApiExt for glib::Type { fn set_skip_documentation(self) { let quark = glib::Quark::from_str("GST_ELEMENTCLASS_SKIP_DOCUMENTATION"); unsafe { crate::glib::gobject_ffi::g_type_set_qdata( self.into_glib(), quark.into_glib(), 1 as *mut c_void, ); } } fn skip_documentation(self) -> bool { let quark = glib::Quark::from_str("GST_ELEMENTCLASS_SKIP_DOCUMENTATION"); unsafe { !crate::glib::gobject_ffi::g_type_get_qdata(self.into_glib(), quark.into_glib()) .is_null() } } fn plugin_api_flags(self) -> Option { assert_initialized_main_thread!(); unsafe { use std::mem; let mut flags = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_type_is_plugin_api( self.into_glib(), flags.as_mut_ptr(), )); if ret { Some(from_glib(flags.assume_init())) } else { None } } } fn mark_as_plugin_api(self, flags: crate::PluginAPIFlags) { assert_initialized_main_thread!(); unsafe { ffi::gst_type_mark_as_plugin_api(self.into_glib(), flags.into_glib()) } } } #[cfg(test)] mod tests { use glib::prelude::StaticType; use super::*; #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy, glib::Enum)] #[repr(u32)] #[enum_type(name = "GstTestEnum")] pub enum TestEnum { #[enum_value(name = "test", nick = "test")] Test, } #[test] fn test_gtype_mark_as_api() { crate::init().unwrap(); assert!(TestEnum::static_type().plugin_api_flags().is_none()); assert!(!TestEnum::static_type().skip_documentation()); TestEnum::static_type().mark_as_plugin_api(crate::PluginAPIFlags::empty()); TestEnum::static_type().set_skip_documentation(); assert!( TestEnum::static_type().plugin_api_flags().unwrap() == crate::PluginAPIFlags::empty() ); assert!(TestEnum::static_type().skip_documentation()); } } gstreamer-0.23.5/src/iterator.rs000064400000000000000000000612361046102023000147020ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{any::Any, fmt, iter, marker::PhantomData, mem, ptr, sync::Arc}; use crate::ffi; use glib::{ ffi::{gconstpointer, gpointer}, prelude::*, translate::*, value::{FromValue, ToValue}, Value, }; use thiserror::Error; #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Error)] pub enum IteratorError { #[error("Resync")] Resync, #[error("Error")] Error, } // Implemented manually so that we can use generics for the item pub struct Iterator { iter: ptr::NonNull, phantom: PhantomData, } impl Iterator where for<'a> T: FromValue<'a> + 'static, { #[allow(clippy::should_implement_trait)] #[doc(alias = "gst_iterator_next")] pub fn next(&mut self) -> Result, IteratorError> { unsafe { let mut value = Value::uninitialized(); let res = ffi::gst_iterator_next(self.to_glib_none_mut().0, value.to_glib_none_mut().0); #[allow(clippy::wildcard_in_or_patterns)] match res { ffi::GST_ITERATOR_OK => match value.get::() { Ok(value) => Ok(Some(value)), Err(_) => Err(IteratorError::Error), }, ffi::GST_ITERATOR_DONE => Ok(None), ffi::GST_ITERATOR_RESYNC => Err(IteratorError::Resync), ffi::GST_ITERATOR_ERROR | _ => Err(IteratorError::Error), } } } #[doc(alias = "gst_iterator_resync")] pub fn resync(&mut self) { unsafe { ffi::gst_iterator_resync(self.to_glib_none_mut().0); } } #[doc(alias = "gst_iterator_filter")] #[must_use] pub fn filter(self, func: F) -> Self where F: Fn(T) -> bool + Send + Sync + 'static, T: StaticType, { unsafe { let func_box: Box = Box::new(func); let mut closure_value = glib::Value::from_type_unchecked(filter_boxed_get_type()); glib::gobject_ffi::g_value_take_boxed( closure_value.to_glib_none_mut().0, Arc::into_raw(Arc::new(func_box)) as gpointer, ); from_glib_full(ffi::gst_iterator_filter( self.into_glib_ptr(), Some(filter_trampoline::), closure_value.to_glib_none().0, )) } } #[doc(alias = "gst_iterator_find_custom")] pub fn find(&mut self, func: F) -> Option where F: FnMut(T) -> bool, { unsafe { let mut elem = glib::Value::uninitialized(); let mut func = func; let func_ptr = &mut func as *mut F as gpointer; let res = from_glib(ffi::gst_iterator_find_custom( self.to_glib_none_mut().0, Some(find_trampoline::), elem.to_glib_none_mut().0, func_ptr, )); if res { Some(elem.get::().expect("Iterator::find")) } else { None } } } #[doc(alias = "gst_iterator_foreach")] pub fn foreach(&mut self, func: F) -> Result<(), IteratorError> where F: FnMut(T), { unsafe { let mut func = func; let func_ptr = &mut func as *mut F as gpointer; let res = ffi::gst_iterator_foreach( self.to_glib_none_mut().0, Some(foreach_trampoline::), func_ptr, ); #[allow(clippy::wildcard_in_or_patterns)] match res { ffi::GST_ITERATOR_OK | ffi::GST_ITERATOR_DONE => Ok(()), ffi::GST_ITERATOR_RESYNC => Err(IteratorError::Resync), ffi::GST_ITERATOR_ERROR | _ => Err(IteratorError::Error), } } } #[doc(alias = "gst_iterator_fold")] pub fn fold(&mut self, init: U, func: F) -> Result where F: FnMut(U, T) -> Result, { unsafe { let mut func = func; let func_ptr = &mut func as *mut F as gpointer; let mut accum = Some(init); let mut ret = glib::Value::from_type_unchecked(glib::Type::POINTER); glib::gobject_ffi::g_value_set_pointer( ret.to_glib_none_mut().0, &mut accum as *mut _ as gpointer, ); let res = ffi::gst_iterator_fold( self.to_glib_none_mut().0, Some(fold_trampoline::), ret.to_glib_none_mut().0, func_ptr, ); #[allow(clippy::wildcard_in_or_patterns)] match res { ffi::GST_ITERATOR_OK | ffi::GST_ITERATOR_DONE => Ok(accum.unwrap()), ffi::GST_ITERATOR_RESYNC => Err(IteratorError::Resync), ffi::GST_ITERATOR_ERROR | _ => Err(IteratorError::Error), } } } } impl Iterator where for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static, { #[doc(alias = "gst_iterator_new")] pub fn new>(imp: I) -> Self { assert_initialized_main_thread!(); static DUMMY_COOKIE: u32 = 0; unsafe { let it = ffi::gst_iterator_new( mem::size_of::>() as u32, T::static_type().into_glib(), ptr::null_mut(), &DUMMY_COOKIE as *const _ as *mut _, Some(rs_iterator_copy::), Some(rs_iterator_next::), None, Some(rs_iterator_resync::), Some(rs_iterator_free::), ); { let it = it as *mut RsIterator; ptr::write(&mut (*it).imp, imp); } from_glib_full(it) } } } impl Iterator where for<'a> T: FromValue<'a> + StaticType + ToValue + Clone + Send + 'static, { pub fn from_vec(items: Vec) -> Self { skip_assert_initialized!(); Self::new(ArrayIteratorImpl::new(items)) } pub fn from_array + Send + Clone + 'static>(items: A) -> Self { skip_assert_initialized!(); Self::new(ArrayIteratorImpl::new(items)) } pub fn from_option(items: Option) -> Self { skip_assert_initialized!(); Self::new(OptionIteratorImpl::new(items)) } pub fn from_single(item: T) -> Self { skip_assert_initialized!(); Self::new(OptionIteratorImpl::new(Some(item))) } } impl IntoGlibPtr<*mut ffi::GstIterator> for Iterator { #[inline] unsafe fn into_glib_ptr(self) -> *mut ffi::GstIterator { let s = mem::ManuallyDrop::new(self); let it = s.to_glib_none().0; it as *mut _ } } #[repr(C)] struct RsIterator> where for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static, { iter: ffi::GstIterator, imp: I, phantom: PhantomData, } pub trait IteratorImpl: Clone + Send + 'static where for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static, { fn next(&mut self) -> Option>; fn resync(&mut self); } unsafe extern "C" fn rs_iterator_copy>( it: *const ffi::GstIterator, copy: *mut ffi::GstIterator, ) where for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static, { let it = it as *const RsIterator; let copy = copy as *mut RsIterator; ptr::write(&mut (*copy).imp, (*it).imp.clone()); } unsafe extern "C" fn rs_iterator_free>(it: *mut ffi::GstIterator) where for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static, { let it = it as *mut RsIterator; ptr::drop_in_place(&mut (*it).imp); } unsafe extern "C" fn rs_iterator_next>( it: *mut ffi::GstIterator, result: *mut glib::gobject_ffi::GValue, ) -> ffi::GstIteratorResult where for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static, { let it = it as *mut RsIterator; match (*it).imp.next() { Some(Ok(value)) => { let value = value.to_value(); ptr::write(result, value.into_raw()); ffi::GST_ITERATOR_OK } None => ffi::GST_ITERATOR_DONE, Some(Err(res)) => match res { IteratorError::Resync => ffi::GST_ITERATOR_RESYNC, IteratorError::Error => ffi::GST_ITERATOR_ERROR, }, } } unsafe extern "C" fn rs_iterator_resync>(it: *mut ffi::GstIterator) where for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static, { let it = it as *mut RsIterator; (*it).imp.resync(); } #[derive(Clone)] struct ArrayIteratorImpl { pos: usize, items: A, phantom: PhantomData, } impl ArrayIteratorImpl { fn new(items: A) -> Self { skip_assert_initialized!(); Self { pos: 0, items, phantom: PhantomData, } } } impl IteratorImpl for ArrayIteratorImpl where A: AsRef<[T]> + Send + Clone + 'static, for<'a> T: StaticType + ToValue + FromValue<'a> + Clone + Send + 'static, { fn next(&mut self) -> Option> { let items = self.items.as_ref(); if self.pos < items.len() { let res = Ok(items[self.pos].clone()); self.pos += 1; return Some(res); } None } fn resync(&mut self) { self.pos = 0; } } #[derive(Clone)] struct OptionIteratorImpl { finished: bool, items: Option, } impl OptionIteratorImpl { fn new(items: Option) -> Self { skip_assert_initialized!(); Self { finished: false, items, } } } impl IteratorImpl for OptionIteratorImpl where for<'a> T: StaticType + ToValue + FromValue<'a> + Clone + Send + 'static, { fn next(&mut self) -> Option> { if self.finished { return None; } let res = Ok(self.items.clone()).transpose(); self.finished = true; res } fn resync(&mut self) { self.finished = false; } } unsafe impl Send for Iterator {} unsafe impl Sync for Iterator {} unsafe extern "C" fn filter_trampoline< T: for<'a> FromValue<'a> + StaticType + 'static, F: Fn(T) -> bool + Send + Sync + 'static, >( value: gconstpointer, func: gconstpointer, ) -> i32 { let value = value as *const glib::gobject_ffi::GValue; let func = func as *const glib::gobject_ffi::GValue; let func = glib::gobject_ffi::g_value_get_boxed(func); let func = &*(func as *const &(dyn Any + Send + Sync + 'static)); let func = func.downcast_ref::().unwrap(); let value = &*(value as *const glib::Value); let value = value.get::().expect("Iterator filter_trampoline"); if func(value) { 0 } else { -1 } } unsafe extern "C" fn filter_boxed_ref(boxed: gpointer) -> gpointer { let boxed = Arc::from_raw(boxed as *const Box); let copy = Arc::clone(&boxed); // Forget it and keep it alive, we will still need it later let _ = Arc::into_raw(boxed); Arc::into_raw(copy) as gpointer } unsafe extern "C" fn filter_boxed_unref(boxed: gpointer) { let _ = Arc::from_raw(boxed as *const Box); } unsafe extern "C" fn filter_boxed_get_type() -> glib::Type { static TYPE: std::sync::OnceLock = std::sync::OnceLock::new(); *TYPE.get_or_init(|| { let iter_type_name = { let mut idx = 0; loop { let iter_type_name = glib::gformat!("GstRsIteratorFilterBoxed-{}", idx); if glib::gobject_ffi::g_type_from_name(iter_type_name.as_ptr()) == glib::gobject_ffi::G_TYPE_INVALID { break iter_type_name; } idx += 1; } }; let t = glib::Type::from_glib(glib::gobject_ffi::g_boxed_type_register_static( iter_type_name.as_ptr(), Some(filter_boxed_ref), Some(filter_boxed_unref), )); assert!(t.is_valid()); t }) } unsafe extern "C" fn find_trampoline bool>( value: gconstpointer, func: gconstpointer, ) -> i32 where for<'a> T: FromValue<'a> + 'static, { let value = value as *const glib::gobject_ffi::GValue; let func = func as *mut F; let value = &*(value as *const glib::Value); let value = value.get::().expect("Iterator find_trampoline"); if (*func)(value) { 0 } else { -1 } } unsafe extern "C" fn foreach_trampoline( value: *const glib::gobject_ffi::GValue, func: gpointer, ) where for<'a> T: FromValue<'a> + 'static, { let func = func as *mut F; let value = &*(value as *const glib::Value); let value = value.get::().expect("Iterator foreach_trampoline"); (*func)(value); } unsafe extern "C" fn fold_trampoline Result>( value: *const glib::gobject_ffi::GValue, ret: *mut glib::gobject_ffi::GValue, func: gpointer, ) -> glib::ffi::gboolean where for<'a> T: FromValue<'a> + 'static, { let func = func as *mut F; let value = &*(value as *const glib::Value); let value = value.get::().expect("Iterator fold_trampoline"); let accum = &mut *(glib::gobject_ffi::g_value_get_pointer(ret) as *mut Option); match (*func)(accum.take().unwrap(), value) { Ok(next_accum) => { *accum = Some(next_accum); glib::ffi::GTRUE } Err(next_accum) => { *accum = Some(next_accum); glib::ffi::GFALSE } } } impl Clone for Iterator { #[inline] fn clone(&self) -> Self { unsafe { from_glib_full(ffi::gst_iterator_copy(self.to_glib_none().0)) } } } impl fmt::Debug for Iterator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Iterator") .field("iter", &self.iter) .finish() } } impl Drop for Iterator { #[inline] fn drop(&mut self) { unsafe { ffi::gst_iterator_free(self.iter.as_ptr()); } } } impl iter::IntoIterator for Iterator where for<'a> T: FromValue<'a> + 'static, { type Item = Result; type IntoIter = StdIterator; fn into_iter(self) -> Self::IntoIter { Self::IntoIter::new(self) } } impl glib::types::StaticType for Iterator { #[inline] fn static_type() -> glib::types::Type { unsafe { glib::translate::from_glib(ffi::gst_iterator_get_type()) } } } impl glib::value::ValueType for Iterator { type Type = Self; } impl glib::value::ValueTypeOptional for Iterator {} unsafe impl<'a, T: StaticType + 'static> glib::value::FromValue<'a> for Iterator { type Checker = glib::value::GenericValueTypeOrNoneChecker; unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib_none( glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut ffi::GstIterator ) } } impl glib::value::ToValue for Iterator { fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, self.to_glib_none().0 as *mut _, ) } value } fn value_type(&self) -> glib::Type { Self::static_type() } } impl glib::value::ToValueOptional for Iterator { fn to_value_optional(s: Option<&Self>) -> glib::Value { skip_assert_initialized!(); let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, s.to_glib_none().0 as *mut _, ) } value } } impl From> for glib::Value { fn from(v: Iterator) -> glib::Value { skip_assert_initialized!(); let mut value = glib::Value::for_value_type::>(); unsafe { glib::gobject_ffi::g_value_take_boxed( value.to_glib_none_mut().0, v.into_glib_ptr() as *mut _, ) } value } } #[doc(hidden)] impl glib::translate::GlibPtrDefault for Iterator { type GlibType = *mut ffi::GstIterator; } #[doc(hidden)] unsafe impl TransparentPtrType for Iterator {} #[doc(hidden)] impl<'a, T: 'static> glib::translate::ToGlibPtr<'a, *const ffi::GstIterator> for Iterator { type Storage = PhantomData<&'a Iterator>; #[inline] fn to_glib_none(&'a self) -> glib::translate::Stash<'a, *const ffi::GstIterator, Self> { glib::translate::Stash(self.iter.as_ptr(), PhantomData) } fn to_glib_full(&self) -> *const ffi::GstIterator { unimplemented!() } } #[doc(hidden)] impl<'a, T: 'static> glib::translate::ToGlibPtrMut<'a, *mut ffi::GstIterator> for Iterator { type Storage = PhantomData<&'a mut Iterator>; #[inline] fn to_glib_none_mut( &'a mut self, ) -> glib::translate::StashMut<'a, *mut ffi::GstIterator, Self> { glib::translate::StashMut(self.iter.as_ptr(), PhantomData) } } #[doc(hidden)] impl glib::translate::FromGlibPtrNone<*const ffi::GstIterator> for Iterator { #[inline] unsafe fn from_glib_none(ptr: *const ffi::GstIterator) -> Self { debug_assert_ne!( glib::gobject_ffi::g_type_is_a((*ptr).type_, T::static_type().into_glib()), glib::ffi::GFALSE ); from_glib_full(ffi::gst_iterator_copy(ptr)) } } #[doc(hidden)] impl glib::translate::FromGlibPtrNone<*mut ffi::GstIterator> for Iterator { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::GstIterator) -> Self { debug_assert_ne!( glib::gobject_ffi::g_type_is_a((*ptr).type_, T::static_type().into_glib()), glib::ffi::GFALSE ); from_glib_full(ffi::gst_iterator_copy(ptr)) } } #[doc(hidden)] impl glib::translate::FromGlibPtrBorrow<*mut ffi::GstIterator> for Iterator { #[inline] unsafe fn from_glib_borrow(ptr: *mut ffi::GstIterator) -> Borrowed { debug_assert!(!ptr.is_null()); debug_assert_ne!( glib::gobject_ffi::g_type_is_a((*ptr).type_, T::static_type().into_glib()), glib::ffi::GFALSE ); Borrowed::new(Self { iter: ptr::NonNull::new_unchecked(ptr), phantom: PhantomData, }) } } #[doc(hidden)] impl glib::translate::FromGlibPtrFull<*mut ffi::GstIterator> for Iterator { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::GstIterator) -> Self { debug_assert!(!ptr.is_null()); debug_assert_ne!( glib::gobject_ffi::g_type_is_a((*ptr).type_, T::static_type().into_glib()), glib::ffi::GFALSE ); Self { iter: ptr::NonNull::new_unchecked(ptr), phantom: PhantomData, } } } pub struct StdIterator { inner: Iterator, error: Option, } impl StdIterator { fn new(inner: Iterator) -> Self { skip_assert_initialized!(); Self { inner, error: None } } } impl Clone for StdIterator { #[inline] fn clone(&self) -> Self { Self { inner: self.inner.clone(), error: self.error, } } } impl fmt::Debug for StdIterator { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("StdIterator") .field("inner", &self.inner) .field("error", &self.error) .finish() } } impl iter::Iterator for StdIterator where for<'a> T: FromValue<'a> + 'static, { type Item = Result; fn next(&mut self) -> Option { match self.error { // Fuse the iterator after returning IteratorError::Error Some(IteratorError::Error) => return None, // The iterator needs a resync Some(IteratorError::Resync) => self.inner.resync(), None => {} } let res = self.inner.next(); self.error = res.as_ref().err().copied(); res.transpose() } } impl iter::FusedIterator for StdIterator where for<'a> T: FromValue<'a> + 'static {} #[cfg(test)] mod tests { use super::*; #[test] fn test_vec() { crate::init().unwrap(); let vec = vec![1i32, 2, 3]; let mut it = Iterator::from_vec(vec); let val = it.next(); assert_eq!(val, Ok(Some(1))); let val = it.next(); assert_eq!(val, Ok(Some(2))); let val = it.next(); assert_eq!(val, Ok(Some(3))); assert_eq!(it.next(), Ok(None)); let vec = vec![1i32, 2, 3]; let mut it = Iterator::from_vec(vec); let mut vals = Vec::new(); while let Ok(Some(res)) = it.next() { vals.push(res); } assert_eq!(vals, [1, 2, 3]); } #[test] fn test_filter() { crate::init().unwrap(); let vec = vec![1i32, 2, 3]; let mut it = Iterator::from_vec(vec).filter(|val| val % 2 == 1); let mut vals = Vec::new(); while let Ok(Some(res)) = it.next() { vals.push(res); } assert_eq!(vals, [1, 3]); } #[test] fn test_find() { crate::init().unwrap(); // Our find let vec = vec![1i32, 2, 3]; let val = Iterator::from_vec(vec).find(|val| val == 2); assert_eq!(val.unwrap(), 2); } #[test] fn test_foreach() { crate::init().unwrap(); let vec = vec![1i32, 2, 3]; let mut sum = 0; let res = Iterator::from_vec(vec).foreach(|val| sum += val); assert_eq!(res, Ok(())); assert_eq!(sum, 6); } #[test] fn test_fold() { crate::init().unwrap(); // Our fold let vec = vec![1i32, 2, 3]; let res = Iterator::from_vec(vec).fold(0, |mut sum, val| { sum += val; Ok(sum) }); assert_eq!(res.unwrap(), 6); } #[test] fn test_std() { crate::init().unwrap(); let mut it = Iterator::from_vec(vec![1i32, 2, 3]).into_iter(); assert_eq!(it.next(), Some(Ok(1))); assert_eq!(it.next(), Some(Ok(2))); assert_eq!(it.next(), Some(Ok(3))); assert_eq!(it.next(), None); } #[test] fn test_into_iter() { crate::init().unwrap(); let mut v = vec![1i32, 2, 3].into_iter(); for x in Iterator::from_vec(vec![1i32, 2, 3]) { assert_eq!(x.unwrap(), v.next().unwrap()); } assert_eq!(v.next(), None); } #[test] fn test_std_resync_collect() { use std::collections::BTreeSet; use crate::prelude::*; crate::init().unwrap(); let bin = crate::Bin::new(); let id1 = crate::ElementFactory::make("identity").build().unwrap(); let id2 = crate::ElementFactory::make("identity").build().unwrap(); bin.add(&id1).unwrap(); let mut it = bin.iterate_elements().into_iter(); assert_eq!(it.next().unwrap().unwrap(), id1); bin.add(&id2).unwrap(); let res = it.by_ref().collect::, _>>().unwrap_err(); assert_eq!(res, IteratorError::Resync); let mut elems = BTreeSet::new(); elems.insert(id1); elems.insert(id2); let res = it.by_ref().collect::, _>>().unwrap(); assert_eq!(res, elems); let res = it.collect::, _>>().unwrap(); assert!(res.is_empty()); } #[test] fn test_std_resync_find() { use crate::prelude::*; crate::init().unwrap(); let bin = crate::Bin::new(); let id1 = crate::ElementFactory::make("identity").build().unwrap(); let id2 = crate::ElementFactory::make("identity").build().unwrap(); bin.add(&id1).unwrap(); let mut it = bin.iterate_elements().into_iter(); assert_eq!(it.next().unwrap().unwrap(), id1); bin.add(&id2).unwrap(); let res = it.find(|x| x.as_ref() == Ok(&id1)); assert_eq!(res.unwrap().unwrap(), id1); } } gstreamer-0.23.5/src/lib.rs000064400000000000000000000240431046102023000136120ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #![cfg_attr(docsrs, feature(doc_cfg))] #![allow(clippy::missing_safety_doc)] #![allow(clippy::manual_range_contains)] #![allow(clippy::manual_c_str_literals)] #![doc = include_str!("../README.md")] // Re-exported for the subclass gst_plugin_define! macro pub use glib; pub use gstreamer_sys as ffi; pub use paste; #[doc(hidden)] pub static INITIALIZED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); #[cold] #[inline(never)] #[track_caller] pub fn assert_initialized() { #[allow(unused_unsafe)] if unsafe { ffi::gst_is_initialized() } != glib::ffi::GTRUE { panic!("GStreamer has not been initialized. Call `gst::init` first."); } else { crate::INITIALIZED.store(true, std::sync::atomic::Ordering::SeqCst); } } macro_rules! assert_initialized_main_thread { () => { if !crate::INITIALIZED.load(std::sync::atomic::Ordering::SeqCst) { $crate::assert_initialized(); } }; } macro_rules! skip_assert_initialized { () => {}; } #[allow(clippy::needless_borrow)] #[allow(clippy::let_unit_value)] #[allow(unused_imports)] mod auto; pub use crate::auto::*; #[macro_use] #[cfg(feature = "serde")] mod serde_macros; #[macro_use] pub mod log; #[cfg(feature = "log")] pub use crate::log::DebugCategoryLogger; pub use crate::log::{ DebugCategory, DebugLogFunction, DebugMessage, LoggedObject, CAT_BUFFER, CAT_BUFFER_LIST, CAT_BUS, CAT_CALL_TRACE, CAT_CAPS, CAT_CLOCK, CAT_CONTEXT, CAT_DEFAULT, CAT_ELEMENT_PADS, CAT_ERROR_SYSTEM, CAT_EVENT, CAT_GST_INIT, CAT_LOCKING, CAT_MEMORY, CAT_MESSAGE, CAT_META, CAT_NEGOTIATION, CAT_PADS, CAT_PARAMS, CAT_PARENTAGE, CAT_PERFORMANCE, CAT_PIPELINE, CAT_PLUGIN_INFO, CAT_PLUGIN_LOADING, CAT_PROBE, CAT_PROPERTIES, CAT_QOS, CAT_REFCOUNTING, CAT_REGISTRY, CAT_RUST, CAT_SCHEDULING, CAT_SIGNAL, CAT_STATES, }; #[cfg(target_os = "macos")] mod macos; #[cfg(target_os = "macos")] pub use crate::macos::*; #[macro_use] mod error; pub use crate::error::*; #[macro_use] pub mod miniobject; pub use miniobject::{MiniObject, MiniObjectRef}; #[macro_use] mod value; pub use crate::value::{ Array, ArrayRef, Bitmask, Fraction, FractionRange, IntRange, List, ListRef, }; #[cfg(feature = "serde")] #[macro_use] mod value_serde; #[cfg(feature = "serde")] mod flag_serde; pub mod message; pub use crate::message::{Message, MessageErrorDomain, MessageRef, MessageView, MessageViewMut}; pub mod structure; pub use crate::structure::{Structure, StructureRef}; #[cfg(feature = "serde")] mod structure_serde; pub mod caps; pub use crate::caps::{Caps, CapsFilterMapAction, CapsRef}; mod caps_features; #[cfg(feature = "serde")] mod caps_serde; pub use crate::caps_features::{ CapsFeatures, CapsFeaturesRef, CAPS_FEATURES_MEMORY_SYSTEM_MEMORY, CAPS_FEATURE_MEMORY_SYSTEM_MEMORY, }; #[cfg(feature = "serde")] mod caps_features_serde; pub mod tags; pub use crate::tags::{ tag_exists, tag_get_description, tag_get_flag, tag_get_nick, tag_get_type, Tag, TagList, TagListRef, }; #[cfg(feature = "serde")] mod tags_serde; #[macro_use] pub mod meta; #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] pub use crate::meta::MetaSeqnum; pub use crate::meta::{ Meta, MetaAPI, MetaAPIExt, MetaRef, MetaRefMut, ParentBufferMeta, ProtectionMeta, ReferenceTimestampMeta, }; pub mod buffer; pub use crate::buffer::{ Buffer, BufferMap, BufferRef, MappedBuffer, BUFFER_COPY_ALL, BUFFER_COPY_METADATA, }; mod buffer_cursor; pub use crate::buffer_cursor::{BufferCursor, BufferRefCursor}; pub mod memory; mod memory_wrapped; pub use crate::memory::{MappedMemory, Memory, MemoryMap, MemoryRef}; #[cfg(feature = "serde")] mod buffer_serde; pub mod slice; pub mod sample; pub use crate::sample::{Sample, SampleRef}; #[cfg(feature = "serde")] mod sample_serde; pub mod bufferlist; pub use crate::bufferlist::{BufferList, BufferListRef}; #[cfg(feature = "serde")] mod bufferlist_serde; pub mod query; pub use crate::query::{Query, QueryRef, QueryView, QueryViewMut}; pub mod event; pub use crate::event::{Event, EventRef, EventView, EventViewMut, GroupId, Seqnum}; pub mod context; pub use crate::context::{Context, ContextRef}; mod rank; pub use crate::rank::Rank; mod static_caps; pub use crate::static_caps::*; mod static_pad_template; pub use crate::static_pad_template::*; pub mod promise; pub use promise::{Promise, PromiseError}; pub mod bus; mod element; pub mod element_factory; mod bin; pub use bin::BinBuilder; mod pipeline; pub use pipeline::PipelineBuilder; mod allocation_params; pub use self::allocation_params::AllocationParams; mod allocator; mod element_factory_type; pub use element_factory_type::*; mod tracer; mod tracer_factory; // OS dependent Bus extensions (also import the other platform mod for doc) #[cfg(any(unix, docsrs))] mod bus_unix; #[cfg(any(windows, docsrs))] mod bus_windows; mod child_proxy; mod date_time; #[cfg(feature = "serde")] mod date_time_serde; mod device_monitor; mod device_provider; mod device_provider_factory; mod enums; mod ghost_pad; mod gobject; mod iterator; mod object; mod pad; pub use pad::{ EventForeachAction, PadBuilder, PadGetRangeSuccess, PadProbeData, PadProbeId, PadProbeInfo, StreamLock, }; mod control_binding; mod control_source; mod parse_context; mod proxy_pad; mod registry; mod tag_setter; pub mod task; pub use task::{TaskLock, TaskLockGuard}; mod task_pool; pub use self::iterator::{Iterator, IteratorError, IteratorImpl, StdIterator}; pub use crate::{ device_monitor::DeviceMonitorFilterId, element::{ ElementMessageType, NotifyWatchId, ELEMENT_METADATA_AUTHOR, ELEMENT_METADATA_DESCRIPTION, ELEMENT_METADATA_DOC_URI, ELEMENT_METADATA_ICON_NAME, ELEMENT_METADATA_KLASS, ELEMENT_METADATA_LONGNAME, }, enums::{ ClockError, ClockSuccess, FlowError, FlowReturn, FlowSuccess, MessageType, PadLinkError, PadLinkReturn, PadLinkSuccess, StateChangeError, StateChangeSuccess, TagError, }, parse_context::ParseContext, task_pool::{TaskHandle, TaskPoolTaskHandle}, }; mod plugin_feature; mod plugin; pub mod stream; pub mod stream_collection; mod typefind; pub use crate::typefind::*; mod typefind_factory; pub mod format; pub use crate::format::{ClockTime, GenericFormattedValue, GenericSignedFormattedValue, Signed}; mod segment; pub use crate::segment::*; #[cfg(feature = "serde")] mod segment_serde; pub mod toc; pub use crate::toc::{Toc, TocEntry, TocEntryRef, TocRef}; #[cfg(feature = "serde")] mod toc_serde; mod clock; pub use crate::clock::{AtomicClockReturn, ClockId, PeriodicClockId, SingleShotClockId}; mod buffer_pool; pub use crate::buffer_pool::{BufferPoolAcquireParams, BufferPoolConfig, BufferPoolConfigRef}; mod pad_template; pub use pad_template::PadTemplateBuilder; pub mod param_spec; pub use crate::param_spec::{ParamSpecArray, ParamSpecFraction}; mod functions; pub use crate::functions::*; mod utils; pub use crate::utils::ObjectLockGuard; pub mod parse; #[cfg(feature = "v1_18")] mod gtype; use std::ptr; #[doc(alias = "gst_init_check")] pub fn init() -> Result<(), glib::Error> { unsafe { use glib::translate::*; let mut error = ptr::null_mut(); if from_glib(ffi::gst_init_check( ptr::null_mut(), ptr::null_mut(), &mut error, )) { crate::INITIALIZED.store(true, std::sync::atomic::Ordering::SeqCst); Ok(()) } else { Err(from_glib_full(error)) } } } // rustdoc-stripper-ignore-next /// Deinitialize GStreamer /// /// # Safety /// /// This must only be called once during the lifetime of the process, once no GStreamer threads /// are running anymore and all GStreamer resources are released. pub unsafe fn deinit() { crate::INITIALIZED.store(false, std::sync::atomic::Ordering::SeqCst); ffi::gst_deinit(); } pub const PARAM_FLAG_CONTROLLABLE: glib::ParamFlags = glib::ParamFlags::USER_1; pub const PARAM_FLAG_MUTABLE_READY: glib::ParamFlags = glib::ParamFlags::USER_2; pub const PARAM_FLAG_MUTABLE_PAUSED: glib::ParamFlags = glib::ParamFlags::USER_3; pub const PARAM_FLAG_MUTABLE_PLAYING: glib::ParamFlags = glib::ParamFlags::USER_4; #[cfg(feature = "v1_18")] pub const PARAM_FLAG_DOC_SHOW_DEFAULT: glib::ParamFlags = glib::ParamFlags::USER_5; #[cfg(feature = "v1_18")] pub const PARAM_FLAG_CONDITIONALLY_AVAILABLE: glib::ParamFlags = glib::ParamFlags::USER_6; // Re-export all the traits in a prelude module, so that applications // can always "use gst::prelude::*" without getting conflicts pub mod prelude { #[doc(hidden)] pub use glib::prelude::*; pub use muldiv::MulDiv; pub use opt_ops::prelude::*; // OS dependent Bus extensions (also import the other platform trait for doc) #[cfg(any(unix, docsrs))] pub use crate::bus_unix::UnixBusExtManual; #[cfg(any(windows, docsrs))] pub use crate::bus_windows::WindowsBusExtManual; #[cfg(feature = "v1_18")] pub use crate::gtype::PluginApiExt; pub use crate::{ auto::traits::*, bin::GstBinExtManual, buffer_pool::BufferPoolExtManual, child_proxy::ChildProxyExtManual, clock::ClockExtManual, control_binding::ControlBindingExtManual, control_source::ControlSourceExtManual, device_monitor::DeviceMonitorExtManual, device_provider::{DeviceProviderClassExt, DeviceProviderExtManual}, element::{ElementClassExt, ElementExtManual}, format::prelude::*, gobject::GObjectExtManualGst, memory::MemoryType, message::MessageErrorDomain, meta::{MetaAPI, MetaAPIExt, MetaTag}, miniobject::IsMiniObject, object::GstObjectExtManual, pad::PadExtManual, param_spec::GstParamSpecBuilderExt, pipeline::GstPipelineExtManual, plugin_feature::PluginFeatureExtManual, slice::ByteSliceExt, tag_setter::TagSetterExtManual, tags::{CustomTag, Tag}, task_pool::{TaskHandle, TaskPoolExtManual}, typefind::TypeFindImpl, utils::Displayable, value::GstValueExt, }; } #[macro_use] pub mod subclass; gstreamer-0.23.5/src/log.rs000064400000000000000000001657231046102023000136400ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{borrow::Cow, ffi::CStr, fmt, ptr}; use glib::{ffi::gpointer, prelude::*, translate::*}; use libc::c_char; #[cfg(feature = "log")] use log; use once_cell::sync::Lazy; use crate::{ffi, DebugLevel}; // import and rename those so they are namespaced as log::* pub use crate::auto::functions::debug_add_ring_buffer_logger as add_ring_buffer_logger; pub use crate::auto::functions::debug_get_default_threshold as get_default_threshold; pub use crate::auto::functions::debug_get_stack_trace as get_stack_trace; pub use crate::auto::functions::debug_is_active as is_active; pub use crate::auto::functions::debug_is_colored as is_colored; pub use crate::auto::functions::debug_print_stack_trace as print_stack_trace; pub use crate::auto::functions::debug_remove_ring_buffer_logger as remove_ring_buffer_logger; pub use crate::auto::functions::debug_ring_buffer_logger_get_logs as ring_buffer_logger_get_logs; pub use crate::auto::functions::debug_set_active as set_active; pub use crate::auto::functions::debug_set_colored as set_colored; pub use crate::auto::functions::debug_set_default_threshold as set_default_threshold; pub use crate::auto::functions::debug_set_threshold_for_name as set_threshold_for_name; pub use crate::auto::functions::debug_set_threshold_from_string as set_threshold_from_string; pub use crate::auto::functions::debug_unset_threshold_for_name as unset_threshold_for_name; #[derive(PartialEq, Eq)] #[doc(alias = "GstDebugMessage")] pub struct DebugMessage(ptr::NonNull); impl fmt::Debug for DebugMessage { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("DebugMessage").field(&self.get()).finish() } } impl DebugMessage { #[doc(alias = "gst_debug_message_get")] #[inline] pub fn get(&self) -> Option> { unsafe { let message = ffi::gst_debug_message_get(self.0.as_ptr()); if message.is_null() { None } else { Some(glib::GStr::from_ptr_lossy(message)) } } } #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] #[doc(alias = "gst_debug_message_get_id")] #[inline] pub fn id(&self) -> Option<&glib::GStr> { unsafe { let id = ffi::gst_debug_message_get_id(self.0.as_ptr()); if id.is_null() { None } else { Some(glib::GStr::from_ptr(id)) } } } #[inline] pub fn as_ptr(&self) -> *mut ffi::GstDebugMessage { self.0.as_ptr() } } #[derive(PartialEq, Eq, Clone, Copy, Hash)] #[doc(alias = "GstDebugCategory")] #[repr(transparent)] pub struct DebugCategory(Option>); impl DebugCategory { #[doc(alias = "gst_debug_category_new")] #[doc(alias = "GST_DEBUG_CATEGORY")] #[doc(alias = "GST_DEBUG_CATEGORY_INIT")] pub fn new( name: &str, color: crate::DebugColorFlags, description: Option<&str>, ) -> DebugCategory { skip_assert_initialized!(); extern "C" { fn _gst_debug_category_new( name: *const c_char, color: ffi::GstDebugColorFlags, description: *const c_char, ) -> *mut ffi::GstDebugCategory; } // Gets the category if it exists already unsafe { let ptr = name.run_with_gstr(|name| { description.run_with_gstr(|description| { _gst_debug_category_new( name.to_glib_none().0, color.into_glib(), description.to_glib_none().0, ) }) }); // Can be NULL if the debug system is compiled out DebugCategory(ptr::NonNull::new(ptr)) } } #[doc(alias = "gst_debug_get_category")] #[inline] pub fn get(name: &str) -> Option { skip_assert_initialized!(); unsafe { extern "C" { fn _gst_debug_get_category(name: *const c_char) -> *mut ffi::GstDebugCategory; } let cat = name.run_with_gstr(|name| _gst_debug_get_category(name.to_glib_none().0)); if cat.is_null() { None } else { Some(DebugCategory(Some(ptr::NonNull::new_unchecked(cat)))) } } } #[doc(alias = "get_threshold")] #[doc(alias = "gst_debug_category_get_threshold")] #[inline] pub fn threshold(self) -> crate::DebugLevel { match self.0 { Some(cat) => unsafe { from_glib(cat.as_ref().threshold) }, None => crate::DebugLevel::None, } } #[doc(alias = "gst_debug_category_set_threshold")] #[inline] pub fn set_threshold(self, threshold: crate::DebugLevel) { if let Some(cat) = self.0 { unsafe { ffi::gst_debug_category_set_threshold(cat.as_ptr(), threshold.into_glib()) } } } #[doc(alias = "gst_debug_category_reset_threshold")] #[inline] pub fn reset_threshold(self) { if let Some(cat) = self.0 { unsafe { ffi::gst_debug_category_reset_threshold(cat.as_ptr()) } } } #[inline] pub fn above_threshold(self, level: crate::DebugLevel) -> bool { match self.0 { Some(cat) => unsafe { cat.as_ref().threshold >= level.into_glib() }, None => false, } } #[doc(alias = "get_color")] #[doc(alias = "gst_debug_category_get_color")] #[inline] pub fn color(self) -> crate::DebugColorFlags { match self.0 { Some(cat) => unsafe { from_glib(cat.as_ref().color) }, None => crate::DebugColorFlags::empty(), } } #[doc(alias = "get_name")] #[doc(alias = "gst_debug_category_get_name")] #[inline] pub fn name<'a>(self) -> &'a str { match self.0 { Some(cat) => unsafe { CStr::from_ptr(cat.as_ref().name).to_str().unwrap() }, None => "", } } #[doc(alias = "get_description")] #[doc(alias = "gst_debug_category_get_description")] #[inline] pub fn description<'a>(self) -> Option<&'a str> { let cat = self.0?; unsafe { let ptr = cat.as_ref().description; if ptr.is_null() { None } else { Some(CStr::from_ptr(ptr).to_str().unwrap()) } } } #[inline] #[doc(alias = "gst_debug_log")] #[doc(alias = "gst_debug_log_literal")] pub fn log( self, obj: Option<&impl IsA>, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, args: fmt::Arguments, ) { if !self.above_threshold(level) { return; } self.log_unfiltered_internal( obj.map(|obj| obj.as_ref()), level, file, function, line, args, ) } #[inline] #[doc(alias = "gst_debug_log_literal")] pub fn log_literal( self, obj: Option<&impl IsA>, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, msg: &glib::GStr, ) { if !self.above_threshold(level) { return; } self.log_literal_unfiltered_internal( obj.map(|obj| obj.as_ref()), level, file, function, line, msg, ) } // rustdoc-stripper-ignore-next /// Logs without checking the log level. #[inline] #[doc(alias = "gst_debug_log")] pub fn log_unfiltered( self, obj: Option<&impl IsA>, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, args: fmt::Arguments, ) { self.log_unfiltered_internal( obj.map(|obj| obj.as_ref()), level, file, function, line, args, ) } // rustdoc-stripper-ignore-next /// Logs without checking the log level. #[inline] #[doc(alias = "gst_debug_log_literal")] pub fn log_literal_unfiltered( self, obj: Option<&impl IsA>, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, msg: &glib::GStr, ) { self.log_literal_unfiltered_internal( obj.map(|obj| obj.as_ref()), level, file, function, line, msg, ) } #[inline(never)] fn log_unfiltered_internal( self, obj: Option<&glib::Object>, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, args: fmt::Arguments, ) { let mut w = smallvec::SmallVec::<[u8; 256]>::new(); // Can't really happen but better safe than sorry if std::io::Write::write_fmt(&mut w, args).is_err() { return; } w.push(0); self.log_literal_unfiltered_internal(obj, level, file, function, line, unsafe { glib::GStr::from_utf8_with_nul_unchecked(&w) }); } #[inline(never)] fn log_literal_unfiltered_internal( self, obj: Option<&glib::Object>, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, msg: &glib::GStr, ) { let cat = match self.0 { Some(cat) => cat, None => return, }; let obj_ptr = match obj { Some(obj) => obj.as_ptr(), None => ptr::null_mut(), }; function.run_with_gstr(|function| { #[cfg(feature = "v1_20")] unsafe { ffi::gst_debug_log_literal( cat.as_ptr(), level.into_glib(), file.as_ptr(), function.as_ptr(), line as i32, obj_ptr, msg.as_ptr(), ); } #[cfg(not(feature = "v1_20"))] unsafe { ffi::gst_debug_log( cat.as_ptr(), level.into_glib(), file.as_ptr(), function.as_ptr(), line as i32, obj_ptr, b"%s\0".as_ptr() as *const _, msg.as_ptr(), ); } }); } #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] #[inline] #[doc(alias = "gst_debug_log_id")] pub fn log_id( self, id: impl AsRef, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, args: fmt::Arguments, ) { if !self.above_threshold(level) { return; } self.log_id_unfiltered_internal(id.as_ref(), level, file, function, line, args); } #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] #[inline] #[doc(alias = "gst_debug_log_id_literal")] pub fn log_id_literal( self, id: impl AsRef, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, msg: &glib::GStr, ) { if !self.above_threshold(level) { return; } self.log_id_literal_unfiltered_internal(id.as_ref(), level, file, function, line, msg); } #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] // rustdoc-stripper-ignore-next /// Logs without checking the log level. #[inline] #[doc(alias = "gst_debug_log_id")] pub fn log_id_unfiltered( self, id: impl AsRef, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, args: fmt::Arguments, ) { self.log_id_unfiltered_internal(id.as_ref(), level, file, function, line, args) } #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] // rustdoc-stripper-ignore-next /// Logs without checking the log level. #[inline] #[doc(alias = "gst_debug_log_id_literal")] pub fn log_id_literal_unfiltered( self, id: impl AsRef, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, msg: &glib::GStr, ) { self.log_id_literal_unfiltered_internal(id.as_ref(), level, file, function, line, msg) } #[cfg(feature = "v1_22")] #[inline(never)] fn log_id_unfiltered_internal( self, id: &glib::GStr, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, args: fmt::Arguments, ) { let mut w = smallvec::SmallVec::<[u8; 256]>::new(); // Can't really happen but better safe than sorry if std::io::Write::write_fmt(&mut w, args).is_err() { return; } w.push(0); self.log_id_literal_unfiltered_internal(id, level, file, function, line, unsafe { glib::GStr::from_utf8_with_nul_unchecked(&w) }); } #[cfg(feature = "v1_22")] #[inline(never)] fn log_id_literal_unfiltered_internal( self, id: &glib::GStr, level: crate::DebugLevel, file: &glib::GStr, function: &str, line: u32, msg: &glib::GStr, ) { let cat = match self.0 { Some(cat) => cat, None => return, }; function.run_with_gstr(|function| unsafe { ffi::gst_debug_log_id_literal( cat.as_ptr(), level.into_glib(), file.as_ptr(), function.as_ptr(), line as i32, id.as_ptr(), msg.as_ptr(), ); }); } #[doc(alias = "get_all_categories")] #[doc(alias = "gst_debug_get_all_categories")] #[inline] pub fn all_categories() -> glib::SList { unsafe { glib::SList::from_glib_container(ffi::gst_debug_get_all_categories()) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "gst_debug_log_get_line")] #[inline] pub fn get_line( &self, level: crate::DebugLevel, file: &glib::GStr, function: &glib::GStr, line: u32, object: Option<&LoggedObject>, message: &DebugMessage, ) -> Option { let cat = self.0?; unsafe { from_glib_full(ffi::gst_debug_log_get_line( cat.as_ptr(), level.into_glib(), file.as_ptr(), function.as_ptr(), line as i32, object.map(|o| o.as_ptr()).unwrap_or(ptr::null_mut()), message.0.as_ptr(), )) } } #[inline] pub fn as_ptr(&self) -> *mut ffi::GstDebugCategory { self.0.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()) } } unsafe impl Sync for DebugCategory {} unsafe impl Send for DebugCategory {} impl fmt::Debug for DebugCategory { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("DebugCategory").field(&self.name()).finish() } } impl GlibPtrDefault for DebugCategory { type GlibType = *mut ffi::GstDebugCategory; } unsafe impl TransparentPtrType for DebugCategory {} impl FromGlibPtrNone<*mut ffi::GstDebugCategory> for DebugCategory { #[inline] unsafe fn from_glib_none(ptr: *mut ffi::GstDebugCategory) -> Self { debug_assert!(!ptr.is_null()); DebugCategory(Some(ptr::NonNull::new_unchecked(ptr))) } } impl FromGlibPtrFull<*mut ffi::GstDebugCategory> for DebugCategory { #[inline] unsafe fn from_glib_full(ptr: *mut ffi::GstDebugCategory) -> Self { debug_assert!(!ptr.is_null()); DebugCategory(Some(ptr::NonNull::new_unchecked(ptr))) } } pub static CAT_RUST: Lazy = Lazy::new(|| { DebugCategory::new( "GST_RUST", crate::DebugColorFlags::UNDERLINE, Some("GStreamer's Rust binding core"), ) }); macro_rules! declare_debug_category_from_name( ($cat:ident, $cat_name:expr) => ( pub static $cat: Lazy = Lazy::new(|| DebugCategory::get($cat_name) .expect(&format!("Unable to find `DebugCategory` with name {}", $cat_name))); ); ); declare_debug_category_from_name!(CAT_DEFAULT, "default"); declare_debug_category_from_name!(CAT_GST_INIT, "GST_INIT"); declare_debug_category_from_name!(CAT_MEMORY, "GST_MEMORY"); declare_debug_category_from_name!(CAT_PARENTAGE, "GST_PARENTAGE"); declare_debug_category_from_name!(CAT_STATES, "GST_STATES"); declare_debug_category_from_name!(CAT_SCHEDULING, "GST_SCHEDULING"); declare_debug_category_from_name!(CAT_BUFFER, "GST_BUFFER"); declare_debug_category_from_name!(CAT_BUFFER_LIST, "GST_BUFFER_LIST"); declare_debug_category_from_name!(CAT_BUS, "GST_BUS"); declare_debug_category_from_name!(CAT_CAPS, "GST_CAPS"); declare_debug_category_from_name!(CAT_CLOCK, "GST_CLOCK"); declare_debug_category_from_name!(CAT_ELEMENT_PADS, "GST_ELEMENT_PADS"); declare_debug_category_from_name!(CAT_PADS, "GST_PADS"); declare_debug_category_from_name!(CAT_PERFORMANCE, "GST_PERFORMANCE"); declare_debug_category_from_name!(CAT_PIPELINE, "GST_PIPELINE"); declare_debug_category_from_name!(CAT_PLUGIN_LOADING, "GST_PLUGIN_LOADING"); declare_debug_category_from_name!(CAT_PLUGIN_INFO, "GST_PLUGIN_INFO"); declare_debug_category_from_name!(CAT_PROPERTIES, "GST_PROPERTIES"); declare_debug_category_from_name!(CAT_NEGOTIATION, "GST_NEGOTIATION"); declare_debug_category_from_name!(CAT_REFCOUNTING, "GST_REFCOUNTING"); declare_debug_category_from_name!(CAT_ERROR_SYSTEM, "GST_ERROR_SYSTEM"); declare_debug_category_from_name!(CAT_EVENT, "GST_EVENT"); declare_debug_category_from_name!(CAT_MESSAGE, "GST_MESSAGE"); declare_debug_category_from_name!(CAT_PARAMS, "GST_PARAMS"); declare_debug_category_from_name!(CAT_CALL_TRACE, "GST_CALL_TRACE"); declare_debug_category_from_name!(CAT_SIGNAL, "GST_SIGNAL"); declare_debug_category_from_name!(CAT_PROBE, "GST_PROBE"); declare_debug_category_from_name!(CAT_REGISTRY, "GST_REGISTRY"); declare_debug_category_from_name!(CAT_QOS, "GST_QOS"); declare_debug_category_from_name!(CAT_META, "GST_META"); declare_debug_category_from_name!(CAT_LOCKING, "GST_LOCKING"); declare_debug_category_from_name!(CAT_CONTEXT, "GST_CONTEXT"); #[macro_export] macro_rules! error( ($cat:expr, obj = $obj:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Error, obj = $obj, $($args)*) }}; ($cat:expr, imp = $imp:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Error, imp = $imp, $($args)*) }}; ($cat:expr, id = $id:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Error, id = $id, $($args)*) }}; ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"] macro_rules! error( () => {} ); error!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Error, obj = $obj, $($args)*) }}; ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"] macro_rules! error( () => {} ); error!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Error, imp = $imp, $($args)*) }}; ($cat:expr, id: $id:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"] macro_rules! error( () => {} ); error!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Error, id = $id, $($args)*) }}; ($cat:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Error, $($args)*) }}; ); #[macro_export] macro_rules! warning( ($cat:expr, obj = $obj:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Warning, obj = $obj, $($args)*) }}; ($cat:expr, imp = $imp:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Warning, imp = $imp, $($args)*) }}; ($cat:expr, id = $id:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Warning, id = $id, $($args)*) }}; ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"] macro_rules! warning( () => {} ); warning!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Warning, obj = $obj, $($args)*) }}; ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"] macro_rules! warning( () => {} ); warning!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Warning, imp = $imp, $($args)*) }}; ($cat:expr, id: $id:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"] macro_rules! warning( () => {} ); warning!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Warning, id = $id, $($args)*) }}; ($cat:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Warning, $($args)*) }}; ); #[macro_export] macro_rules! fixme( ($cat:expr, obj = $obj:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, obj = $obj, $($args)*) }}; ($cat:expr, imp = $imp:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, imp = $imp, $($args)*) }}; ($cat:expr, id = $id:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, id = $id, $($args)*) }}; ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"] macro_rules! fixme( () => {} ); fixme!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, obj = $obj, $($args)*) }}; ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"] macro_rules! fixme( () => {} ); fixme!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, imp = $imp, $($args)*) }}; ($cat:expr, id: $id:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"] macro_rules! fixme( () => {} ); fixme!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, id = $id, $($args)*) }}; ($cat:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Fixme, $($args)*) }}; ); #[macro_export] macro_rules! info( ($cat:expr, obj = $obj:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Info, obj = $obj, $($args)*) }}; ($cat:expr, imp = $imp:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Info, imp = $imp, $($args)*) }}; ($cat:expr, id = $id:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Info, id = $id, $($args)*) }}; ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"] macro_rules! info( () => {} ); info!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Info, obj = $obj, $($args)*) }}; ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"] macro_rules! info( () => {} ); info!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Info, imp = $imp, $($args)*) }}; ($cat:expr, id: $id:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"] macro_rules! info( () => {} ); info!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Info, id = $id, $($args)*) }}; ($cat:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Info, $($args)*) }}; ); #[macro_export] macro_rules! debug( ($cat:expr, obj = $obj:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Debug, obj = $obj, $($args)*) }}; ($cat:expr, imp = $imp:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Debug, imp = $imp, $($args)*) }}; ($cat:expr, id = $id:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Debug, id = $id, $($args)*) }}; ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"] macro_rules! debug( () => {} ); debug!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Debug, obj = $obj, $($args)*) }}; ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"] macro_rules! debug( () => {} ); debug!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Debug, imp = $imp, $($args)*) }}; ($cat:expr, id: $id:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"] macro_rules! debug( () => {} ); debug!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Debug, id = $id, $($args)*) }}; ($cat:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Debug, $($args)*) }}; ); #[macro_export] macro_rules! log( ($cat:expr, obj = $obj:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Log, obj = $obj, $($args)*) }}; ($cat:expr, imp = $imp:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Log, imp = $imp, $($args)*) }}; ($cat:expr, id = $id:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Log, id = $id, $($args)*) }}; ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"] macro_rules! log( () => {} ); log!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Log, obj = $obj, $($args)*) }}; ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"] macro_rules! log( () => {} ); log!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Log, imp = $imp, $($args)*) }}; ($cat:expr, id: $id:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"] macro_rules! log( () => {} ); log!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Log, id = $id, $($args)*) }}; ($cat:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Log, $($args)*) }}; ); #[macro_export] macro_rules! trace( ($cat:expr, obj = $obj:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Trace, obj = $obj, $($args)*) }}; ($cat:expr, imp = $imp:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Trace, imp = $imp, $($args)*) }}; ($cat:expr, id = $id:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Trace, id = $id, $($args)*) }}; ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"] macro_rules! trace( () => {} ); trace!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Trace, obj = $obj, $($args)*) }}; ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"] macro_rules! trace( () => {} ); trace!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Trace, imp = $imp, $($args)*) }}; ($cat:expr, id: $id:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style id format. Use `id = ` instead of `id: `"] macro_rules! trace( () => {} ); trace!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Trace, id = $id, $($args)*) }}; ($cat:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Trace, $($args)*) }}; ); #[macro_export] macro_rules! memdump( ($cat:expr, obj = $obj:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, obj = $obj, $($args)*) }}; ($cat:expr, imp = $imp:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, imp = $imp, $($args)*) }}; ($cat:expr, id = $id:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, id = $id, $($args)*) }}; ($cat:expr, obj: $obj:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style obj format. Use `obj = ` instead of `obj: ` for better tooling support"] macro_rules! memdump( () => {} ); memdump!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, obj = $obj, $($args)*) }}; ($cat:expr, imp: $imp:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style imp format. Use `imp = ` instead of `imp: ` for better tooling support"] macro_rules! memdump( () => {} ); memdump!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, imp = $imp, $($args)*) }}; ($cat:expr, id: $id:expr, $($args:tt)*) => { { { #[deprecated = "Using old-style id format. Use `id = ` instead of `id: ` for better tooling support"] macro_rules! memdump( () => {} ); memdump!(); } $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, id = $id, $($args)*) }}; ($cat:expr, $($args:tt)*) => { { $crate::log_with_level!($cat, $crate::DebugLevel::Memdump, $($args)*) }}; ); #[macro_export] macro_rules! log_with_level( ($cat:expr, $level:expr, obj = $obj:expr, $msg:literal) => { { let cat = $cat.clone(); // Check the log level before using `format_args!` otherwise // formatted arguments are evaluated even if we end up not logging. #[allow(unused_unsafe)] #[allow(clippy::redundant_closure_call)] if cat.above_threshold($level) { use $crate::glib::prelude::Cast; // FIXME: Once there's a function_name! macro that returns a string literal we can // directly pass it as `&GStr` forward let obj = &$obj; let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() }; let function_name = $crate::glib::function_name!(); // Check if formatting is necessary or not // FIXME: This needs to be a closure because the return value of format_args!() can't // be assigned to a variable (|args: std::fmt::Arguments| { if args.as_str().is_some() { $crate::DebugCategory::log_literal_unfiltered( cat, Some(obj), $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, function_name, line!(), $crate::glib::gstr!($msg), ) } else { $crate::DebugCategory::log_unfiltered( cat, Some(obj), $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, function_name, line!(), args, ) } })(format_args!($msg)) } }}; ($cat:expr, $level:expr, obj = $obj:expr, $($args:tt)*) => { { let cat = $cat.clone(); // Check the log level before using `format_args!` otherwise // formatted arguments are evaluated even if we end up not logging. #[allow(unused_unsafe)] if cat.above_threshold($level) { use $crate::glib::prelude::Cast; // FIXME: Once there's a function_name! macro that returns a string literal we can // directly pass it as `&GStr` forward let obj = &$obj; let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() }; $crate::DebugCategory::log_unfiltered( cat, Some(obj), $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, $crate::glib::function_name!(), line!(), format_args!($($args)*), ) } }}; ($cat:expr, $level:expr, imp = $imp:expr, $msg:literal) => { { let cat = $cat.clone(); // Check the log level before using `format_args!` otherwise // formatted arguments are evaluated even if we end up not logging. #[allow(unused_unsafe)] #[allow(clippy::redundant_closure_call)] if cat.above_threshold($level) { use $crate::glib::prelude::Cast; // FIXME: Once there's a function_name! macro that returns a string literal we can // directly pass it as `&GStr` forward let obj = $imp.obj(); let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() }; let function_name = $crate::glib::function_name!(); // Check if formatting is necessary or not // FIXME: This needs to be a closure because the return value of format_args!() can't // be assigned to a variable (|args: std::fmt::Arguments| { if args.as_str().is_some() { $crate::DebugCategory::log_literal_unfiltered( cat, Some(obj), $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, function_name, line!(), $crate::glib::gstr!($msg), ) } else { $crate::DebugCategory::log_unfiltered( cat, Some(obj), $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, function_name, line!(), args, ) } })(format_args!($msg)) } }}; ($cat:expr, $level:expr, imp = $imp:expr, $($args:tt)*) => { { let cat = $cat.clone(); // Check the log level before using `format_args!` otherwise // formatted arguments are evaluated even if we end up not logging. #[allow(unused_unsafe)] if cat.above_threshold($level) { use $crate::glib::prelude::Cast; // FIXME: Once there's a function_name! macro that returns a string literal we can // directly pass it as `&GStr` forward let obj = $imp.obj(); let obj = unsafe { obj.unsafe_cast_ref::<$crate::glib::Object>() }; $crate::DebugCategory::log_unfiltered( cat, Some(obj), $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, $crate::glib::function_name!(), line!(), format_args!($($args)*), ) } }}; ($cat:expr, $level:expr, id = $id:literal, $msg:literal) => { { let cat = $cat.clone(); // Check the log level before using `format_args!` otherwise // formatted arguments are evaluated even if we end up not logging. #[allow(unused_unsafe)] #[allow(clippy::redundant_closure_call)] if cat.above_threshold($level) { // FIXME: Once there's a function_name! macro that returns a string literal we can // directly pass it as `&GStr` forward let function_name = $crate::glib::function_name!(); // Check if formatting is necessary or not // FIXME: This needs to be a closure because the return value of format_args!() can't // be assigned to a variable (|args: std::fmt::Arguments| { if args.as_str().is_some() { $crate::DebugCategory::log_id_literal_unfiltered( cat, $crate::glib::gstr!($id), $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, function_name, line!(), $crate::glib::gstr!($msg), ) } else { $crate::DebugCategory::log_id_unfiltered( cat, $crate::glib::gstr!($id), $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, function_name, line!(), args, ) } })(format_args!($msg)) } }}; ($cat:expr, $level:expr, id = $id:literal, $($args:tt)*) => { { let cat = $cat.clone(); // Check the log level before using `format_args!` otherwise // formatted arguments are evaluated even if we end up not logging. #[allow(unused_unsafe)] if cat.above_threshold($level) { // FIXME: Once there's a function_name! macro that returns a string literal we can // directly pass it as `&GStr` forward $crate::DebugCategory::log_id_unfiltered( cat, $crate::glib::gstr!($id), $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, $crate::glib::function_name!(), line!(), format_args!($($args)*), ) } }}; ($cat:expr, $level:expr, id = $id:expr, $msg:literal) => { { let cat = $cat.clone(); // Check the log level before using `format_args!` otherwise // formatted arguments are evaluated even if we end up not logging. #[allow(unused_unsafe)] #[allow(clippy::redundant_closure_call)] if cat.above_threshold($level) { // FIXME: Once there's a function_name! macro that returns a string literal we can // directly pass it as `&GStr` forward let function_name = $crate::glib::function_name!(); // Check if formatting is necessary or not // FIXME: This needs to be a closure because the return value of format_args!() can't // be assigned to a variable (|args: std::fmt::Arguments| { if args.as_str().is_some() { $crate::DebugCategory::log_id_literal_unfiltered( cat, $id, $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, function_name, line!(), $crate::glib::gstr!($msg), ) } else { $crate::DebugCategory::log_id_unfiltered( cat, $id, $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, function_name, line!(), args, ) } })(format_args!($msg)) } }}; ($cat:expr, $level:expr, id = $id:expr, $($args:tt)*) => { { let cat = $cat.clone(); // Check the log level before using `format_args!` otherwise // formatted arguments are evaluated even if we end up not logging. #[allow(unused_unsafe)] if cat.above_threshold($level) { // FIXME: Once there's a function_name! macro that returns a string literal we can // directly pass it as `&GStr` forward $crate::DebugCategory::log_id_unfiltered( cat, $id, $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, $crate::glib::function_name!(), line!(), format_args!($($args)*), ) } }}; ($cat:expr, $level:expr, $msg:literal) => { { let cat = $cat.clone(); // Check the log level before using `format_args!` otherwise // formatted arguments are evaluated even if we end up not logging. #[allow(unused_unsafe)] #[allow(clippy::redundant_closure_call)] if cat.above_threshold($level) { // FIXME: Once there's a function_name! macro that returns a string literal we can // directly pass it as `&GStr` forward let function_name = $crate::glib::function_name!(); // Check if formatting is necessary or not // FIXME: This needs to be a closure because the return value of format_args!() can't // be assigned to a variable (|args: std::fmt::Arguments| { if args.as_str().is_some() { $crate::DebugCategory::log_literal_unfiltered( cat, None as Option<&$crate::glib::Object>, $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, function_name, line!(), $crate::glib::gstr!($msg), ) } else { $crate::DebugCategory::log_unfiltered( cat, None as Option<&$crate::glib::Object>, $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, function_name, line!(), args, ) } })(format_args!($msg)) } }}; ($cat:expr, $level:expr, $($args:tt)*) => { { let cat = $cat.clone(); // Check the log level before using `format_args!` otherwise // formatted arguments are evaluated even if we end up not logging. #[allow(unused_unsafe)] if cat.above_threshold($level) { // FIXME: Once there's a function_name! macro that returns a string literal we can // directly pass it as `&GStr` forward $crate::DebugCategory::log_unfiltered( cat, None as Option<&$crate::glib::Object>, $level, unsafe { $crate::glib::GStr::from_utf8_with_nul_unchecked(concat!(file!(), "\0").as_bytes()) }, $crate::glib::function_name!(), line!(), format_args!($($args)*), ) } }}; ); #[cfg(feature = "log")] #[cfg_attr(docsrs, doc(cfg(feature = "log")))] #[derive(Debug)] pub struct DebugCategoryLogger(DebugCategory); #[cfg(feature = "log")] #[cfg_attr(docsrs, doc(cfg(feature = "log")))] impl DebugCategoryLogger { pub fn new(cat: DebugCategory) -> Self { skip_assert_initialized!(); Self(cat) } fn to_level(level: log::Level) -> crate::DebugLevel { skip_assert_initialized!(); match level { log::Level::Error => DebugLevel::Error, log::Level::Warn => DebugLevel::Warning, log::Level::Info => DebugLevel::Info, log::Level::Debug => DebugLevel::Debug, log::Level::Trace => DebugLevel::Trace, } } } #[cfg(feature = "log")] #[cfg_attr(docsrs, doc(cfg(feature = "log")))] impl log::Log for DebugCategoryLogger { fn enabled(&self, metadata: &log::Metadata) -> bool { self.0.above_threshold(Self::to_level(metadata.level())) } fn log(&self, record: &log::Record) { if !self.enabled(record.metadata()) { return; } record.file().unwrap_or("").run_with_gstr(|file| { self.0.log( None::<&glib::Object>, Self::to_level(record.level()), file, record.module_path().unwrap_or(""), record.line().unwrap_or(0), *record.args(), ); }); } fn flush(&self) {} } unsafe extern "C" fn log_handler( category: *mut ffi::GstDebugCategory, level: ffi::GstDebugLevel, file: *const c_char, function: *const c_char, line: i32, object: *mut glib::gobject_ffi::GObject, message: *mut ffi::GstDebugMessage, user_data: gpointer, ) where T: Fn( DebugCategory, DebugLevel, &glib::GStr, &glib::GStr, u32, Option<&LoggedObject>, &DebugMessage, ) + Send + Sync + 'static, { if category.is_null() { return; } let category = DebugCategory(Some(ptr::NonNull::new_unchecked(category))); let level = from_glib(level); let file = glib::GStr::from_ptr(file); let function = glib::GStr::from_ptr(function); let line = line as u32; let object = ptr::NonNull::new(object).map(LoggedObject); let message = DebugMessage(ptr::NonNull::new_unchecked(message)); let handler = &*(user_data as *mut T); (handler)( category, level, file, function, line, object.as_ref(), &message, ); } unsafe extern "C" fn log_handler_data_free(data: gpointer) { let data = Box::from_raw(data as *mut T); drop(data); } #[derive(Debug)] pub struct DebugLogFunction(ptr::NonNull); // The contained pointer is never dereferenced and has no thread affinity. // It may be convenient to send it or share it between threads to allow cleaning // up log functions from other threads than the one that created it. unsafe impl Send for DebugLogFunction {} unsafe impl Sync for DebugLogFunction {} #[derive(Debug)] #[doc(alias = "GObject")] pub struct LoggedObject(ptr::NonNull); impl LoggedObject { #[inline] pub fn as_ptr(&self) -> *mut glib::gobject_ffi::GObject { self.0.as_ptr() } } impl fmt::Display for LoggedObject { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { unsafe { let ptr = self.0.as_ptr(); let g_type_instance = &mut (*ptr).g_type_instance; if glib::gobject_ffi::g_type_check_instance_is_fundamentally_a( g_type_instance, glib::gobject_ffi::g_object_get_type(), ) != glib::ffi::GFALSE { let type_ = (*g_type_instance.g_class).g_type; if glib::gobject_ffi::g_type_is_a(type_, ffi::gst_pad_get_type()) != glib::ffi::GFALSE { let name_ptr = (*(ptr as *mut ffi::GstObject)).name; let name = if name_ptr.is_null() { "" } else { CStr::from_ptr(name_ptr) .to_str() .unwrap_or("") }; let parent_ptr = (*(ptr as *mut ffi::GstObject)).parent; let parent_name = if parent_ptr.is_null() { "" } else { let name_ptr = (*(parent_ptr)).name; if name_ptr.is_null() { "" } else { CStr::from_ptr(name_ptr) .to_str() .unwrap_or("") } }; write!(f, "{parent_name}:{name}") } else if glib::gobject_ffi::g_type_is_a(type_, ffi::gst_object_get_type()) != glib::ffi::GFALSE { let name_ptr = (*(ptr as *mut ffi::GstObject)).name; let name = if name_ptr.is_null() { "" } else { CStr::from_ptr(name_ptr) .to_str() .unwrap_or("") }; write!(f, "{name}") } else { let type_name = CStr::from_ptr(glib::gobject_ffi::g_type_name(type_)); write!( f, "{}:{:?}", type_name.to_str().unwrap_or(""), ptr ) } } else { write!(f, "{ptr:?}") } } } } #[doc(alias = "gst_debug_add_log_function")] pub fn add_log_function(function: T) -> DebugLogFunction where T: Fn( DebugCategory, DebugLevel, &glib::GStr, &glib::GStr, u32, Option<&LoggedObject>, &DebugMessage, ) + Send + Sync + 'static, { skip_assert_initialized!(); unsafe { let user_data = Box::new(function); let user_data_ptr = Box::into_raw(user_data) as gpointer; ffi::gst_debug_add_log_function( Some(log_handler::), user_data_ptr, Some(log_handler_data_free::), ); DebugLogFunction(ptr::NonNull::new_unchecked(user_data_ptr)) } } pub fn remove_default_log_function() { skip_assert_initialized!(); unsafe { ffi::gst_debug_remove_log_function(None); } } #[doc(alias = "gst_debug_remove_log_function_by_data")] pub fn remove_log_function(log_fn: DebugLogFunction) { skip_assert_initialized!(); unsafe { ffi::gst_debug_remove_log_function_by_data(log_fn.0.as_ptr()); } } #[cfg(test)] mod tests { use std::sync::{mpsc, Arc, Mutex}; use super::*; #[test] #[doc(alias = "get_existing")] fn existing() { crate::init().unwrap(); let perf_cat = DebugCategory::get("GST_PERFORMANCE") .expect("Unable to find `DebugCategory` with name \"GST_PERFORMANCE\""); assert_eq!(perf_cat.name(), CAT_PERFORMANCE.name()); } #[test] fn all() { crate::init().unwrap(); assert!(DebugCategory::all_categories() .iter() .any(|c| c.name() == "GST_PERFORMANCE")); } #[test] fn new_and_log() { crate::init().unwrap(); let cat = DebugCategory::new( "test-cat", crate::DebugColorFlags::empty(), Some("some debug category"), ); error!(cat, "meh"); warning!(cat, "meh"); fixme!(cat, "meh"); info!(cat, "meh"); debug!(cat, "meh"); log!(cat, "meh"); trace!(cat, "meh"); memdump!(cat, "meh"); let obj = crate::Bin::with_name("meh"); error!(cat, obj = &obj, "meh"); warning!(cat, obj = &obj, "meh"); fixme!(cat, obj = &obj, "meh"); info!(cat, obj = &obj, "meh"); debug!(cat, obj = &obj, "meh"); log!(cat, obj = &obj, "meh"); trace!(cat, obj = &obj, "meh"); memdump!(cat, obj = &obj, "meh"); error!(cat, obj = obj, "meh"); warning!(cat, obj = obj, "meh"); fixme!(cat, obj = obj, "meh"); info!(cat, obj = obj, "meh"); debug!(cat, obj = obj, "meh"); log!(cat, obj = obj, "meh"); trace!(cat, obj = obj, "meh"); memdump!(cat, obj = obj, "meh"); } #[cfg(feature = "log")] static LOGGER: Lazy = Lazy::new(|| { DebugCategoryLogger::new(DebugCategory::new( "Log_trait", crate::DebugColorFlags::empty(), Some("Using the Log trait"), )) }); #[test] #[cfg(feature = "log")] fn log_trait() { crate::init().unwrap(); log::set_logger(&(*LOGGER)).expect("Failed to set logger"); log::set_max_level(log::LevelFilter::Trace); log::error!("meh"); log::warn!("fish"); let (sender, receiver) = mpsc::channel(); let sender = Arc::new(Mutex::new(sender)); let handler = move |category: DebugCategory, level: DebugLevel, _file: &glib::GStr, _function: &glib::GStr, _line: u32, _object: Option<&LoggedObject>, message: &DebugMessage| { let cat = DebugCategory::get("Log_trait").unwrap(); if category != cat { // This test can run in parallel with other tests, including new_and_log above. // We cannot be certain we only see our own messages. return; } assert_eq!(level, DebugLevel::Error); assert_eq!(message.get().unwrap().as_ref(), "meh"); let _ = sender.lock().unwrap().send(()); }; remove_default_log_function(); add_log_function(handler); let cat = LOGGER.0; cat.set_threshold(crate::DebugLevel::Warning); log::error!("meh"); receiver.recv().unwrap(); cat.set_threshold(crate::DebugLevel::Error); log::error!("meh"); receiver.recv().unwrap(); cat.set_threshold(crate::DebugLevel::None); log::error!("fish"); log::warn!("meh"); } #[test] fn log_handler() { crate::init().unwrap(); let cat = DebugCategory::new( "test-cat-log", crate::DebugColorFlags::empty(), Some("some debug category"), ); cat.set_threshold(DebugLevel::Info); let obj = crate::Bin::with_name("meh"); let (sender, receiver) = mpsc::channel(); let sender = Arc::new(Mutex::new(sender)); let handler = move |category: DebugCategory, level: DebugLevel, _file: &glib::GStr, _function: &glib::GStr, _line: u32, _object: Option<&LoggedObject>, message: &DebugMessage| { let cat = DebugCategory::get("test-cat-log").unwrap(); if category != cat { // This test can run in parallel with other tests, including new_and_log above. // We cannot be certain we only see our own messages. return; } assert_eq!(level, DebugLevel::Info); assert_eq!(message.get().unwrap().as_ref(), "meh"); let _ = sender.lock().unwrap().send(()); }; remove_default_log_function(); let log_fn = add_log_function(handler); info!(cat, obj = &obj, "meh"); receiver.recv().unwrap(); remove_log_function(log_fn); info!(cat, obj = &obj, "meh2"); assert!(receiver.recv().is_err()); } #[test] fn no_argument_evaluation() { crate::init().unwrap(); let cat = DebugCategory::new( "no_argument_evaluation", crate::DebugColorFlags::empty(), Some("No Argument Evaluation debug category"), ); let mut arg_evaluated = false; trace!(cat, "{}", { arg_evaluated = true; "trace log" }); assert!(!arg_evaluated); } #[cfg(feature = "v1_22")] #[test] fn id_logging() { crate::init().unwrap(); let cat = DebugCategory::new( "log_with_id_test_category", crate::DebugColorFlags::empty(), Some("Blablabla"), ); cat.set_threshold(crate::DebugLevel::Trace); trace!(cat, id = "123", "test"); trace!(cat, id = glib::GString::from("123"), "test"); trace!(cat, id = &glib::GString::from("123"), "test"); // Try with a formatted string too (which is a different code path in the bindings) let log_id = glib::GString::from("456"); trace!(cat, id = &log_id, "{log_id:?}"); } } gstreamer-0.23.5/src/macos.rs000064400000000000000000000020041046102023000141370ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. type GstMainFuncSimple = Option; extern "C" { #[cfg(feature = "v1_22")] fn gst_macos_main_simple(func: GstMainFuncSimple, user_data: glib::ffi::gpointer); } #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] #[doc(alias = "gst_macos_main")] pub fn macos_main(func: F) -> T where F: FnOnce() -> T + Send, { skip_assert_initialized!(); unsafe extern "C" fn trampoline T + Send>(user_data: glib::ffi::gpointer) { let data = &mut *(user_data as *mut (Option, Option)); let func = data.0.take().unwrap(); let res = func(); data.1 = Some(res); } let mut func: (Option, Option) = (Some(func), None); unsafe { gst_macos_main_simple( Some(trampoline::), &mut func as *mut (Option, Option) as *mut _, ); } func.1.unwrap() } gstreamer-0.23.5/src/memory.rs000064400000000000000000000777221046102023000143700ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ fmt, marker::PhantomData, mem, ops::{Bound, Deref, DerefMut, RangeBounds}, ptr, slice, }; use glib::translate::*; use crate::{ffi, AllocationParams, Allocator, MemoryFlags}; mini_object_wrapper!(Memory, MemoryRef, ffi::GstMemory, || { ffi::gst_memory_get_type() }); pub struct MemoryMap<'a, T> { memory: &'a MemoryRef, map_info: ffi::GstMapInfo, phantom: PhantomData, } pub struct MappedMemory { memory: Memory, map_info: ffi::GstMapInfo, phantom: PhantomData, } impl fmt::Debug for Memory { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { MemoryRef::fmt(self, f) } } impl fmt::Debug for MemoryRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Memory") .field("ptr", &self.as_ptr()) .field("allocator", &self.allocator()) .field("parent", &self.parent()) .field("maxsize", &self.maxsize()) .field("align", &self.align()) .field("offset", &self.offset()) .field("size", &self.size()) .field("flags", &self.flags()) .finish() } } pub enum Readable {} pub enum Writable {} impl Memory { #[inline] pub fn with_size(size: usize) -> Self { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_allocator_alloc( ptr::null_mut(), size, ptr::null_mut(), )) } } #[inline] pub fn with_size_and_params(size: usize, params: &AllocationParams) -> Self { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_allocator_alloc( ptr::null_mut(), size, params.as_ptr() as *mut _, )) } } #[inline] pub fn into_mapped_memory_readable(self) -> Result, Self> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res: bool = from_glib(ffi::gst_memory_map( self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READ, )); if res { Ok(MappedMemory { memory: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(self) } } } #[inline] pub fn into_mapped_memory_writable(self) -> Result, Self> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res: bool = from_glib(ffi::gst_memory_map( self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READWRITE, )); if res { Ok(MappedMemory { memory: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(self) } } } } impl MemoryRef { #[doc(alias = "get_allocator")] #[inline] pub fn allocator(&self) -> Option<&Allocator> { unsafe { if self.0.allocator.is_null() { None } else { Some(&*(&self.0.allocator as *const *mut ffi::GstAllocator as *const Allocator)) } } } #[doc(alias = "get_parent")] #[inline] pub fn parent(&self) -> Option<&MemoryRef> { unsafe { if self.0.parent.is_null() { None } else { Some(MemoryRef::from_ptr(self.0.parent)) } } } #[doc(alias = "get_maxsize")] #[inline] pub fn maxsize(&self) -> usize { self.0.maxsize } #[doc(alias = "get_align")] #[inline] pub fn align(&self) -> usize { self.0.align } #[doc(alias = "get_offset")] #[inline] pub fn offset(&self) -> usize { self.0.offset } #[doc(alias = "get_size")] #[inline] pub fn size(&self) -> usize { self.0.size } #[doc(alias = "get_flags")] #[inline] pub fn flags(&self) -> MemoryFlags { unsafe { from_glib(self.0.mini_object.flags) } } fn calculate_offset_size(&self, range: impl RangeBounds) -> (isize, isize) { let size = self.size(); let start_offset = match range.start_bound() { Bound::Included(v) => *v, Bound::Excluded(v) => v.checked_add(1).expect("Invalid start offset"), Bound::Unbounded => 0, }; assert!(start_offset < size, "Start offset after valid range"); let end_offset = match range.end_bound() { Bound::Included(v) => v.checked_add(1).expect("Invalid end offset"), Bound::Excluded(v) => *v, Bound::Unbounded => size, }; assert!(end_offset <= size, "End offset after valid range"); // Cast from usize to isize because that's literally how this works in the // implementation and how the upper half of the usize range can be made use of. // // The implementation works exploiting wraparounds. let new_offset = start_offset as isize; let new_size = end_offset.saturating_sub(start_offset) as isize; (new_offset, new_size) } fn calculate_offset_size_maxsize(&self, range: impl RangeBounds) -> (isize, isize) { let maxsize = self.maxsize(); let start_offset = match range.start_bound() { Bound::Included(v) => *v, Bound::Excluded(v) => v.checked_add(1).expect("Invalid start offset"), Bound::Unbounded => 0, }; assert!(start_offset < maxsize, "Start offset after valid range"); let end_offset = match range.end_bound() { Bound::Included(v) => v.checked_add(1).expect("Invalid end offset"), Bound::Excluded(v) => *v, Bound::Unbounded => maxsize, }; assert!(end_offset <= maxsize, "End offset after valid range"); // Cast from usize to isize because that's literally how this works in the // implementation and how the upper half of the usize range can be made use of. // // The implementation works by exploiting wraparounds. let offset = self.offset(); let new_offset = start_offset.wrapping_sub(offset) as isize; let new_size = end_offset.saturating_sub(start_offset) as isize; (new_offset, new_size) } #[doc(alias = "gst_memory_copy")] pub fn copy_range(&self, range: impl RangeBounds) -> Memory { let (offset, size) = self.calculate_offset_size(range); unsafe { from_glib_full(ffi::gst_memory_copy(self.as_mut_ptr(), offset, size)) } } #[doc(alias = "gst_memory_copy")] pub fn copy_range_maxsize(&self, range: impl RangeBounds) -> Memory { let (offset, size) = self.calculate_offset_size_maxsize(range); unsafe { from_glib_full(ffi::gst_memory_copy(self.as_mut_ptr(), offset, size)) } } #[doc(alias = "gst_memory_is_span")] pub fn is_span(&self, mem2: &MemoryRef) -> Option { unsafe { let mut offset = mem::MaybeUninit::uninit(); let res = from_glib(ffi::gst_memory_is_span( self.as_mut_ptr(), mem2.as_mut_ptr(), offset.as_mut_ptr(), )); if res { Some(offset.assume_init()) } else { None } } } #[doc(alias = "gst_memory_is_type")] pub fn is_type(&self, mem_type: &str) -> bool { unsafe { from_glib(ffi::gst_memory_is_type( self.as_mut_ptr(), mem_type.to_glib_none().0, )) } } #[inline] pub fn map_readable(&self) -> Result, glib::BoolError> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res = ffi::gst_memory_map(self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READ); if res == glib::ffi::GTRUE { Ok(MemoryMap { memory: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(glib::bool_error!("Failed to map memory readable")) } } } #[inline] pub fn map_writable(&mut self) -> Result, glib::BoolError> { unsafe { let mut map_info = mem::MaybeUninit::uninit(); let res = ffi::gst_memory_map( self.as_mut_ptr(), map_info.as_mut_ptr(), ffi::GST_MAP_READWRITE, ); if res == glib::ffi::GTRUE { Ok(MemoryMap { memory: self, map_info: map_info.assume_init(), phantom: PhantomData, }) } else { Err(glib::bool_error!("Failed to map memory writable")) } } } #[doc(alias = "gst_memory_share")] pub fn share(&self, range: impl RangeBounds) -> Memory { let (offset, size) = self.calculate_offset_size(range); unsafe { from_glib_full(ffi::gst_memory_share(self.as_ptr() as *mut _, offset, size)) } } #[doc(alias = "gst_memory_share")] pub fn share_maxsize(&self, range: impl RangeBounds) -> Memory { let (offset, size) = self.calculate_offset_size_maxsize(range); unsafe { from_glib_full(ffi::gst_memory_share(self.as_ptr() as *mut _, offset, size)) } } #[doc(alias = "gst_memory_resize")] pub fn resize(&mut self, range: impl RangeBounds) { let (offset, size) = self.calculate_offset_size(range); unsafe { ffi::gst_memory_resize(self.as_mut_ptr(), offset, size as usize) } } #[doc(alias = "gst_memory_resize")] pub fn resize_maxsize(&mut self, range: impl RangeBounds) { let (offset, size) = self.calculate_offset_size_maxsize(range); unsafe { ffi::gst_memory_resize(self.as_mut_ptr(), offset, size as usize) } } #[doc(alias = "gst_util_dump_mem")] pub fn dump(&self) -> Dump { Dump { memory: self, start: Bound::Unbounded, end: Bound::Unbounded, } } #[doc(alias = "gst_util_dump_mem")] pub fn dump_range(&self, range: impl RangeBounds) -> Dump { Dump { memory: self, start: range.start_bound().cloned(), end: range.end_bound().cloned(), } } } impl MemoryMap<'_, T> { #[doc(alias = "get_size")] #[inline] pub fn size(&self) -> usize { self.map_info.size } #[doc(alias = "get_memory")] #[inline] pub fn memory(&self) -> &MemoryRef { self.memory } #[inline] pub fn as_slice(&self) -> &[u8] { if self.map_info.size == 0 { return &[]; } unsafe { slice::from_raw_parts(self.map_info.data, self.map_info.size) } } } impl MemoryMap<'_, Writable> { #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { if self.map_info.size == 0 { return &mut []; } unsafe { slice::from_raw_parts_mut(self.map_info.data, self.map_info.size) } } } impl AsRef<[u8]> for MemoryMap<'_, T> { #[inline] fn as_ref(&self) -> &[u8] { self.as_slice() } } impl AsMut<[u8]> for MemoryMap<'_, Writable> { #[inline] fn as_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl Deref for MemoryMap<'_, T> { type Target = [u8]; #[inline] fn deref(&self) -> &[u8] { self.as_slice() } } impl DerefMut for MemoryMap<'_, Writable> { #[inline] fn deref_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl fmt::Debug for MemoryMap<'_, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("MemoryMap").field(&self.memory()).finish() } } impl<'a, T> PartialEq for MemoryMap<'a, T> { fn eq(&self, other: &MemoryMap<'a, T>) -> bool { self.as_slice().eq(other.as_slice()) } } impl Eq for MemoryMap<'_, T> {} impl Drop for MemoryMap<'_, T> { #[inline] fn drop(&mut self) { unsafe { ffi::gst_memory_unmap(self.memory.as_mut_ptr(), &mut self.map_info); } } } unsafe impl Send for MemoryMap<'_, T> {} unsafe impl Sync for MemoryMap<'_, T> {} impl MappedMemory { #[inline] pub fn as_slice(&self) -> &[u8] { if self.map_info.size == 0 { return &[]; } unsafe { slice::from_raw_parts(self.map_info.data, self.map_info.size) } } #[doc(alias = "get_size")] #[inline] pub fn size(&self) -> usize { self.map_info.size } #[doc(alias = "get_memory")] #[inline] pub fn memory(&self) -> &MemoryRef { self.memory.as_ref() } #[inline] pub fn into_memory(self) -> Memory { let mut s = mem::ManuallyDrop::new(self); let memory = unsafe { ptr::read(&s.memory) }; unsafe { ffi::gst_memory_unmap(memory.as_mut_ptr(), &mut s.map_info); } memory } } impl MappedMemory { #[inline] pub fn as_mut_slice(&mut self) -> &mut [u8] { if self.map_info.size == 0 { return &mut []; } unsafe { slice::from_raw_parts_mut(self.map_info.data, self.map_info.size) } } } impl AsRef<[u8]> for MappedMemory { #[inline] fn as_ref(&self) -> &[u8] { self.as_slice() } } impl AsMut<[u8]> for MappedMemory { #[inline] fn as_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl Deref for MappedMemory { type Target = [u8]; #[inline] fn deref(&self) -> &[u8] { self.as_slice() } } impl DerefMut for MappedMemory { #[inline] fn deref_mut(&mut self) -> &mut [u8] { self.as_mut_slice() } } impl Drop for MappedMemory { #[inline] fn drop(&mut self) { unsafe { ffi::gst_memory_unmap(self.memory.as_mut_ptr(), &mut self.map_info); } } } impl fmt::Debug for MappedMemory { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("MappedMemory").field(&self.memory()).finish() } } impl PartialEq for MappedMemory { fn eq(&self, other: &MappedMemory) -> bool { self.as_slice().eq(other.as_slice()) } } impl Eq for MappedMemory {} unsafe impl Send for MappedMemory {} unsafe impl Sync for MappedMemory {} pub struct Dump<'a> { memory: &'a MemoryRef, start: Bound, end: Bound, } impl Dump<'_> { fn fmt(&self, f: &mut fmt::Formatter, debug: bool) -> fmt::Result { let map = self.memory.map_readable().expect("Failed to map memory"); let data = map.as_slice(); let dump = crate::slice::Dump { data, start: self.start, end: self.end, }; if debug { ::fmt(&dump, f) } else { ::fmt(&dump, f) } } } impl fmt::Display for Dump<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.fmt(f, false) } } impl fmt::Debug for Dump<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt(f, true) } } pub unsafe trait MemoryType: crate::prelude::IsMiniObject + AsRef where ::RefType: AsRef + AsMut, { fn check_memory_type(mem: &MemoryRef) -> bool; } #[derive(Debug, thiserror::Error)] pub enum MemoryTypeMismatchError { #[error(transparent)] ValueTypeMismatch(#[from] glib::value::ValueTypeMismatchError), #[error("the memory is not of the requested type {requested}")] MemoryTypeMismatch { requested: &'static str }, } pub struct MemoryTypeValueTypeChecker(PhantomData); unsafe impl glib::value::ValueTypeChecker for MemoryTypeValueTypeChecker where M: MemoryType + glib::prelude::StaticType, ::RefType: AsRef + AsMut, { type Error = glib::value::ValueTypeMismatchOrNoneError; fn check(value: &glib::Value) -> Result<(), Self::Error> { skip_assert_initialized!(); let mem = value.get::<&Memory>().map_err(|err| match err { glib::value::ValueTypeMismatchOrNoneError::UnexpectedNone => { glib::value::ValueTypeMismatchOrNoneError::UnexpectedNone } glib::value::ValueTypeMismatchOrNoneError::WrongValueType(err) => { glib::value::ValueTypeMismatchOrNoneError::WrongValueType( MemoryTypeMismatchError::ValueTypeMismatch(err), ) } })?; if mem.is_memory_type::() { Ok(()) } else { Err(glib::value::ValueTypeMismatchOrNoneError::WrongValueType( MemoryTypeMismatchError::MemoryTypeMismatch { requested: std::any::type_name::(), }, )) } } } impl AsRef for MemoryRef { #[inline] fn as_ref(&self) -> &MemoryRef { self } } impl AsMut for MemoryRef { #[inline] fn as_mut(&mut self) -> &mut MemoryRef { self } } impl AsRef for Memory { #[inline] fn as_ref(&self) -> &Memory { self } } unsafe impl MemoryType for Memory { #[inline] fn check_memory_type(_mem: &MemoryRef) -> bool { skip_assert_initialized!(); true } } impl Memory { #[inline] pub fn downcast_memory(self) -> Result where ::RefType: AsRef + AsMut, { if M::check_memory_type(&self) { unsafe { Ok(from_glib_full(self.into_glib_ptr() as *mut M::FfiType)) } } else { Err(self) } } } impl MemoryRef { #[inline] pub fn is_memory_type(&self) -> bool where ::RefType: AsRef + AsMut, { M::check_memory_type(self) } #[inline] pub fn downcast_memory_ref(&self) -> Option<&M::RefType> where ::RefType: AsRef + AsMut, { if M::check_memory_type(self) { unsafe { Some(&*(self as *const Self as *const M::RefType)) } } else { None } } #[inline] pub fn downcast_memory_mut(&mut self) -> Option<&mut M::RefType> where ::RefType: AsRef + AsMut, { if M::check_memory_type(self) { unsafe { Some(&mut *(self as *mut Self as *mut M::RefType)) } } else { None } } } #[macro_export] macro_rules! memory_object_wrapper { ($name:ident, $ref_name:ident, $ffi_name:path, $mem_type_check:expr, $parent_memory_type:path, $parent_memory_ref_type:path) => { $crate::mini_object_wrapper!($name, $ref_name, $ffi_name); unsafe impl $crate::memory::MemoryType for $name { #[inline] fn check_memory_type(mem: &$crate::MemoryRef) -> bool { skip_assert_initialized!(); $mem_type_check(mem) } } impl $name { #[inline] pub fn downcast_memory(self) -> Result where ::RefType: AsRef<$crate::MemoryRef> + AsMut<$crate::MemoryRef> + AsRef<$ref_name> + AsMut<$ref_name>, { if M::check_memory_type(&self) { unsafe { Ok($crate::glib::translate::from_glib_full( self.into_glib_ptr() as *mut M::FfiType )) } } else { Err(self) } } #[inline] pub fn upcast_memory(self) -> M where M: $crate::memory::MemoryType + $crate::glib::translate::FromGlibPtrFull< *const ::FfiType, >, ::RefType: AsRef<$crate::MemoryRef> + AsMut<$crate::MemoryRef>, Self: AsRef, { unsafe { $crate::glib::translate::from_glib_full( self.into_glib_ptr() as *const ::FfiType ) } } } impl $ref_name { #[inline] pub fn upcast_memory_ref(&self) -> &M::RefType where M: $crate::memory::MemoryType, ::RefType: AsRef<$crate::MemoryRef> + AsMut<$crate::MemoryRef>, Self: AsRef + AsMut { self.as_ref() } #[inline] pub fn upcast_memory_mut(&mut self) -> &mut M::RefType where M: $crate::memory::MemoryType, ::RefType: AsRef<$crate::MemoryRef> + AsMut<$crate::MemoryRef>, Self: AsRef + AsMut { self.as_mut() } } impl std::ops::Deref for $ref_name { type Target = $parent_memory_ref_type; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self as *const _ as *const Self::Target) } } } impl std::ops::DerefMut for $ref_name { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *(self as *mut _ as *mut Self::Target) } } } impl AsRef<$parent_memory_type> for $name { #[inline] fn as_ref(&self) -> &$parent_memory_type { unsafe { &*(self as *const _ as *const $parent_memory_type) } } } impl AsRef<$parent_memory_ref_type> for $ref_name { #[inline] fn as_ref(&self) -> &$parent_memory_ref_type { self } } impl AsMut<$parent_memory_ref_type> for $ref_name { #[inline] fn as_mut(&mut self) -> &mut $parent_memory_ref_type { &mut *self } } impl $crate::glib::types::StaticType for $name { #[inline] fn static_type() -> glib::types::Type { $ref_name::static_type() } } impl $crate::glib::types::StaticType for $ref_name { #[inline] fn static_type() -> $crate::glib::types::Type { unsafe { $crate::glib::translate::from_glib($crate::ffi::gst_memory_get_type()) } } } impl $crate::glib::value::ValueType for $name { type Type = Self; } unsafe impl<'a> $crate::glib::value::FromValue<'a> for $name { type Checker = $crate::memory::MemoryTypeValueTypeChecker; unsafe fn from_value(value: &'a $crate::glib::Value) -> Self { skip_assert_initialized!(); $crate::glib::translate::from_glib_none($crate::glib::gobject_ffi::g_value_get_boxed( $crate::glib::translate::ToGlibPtr::to_glib_none(value).0, ) as *mut $ffi_name) } } unsafe impl<'a> $crate::glib::value::FromValue<'a> for &'a $name { type Checker = $crate::memory::MemoryTypeValueTypeChecker<$name>; unsafe fn from_value(value: &'a $crate::glib::Value) -> Self { skip_assert_initialized!(); assert_eq!( std::mem::size_of::<$name>(), std::mem::size_of::<$crate::glib::ffi::gpointer>() ); let value = &*(value as *const $crate::glib::Value as *const $crate::glib::gobject_ffi::GValue); let ptr = &value.data[0].v_pointer as *const $crate::glib::ffi::gpointer as *const *const $ffi_name; debug_assert!(!(*ptr).is_null()); &*(ptr as *const $name) } } impl $crate::glib::value::ToValue for $name { fn to_value(&self) -> $crate::glib::Value { let mut value = $crate::glib::Value::for_value_type::(); unsafe { $crate::glib::gobject_ffi::g_value_set_boxed( $crate::glib::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::glib::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(self).0 as *mut _, ) } value } fn value_type(&self) -> glib::Type { ::static_type() } } impl $crate::glib::value::ToValueOptional for $name { fn to_value_optional(s: Option<&Self>) -> $crate::glib::Value { skip_assert_initialized!(); let mut value = $crate::glib::Value::for_value_type::(); unsafe { $crate::glib::gobject_ffi::g_value_set_boxed( $crate::glib::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::glib::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&s).0 as *mut _, ) } value } } impl From<$name> for $crate::glib::Value { fn from(v: $name) -> $crate::glib::Value { skip_assert_initialized!(); let mut value = $crate::glib::Value::for_value_type::<$name>(); unsafe { $crate::glib::gobject_ffi::g_value_take_boxed( $crate::glib::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::glib::translate::IntoGlibPtr::<*mut $ffi_name>::into_glib_ptr(v) as *mut _, ) } value } } unsafe impl<'a> $crate::glib::value::FromValue<'a> for &'a $ref_name { type Checker = $crate::memory::MemoryTypeValueTypeChecker<$name>; unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); &*($crate::glib::gobject_ffi::g_value_get_boxed($crate::glib::translate::ToGlibPtr::to_glib_none(value).0) as *const $ref_name) } } // Can't have SetValue/SetValueOptional impls as otherwise one could use it to get // immutable references from a mutable reference without borrowing via the value }; ($name:ident, $ref_name:ident, $ffi_name:path, $mem_type_check:expr, $parent_memory_type:path, $parent_memory_ref_type:path, $($parent_parent_memory_type:path, $parent_parent_memory_ref_type:path),*) => { $crate::memory_object_wrapper!($name, $ref_name, $ffi_name, $mem_type_check, $parent_memory_type, $parent_memory_ref_type); $( impl AsRef<$parent_parent_memory_type> for $name { #[inline] fn as_ref(&self) -> &$parent_parent_memory_type { unsafe { &*(self as *const _ as *const $parent_parent_memory_type) } } } impl AsRef<$parent_parent_memory_ref_type> for $ref_name { #[inline] fn as_ref(&self) -> &$parent_parent_memory_ref_type { self } } impl AsMut<$parent_parent_memory_ref_type> for $ref_name { #[inline] fn as_mut(&mut self) -> &mut $parent_parent_memory_ref_type { &mut *self } } )* }; } #[cfg(test)] mod tests { #[test] fn test_map() { crate::init().unwrap(); let mem = crate::Memory::from_slice(vec![1, 2, 3, 4]); let map = mem.map_readable().unwrap(); assert_eq!(map.as_slice(), &[1, 2, 3, 4]); drop(map); let mem = mem.into_mapped_memory_readable().unwrap(); assert_eq!(mem.as_slice(), &[1, 2, 3, 4]); let mem = mem.into_memory(); let map = mem.map_readable().unwrap(); assert_eq!(map.as_slice(), &[1, 2, 3, 4]); } #[test] fn test_share() { crate::init().unwrap(); let mem = crate::Memory::from_slice(vec![1, 2, 3, 4]); let sub = mem.share(1..=2); // [2, 3] let sub_sub1 = sub.share(1..=1); // [3] let sub_sub2 = sub.share_maxsize(0..4); // [1, 2, 3, 4] let map = mem.map_readable().unwrap(); assert_eq!(map.as_slice(), &[1, 2, 3, 4]); drop(map); let map = sub.map_readable().unwrap(); assert_eq!(map.as_slice(), &[2, 3]); drop(map); let map = sub_sub1.map_readable().unwrap(); assert_eq!(map.as_slice(), &[3]); drop(map); let map = sub_sub2.map_readable().unwrap(); assert_eq!(map.as_slice(), &[1, 2, 3, 4]); drop(map); } #[test] fn test_dump() { use std::fmt::Write; crate::init().unwrap(); let mut s = String::new(); let mem = crate::Memory::from_slice(vec![1, 2, 3, 4]); write!(&mut s, "{:?}", mem.dump()).unwrap(); assert_eq!( s, "0000: 01 02 03 04 ...." ); s.clear(); write!(&mut s, "{}", mem.dump()).unwrap(); assert_eq!(s, "01 02 03 04"); s.clear(); let mem = crate::Memory::from_slice(vec![1, 2, 3, 4]); write!(&mut s, "{:?}", mem.dump_range(..)).unwrap(); assert_eq!( s, "0000: 01 02 03 04 ...." ); s.clear(); write!(&mut s, "{:?}", mem.dump_range(..2)).unwrap(); assert_eq!( s, "0000: 01 02 .." ); s.clear(); write!(&mut s, "{:?}", mem.dump_range(2..=3)).unwrap(); assert_eq!( s, "0002: 03 04 .." ); s.clear(); write!(&mut s, "{:?}", mem.dump_range(..100)).unwrap(); assert_eq!(s, "",); s.clear(); write!(&mut s, "{:?}", mem.dump_range(90..100)).unwrap(); assert_eq!(s, "",); s.clear(); let mem = crate::Memory::from_slice(vec![0; 19]); write!(&mut s, "{:?}", mem.dump()).unwrap(); assert_eq!( s, "0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................\n\ 0010: 00 00 00 ..." ); s.clear(); } #[test] fn test_value() { use glib::prelude::*; crate::init().unwrap(); let v = None::<&crate::Memory>.to_value(); assert!(matches!(v.get::>(), Ok(None))); let mem = crate::Memory::from_slice(vec![1, 2, 3, 4]); let v = mem.to_value(); assert!(matches!(v.get::>(), Ok(Some(_)))); assert!(v.get::().is_ok()); } } gstreamer-0.23.5/src/memory_wrapped.rs000064400000000000000000000211721046102023000160760ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::{prelude::*, translate::*}; use std::{alloc, mem, ptr}; use crate::{ffi, Memory}; #[repr(C)] struct WrappedMemory { mem: ffi::GstMemory, // AsRef / AsMut values data: *mut u8, // Layout used for allocating this struct, literally `Layout::new` layout: alloc::Layout, // Offset from the beginning of the struct until `wrap` wrap_offset: usize, // `ptr::drop_in_place()` for `T` wrap_drop_in_place: unsafe fn(*mut T), wrap: T, } unsafe extern "C" fn free(_allocator: *mut ffi::GstAllocator, mem: *mut ffi::GstMemory) { let mem = mem as *mut WrappedMemory<()>; if (*mem).wrap_offset > 0 { let wrap = (mem as *mut u8).add((*mem).wrap_offset) as *mut (); ((*mem).wrap_drop_in_place)(wrap); } alloc::dealloc(mem as *mut u8, (*mem).layout); } unsafe extern "C" fn mem_map( mem: *mut ffi::GstMemory, _maxsize: usize, _flags: ffi::GstMapFlags, ) -> glib::ffi::gpointer { let mem = mem as *mut WrappedMemory<()>; (*mem).data as glib::ffi::gpointer } unsafe extern "C" fn mem_unmap(_mem: *mut ffi::GstMemory) {} unsafe extern "C" fn mem_share( mem: *mut ffi::GstMemory, offset: isize, size: isize, ) -> *mut ffi::GstMemory { let mem = mem as *mut WrappedMemory<()>; // Basically a re-implementation of _sysmem_share() let parent = if (*mem).mem.parent.is_null() { mem } else { (*mem).mem.parent as *mut WrappedMemory<()> }; // Offset and size are actually usizes and the API assumes that negative values simply wrap // around, so let's cast to usizes here and do wrapping arithmetic. let offset = offset as usize; let mut size = size as usize; let new_offset = (*mem).mem.offset.wrapping_add(offset); debug_assert!(new_offset < (*mem).mem.maxsize); if size == usize::MAX { size = (*mem).mem.size.wrapping_sub(offset); } debug_assert!(new_offset <= usize::MAX - size); debug_assert!(new_offset + size <= (*mem).mem.maxsize); let layout = alloc::Layout::new::>(); let sub = alloc::alloc(layout) as *mut WrappedMemory<()>; ffi::gst_memory_init( sub as *mut ffi::GstMemory, (*mem).mem.mini_object.flags | ffi::GST_MINI_OBJECT_FLAG_LOCK_READONLY, (*mem).mem.allocator, parent as *mut ffi::GstMemory, (*mem).mem.maxsize, (*mem).mem.align, new_offset, size, ); ptr::write(ptr::addr_of_mut!((*sub).data), (*mem).data); ptr::write(ptr::addr_of_mut!((*sub).layout), layout); ptr::write(ptr::addr_of_mut!((*sub).wrap_offset), 0); ptr::write(ptr::addr_of_mut!((*sub).wrap_drop_in_place), |_| ()); sub as *mut ffi::GstMemory } unsafe extern "C" fn mem_is_span( mem1: *mut ffi::GstMemory, mem2: *mut ffi::GstMemory, offset: *mut usize, ) -> glib::ffi::gboolean { let mem1 = mem1 as *mut WrappedMemory<()>; let mem2 = mem2 as *mut WrappedMemory<()>; // Basically a re-implementation of _sysmem_is_span() if !offset.is_null() { let parent = (*mem1).mem.parent as *mut WrappedMemory<()>; *offset = (*mem1).mem.offset - (*parent).mem.offset; } let is_span = (*mem1).data.add((*mem1).mem.offset).add((*mem1).mem.size) == (*mem2).data.add((*mem2).mem.offset); is_span.into_glib() } unsafe extern "C" fn class_init(class: glib::ffi::gpointer, _class_data: glib::ffi::gpointer) { let class = class as *mut ffi::GstAllocatorClass; (*class).free = Some(free); } unsafe extern "C" fn instance_init( obj: *mut glib::gobject_ffi::GTypeInstance, _class: glib::ffi::gpointer, ) { static ALLOCATOR_TYPE: &[u8] = b"RustGlobalAllocatorMemory\0"; let allocator = obj as *mut ffi::GstAllocator; (*allocator).mem_type = ALLOCATOR_TYPE.as_ptr() as *const _; (*allocator).mem_map = Some(mem_map); (*allocator).mem_unmap = Some(mem_unmap); // mem_copy not set because the fallback already does the right thing (*allocator).mem_share = Some(mem_share); (*allocator).mem_is_span = Some(mem_is_span); // TODO: Could also implement alloc() (*allocator).object.flags |= ffi::GST_ALLOCATOR_FLAG_CUSTOM_ALLOC; } fn rust_allocator() -> &'static crate::Allocator { static RUST_ALLOCATOR: std::sync::OnceLock = std::sync::OnceLock::new(); RUST_ALLOCATOR.get_or_init(|| unsafe { struct TypeInfoWrap(glib::gobject_ffi::GTypeInfo); unsafe impl Send for TypeInfoWrap {} unsafe impl Sync for TypeInfoWrap {} static TYPE_INFO: TypeInfoWrap = TypeInfoWrap(glib::gobject_ffi::GTypeInfo { class_size: mem::size_of::() as u16, base_init: None, base_finalize: None, class_init: Some(class_init), class_finalize: None, class_data: ptr::null_mut(), instance_size: mem::size_of::() as u16, n_preallocs: 0, instance_init: Some(instance_init), value_table: ptr::null(), }); let type_name = { let mut idx = 0; loop { let type_name = glib::gformat!("GstRsAllocator-{}", idx); if glib::gobject_ffi::g_type_from_name(type_name.as_ptr()) == glib::gobject_ffi::G_TYPE_INVALID { break type_name; } idx += 1; } }; let t = glib::gobject_ffi::g_type_register_static( crate::Allocator::static_type().into_glib(), type_name.as_ptr(), &TYPE_INFO.0, 0, ); assert!(t != glib::gobject_ffi::G_TYPE_INVALID); from_glib_none( glib::gobject_ffi::g_object_newv(t, 0, ptr::null_mut()) as *mut ffi::GstAllocator ) }) } impl Memory { #[doc(alias = "gst_memory_new_wrapped")] #[doc(alias = "gst_memory_new_wrapped_full")] #[inline] pub fn from_slice + Send + 'static>(slice: T) -> Self { assert_initialized_main_thread!(); let len = slice.as_ref().len(); unsafe { let layout = alloc::Layout::new::>(); let mem = alloc::alloc(layout) as *mut WrappedMemory; ffi::gst_memory_init( mem as *mut ffi::GstMemory, ffi::GST_MINI_OBJECT_FLAG_LOCK_READONLY, rust_allocator().to_glib_none().0, ptr::null_mut(), len, 0, 0, len, ); ptr::write(ptr::addr_of_mut!((*mem).wrap), slice); assert_eq!(len, (*mem).wrap.as_ref().len()); let data = (*mem).wrap.as_ref().as_ptr(); ptr::write(ptr::addr_of_mut!((*mem).data), mut_override(data)); ptr::write(ptr::addr_of_mut!((*mem).layout), layout); let wrap_offset = ptr::addr_of!((*mem).wrap) as usize - mem as usize; ptr::write(ptr::addr_of_mut!((*mem).wrap_offset), wrap_offset); ptr::write( ptr::addr_of_mut!((*mem).wrap_drop_in_place), ptr::drop_in_place::, ); from_glib_full(mem as *mut ffi::GstMemory) } } #[doc(alias = "gst_memory_new_wrapped")] #[doc(alias = "gst_memory_new_wrapped_full")] #[inline] pub fn from_mut_slice + Send + 'static>(mut slice: T) -> Self { assert_initialized_main_thread!(); let len = slice.as_mut().len(); unsafe { let layout = alloc::Layout::new::>(); let mem = alloc::alloc(layout) as *mut WrappedMemory; ffi::gst_memory_init( mem as *mut ffi::GstMemory, 0, rust_allocator().to_glib_none().0, ptr::null_mut(), len, 0, 0, len, ); ptr::write(ptr::addr_of_mut!((*mem).wrap), slice); assert_eq!(len, (*mem).wrap.as_mut().len()); let data = (*mem).wrap.as_mut().as_mut_ptr(); ptr::write(ptr::addr_of_mut!((*mem).data), data); ptr::write(ptr::addr_of_mut!((*mem).layout), layout); let wrap_offset = ptr::addr_of!((*mem).wrap) as usize - mem as usize; ptr::write(ptr::addr_of_mut!((*mem).wrap_offset), wrap_offset); ptr::write( ptr::addr_of_mut!((*mem).wrap_drop_in_place), ptr::drop_in_place::, ); from_glib_full(mem as *mut ffi::GstMemory) } } } gstreamer-0.23.5/src/message.rs000064400000000000000000004110701046102023000144700ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{borrow::Borrow, ffi::CStr, fmt, mem, num::NonZeroU32, ops::Deref, ops::DerefMut, ptr}; use glib::{ translate::*, value::{SendValue, ValueType}, }; use crate::{ ffi, format::{CompatibleFormattedValue, FormattedValue}, prelude::*, structure::*, GenericFormattedValue, GroupId, MessageType, Object, Seqnum, TagList, }; mini_object_wrapper!(Message, MessageRef, ffi::GstMessage, || { ffi::gst_message_get_type() }); impl MessageRef { #[doc(alias = "get_src")] #[inline] pub fn src(&self) -> Option<&Object> { unsafe { if (*self.as_ptr()).src.is_null() { None } else { Some(&*(&(*self.as_ptr()).src as *const *mut ffi::GstObject as *const Object)) } } } #[doc(alias = "get_seqnum")] #[doc(alias = "gst_message_get_seqnum")] pub fn seqnum(&self) -> Seqnum { unsafe { let seqnum = ffi::gst_message_get_seqnum(self.as_mut_ptr()); if seqnum == 0 { // seqnum for this message is invalid. This can happen with buggy elements // overriding the seqnum with GST_SEQNUM_INVALID instead of the expected seqnum. // As a workaround, let's generate an unused valid seqnum. let next = Seqnum::next(); crate::warning!( crate::CAT_RUST, "get_seqnum detected invalid seqnum, returning next {:?}", next ); return next; } Seqnum(NonZeroU32::new_unchecked(seqnum)) } } #[doc(alias = "gst_message_set_seqnum")] pub fn set_seqnum(&self, seqnum: Seqnum) { unsafe { ffi::gst_message_set_seqnum(self.as_mut_ptr(), seqnum.0.get()); } } #[doc(alias = "get_structure")] #[doc(alias = "gst_message_get_structure")] #[inline] pub fn structure(&self) -> Option<&StructureRef> { unsafe { let structure = ffi::gst_message_get_structure(self.as_mut_ptr()); if structure.is_null() { None } else { Some(StructureRef::from_glib_borrow(structure)) } } } #[doc(alias = "gst_message_writable_structure")] #[inline] pub fn structure_mut(&mut self) -> &mut StructureRef { unsafe { StructureRef::from_glib_borrow_mut(ffi::gst_message_writable_structure( self.as_mut_ptr(), )) } } #[cfg(feature = "v1_26")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))] #[doc(alias = "gst_message_writable_details")] #[inline] pub fn details(&self) -> Option<&StructureRef> { unsafe { let structure = ffi::gst_message_writable_details(self.as_mut_ptr()); if structure.is_null() { None } else { Some(StructureRef::from_glib_borrow(structure)) } } } #[cfg(feature = "v1_26")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))] #[doc(alias = "gst_message_writable_details")] #[inline] pub fn details_mut(&mut self) -> &mut StructureRef { unsafe { StructureRef::from_glib_borrow_mut(ffi::gst_message_writable_details(self.as_mut_ptr())) } } #[cfg(feature = "v1_26")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))] #[doc(alias = "gst_message_set_details")] #[inline] pub fn set_details(&mut self, structure: Structure) { unsafe { ffi::gst_message_set_details(self.as_mut_ptr(), structure.into_glib_ptr()); } } #[doc(alias = "gst_message_has_name")] #[inline] pub fn has_name(&self, name: &str) -> bool { self.structure().is_some_and(|s| s.has_name(name)) } pub fn view(&self) -> MessageView { unsafe { let type_ = (*self.as_ptr()).type_; match type_ { ffi::GST_MESSAGE_EOS => Eos::view(self), ffi::GST_MESSAGE_ERROR => Error::view(self), ffi::GST_MESSAGE_WARNING => Warning::view(self), ffi::GST_MESSAGE_INFO => Info::view(self), ffi::GST_MESSAGE_TAG => Tag::view(self), ffi::GST_MESSAGE_BUFFERING => Buffering::view(self), ffi::GST_MESSAGE_STATE_CHANGED => StateChanged::view(self), ffi::GST_MESSAGE_STATE_DIRTY => StateDirty::view(self), ffi::GST_MESSAGE_STEP_DONE => StepDone::view(self), ffi::GST_MESSAGE_CLOCK_PROVIDE => ClockProvide::view(self), ffi::GST_MESSAGE_CLOCK_LOST => ClockLost::view(self), ffi::GST_MESSAGE_NEW_CLOCK => NewClock::view(self), ffi::GST_MESSAGE_STRUCTURE_CHANGE => StructureChange::view(self), ffi::GST_MESSAGE_STREAM_STATUS => StreamStatus::view(self), ffi::GST_MESSAGE_APPLICATION => Application::view(self), ffi::GST_MESSAGE_ELEMENT => Element::view(self), ffi::GST_MESSAGE_SEGMENT_START => SegmentStart::view(self), ffi::GST_MESSAGE_SEGMENT_DONE => SegmentDone::view(self), ffi::GST_MESSAGE_DURATION_CHANGED => DurationChanged::view(self), ffi::GST_MESSAGE_LATENCY => Latency::view(self), ffi::GST_MESSAGE_ASYNC_START => AsyncStart::view(self), ffi::GST_MESSAGE_ASYNC_DONE => AsyncDone::view(self), ffi::GST_MESSAGE_REQUEST_STATE => RequestState::view(self), ffi::GST_MESSAGE_STEP_START => StepStart::view(self), ffi::GST_MESSAGE_QOS => Qos::view(self), ffi::GST_MESSAGE_PROGRESS => Progress::view(self), ffi::GST_MESSAGE_TOC => Toc::view(self), ffi::GST_MESSAGE_RESET_TIME => ResetTime::view(self), ffi::GST_MESSAGE_STREAM_START => StreamStart::view(self), ffi::GST_MESSAGE_NEED_CONTEXT => NeedContext::view(self), ffi::GST_MESSAGE_HAVE_CONTEXT => HaveContext::view(self), ffi::GST_MESSAGE_DEVICE_ADDED => DeviceAdded::view(self), ffi::GST_MESSAGE_DEVICE_REMOVED => DeviceRemoved::view(self), ffi::GST_MESSAGE_REDIRECT => Redirect::view(self), ffi::GST_MESSAGE_PROPERTY_NOTIFY => PropertyNotify::view(self), ffi::GST_MESSAGE_STREAM_COLLECTION => StreamCollection::view(self), ffi::GST_MESSAGE_STREAMS_SELECTED => StreamsSelected::view(self), #[cfg(feature = "v1_16")] ffi::GST_MESSAGE_DEVICE_CHANGED => DeviceChanged::view(self), #[cfg(feature = "v1_18")] ffi::GST_MESSAGE_INSTANT_RATE_REQUEST => InstantRateRequest::view(self), _ => MessageView::Other, } } } pub fn view_mut(&mut self) -> MessageViewMut { unsafe { let type_ = (*self.as_ptr()).type_; match type_ { ffi::GST_MESSAGE_EOS => Eos::view_mut(self), ffi::GST_MESSAGE_ERROR => Error::view_mut(self), ffi::GST_MESSAGE_WARNING => Warning::view_mut(self), ffi::GST_MESSAGE_INFO => Info::view_mut(self), ffi::GST_MESSAGE_TAG => Tag::view_mut(self), ffi::GST_MESSAGE_BUFFERING => Buffering::view_mut(self), ffi::GST_MESSAGE_STATE_CHANGED => StateChanged::view_mut(self), ffi::GST_MESSAGE_STATE_DIRTY => StateDirty::view_mut(self), ffi::GST_MESSAGE_STEP_DONE => StepDone::view_mut(self), ffi::GST_MESSAGE_CLOCK_PROVIDE => ClockProvide::view_mut(self), ffi::GST_MESSAGE_CLOCK_LOST => ClockLost::view_mut(self), ffi::GST_MESSAGE_NEW_CLOCK => NewClock::view_mut(self), ffi::GST_MESSAGE_STRUCTURE_CHANGE => StructureChange::view_mut(self), ffi::GST_MESSAGE_STREAM_STATUS => StreamStatus::view_mut(self), ffi::GST_MESSAGE_APPLICATION => Application::view_mut(self), ffi::GST_MESSAGE_ELEMENT => Element::view_mut(self), ffi::GST_MESSAGE_SEGMENT_START => SegmentStart::view_mut(self), ffi::GST_MESSAGE_SEGMENT_DONE => SegmentDone::view_mut(self), ffi::GST_MESSAGE_DURATION_CHANGED => DurationChanged::view_mut(self), ffi::GST_MESSAGE_LATENCY => Latency::view_mut(self), ffi::GST_MESSAGE_ASYNC_START => AsyncStart::view_mut(self), ffi::GST_MESSAGE_ASYNC_DONE => AsyncDone::view_mut(self), ffi::GST_MESSAGE_REQUEST_STATE => RequestState::view_mut(self), ffi::GST_MESSAGE_STEP_START => StepStart::view_mut(self), ffi::GST_MESSAGE_QOS => Qos::view_mut(self), ffi::GST_MESSAGE_PROGRESS => Progress::view_mut(self), ffi::GST_MESSAGE_TOC => Toc::view_mut(self), ffi::GST_MESSAGE_RESET_TIME => ResetTime::view_mut(self), ffi::GST_MESSAGE_STREAM_START => StreamStart::view_mut(self), ffi::GST_MESSAGE_NEED_CONTEXT => NeedContext::view_mut(self), ffi::GST_MESSAGE_HAVE_CONTEXT => HaveContext::view_mut(self), ffi::GST_MESSAGE_DEVICE_ADDED => DeviceAdded::view_mut(self), ffi::GST_MESSAGE_DEVICE_REMOVED => DeviceRemoved::view_mut(self), ffi::GST_MESSAGE_REDIRECT => Redirect::view_mut(self), ffi::GST_MESSAGE_PROPERTY_NOTIFY => PropertyNotify::view_mut(self), ffi::GST_MESSAGE_STREAM_COLLECTION => StreamCollection::view_mut(self), ffi::GST_MESSAGE_STREAMS_SELECTED => StreamsSelected::view_mut(self), #[cfg(feature = "v1_16")] ffi::GST_MESSAGE_DEVICE_CHANGED => DeviceChanged::view_mut(self), #[cfg(feature = "v1_18")] ffi::GST_MESSAGE_INSTANT_RATE_REQUEST => InstantRateRequest::view_mut(self), _ => MessageViewMut::Other, } } } #[doc(alias = "get_type")] #[inline] pub fn type_(&self) -> MessageType { unsafe { from_glib((*self.as_ptr()).type_) } } } impl fmt::Debug for Message { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { MessageRef::fmt(self, f) } } impl fmt::Debug for MessageRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Don't retrieve `seqnum` using `MessageRef::get_seqnum` // because it would generate a new seqnum if a buggy `Element` // emitted a `Message` with an invalid `seqnum`. // We want to help the user find out there is something wrong here, // so they can investigate the origin. let seqnum = unsafe { ffi::gst_message_get_seqnum(self.as_mut_ptr()) }; let seqnum = if seqnum != 0 { &seqnum as &dyn fmt::Debug } else { &"INVALID (0)" as &dyn fmt::Debug }; f.debug_struct("Message") .field("ptr", &self.as_ptr()) .field("type", &unsafe { let type_ = ffi::gst_message_type_get_name((*self.as_ptr()).type_); CStr::from_ptr(type_).to_str().unwrap() }) .field("seqnum", seqnum) .field( "src", &self .src() .map(|s| s.name()) .as_ref() .map(glib::GString::as_str), ) .field("structure", &self.structure()) .finish() } } #[derive(Debug)] #[non_exhaustive] pub enum MessageView<'a> { Eos(&'a Eos), Error(&'a Error), Warning(&'a Warning), Info(&'a Info), Tag(&'a Tag), Buffering(&'a Buffering), StateChanged(&'a StateChanged), StateDirty(&'a StateDirty), StepDone(&'a StepDone), ClockProvide(&'a ClockProvide), ClockLost(&'a ClockLost), NewClock(&'a NewClock), StructureChange(&'a StructureChange), StreamStatus(&'a StreamStatus), Application(&'a Application), Element(&'a Element), SegmentStart(&'a SegmentStart), SegmentDone(&'a SegmentDone), DurationChanged(&'a DurationChanged), Latency(&'a Latency), AsyncStart(&'a AsyncStart), AsyncDone(&'a AsyncDone), RequestState(&'a RequestState), StepStart(&'a StepStart), Qos(&'a Qos), Progress(&'a Progress), Toc(&'a Toc), ResetTime(&'a ResetTime), StreamStart(&'a StreamStart), NeedContext(&'a NeedContext), HaveContext(&'a HaveContext), DeviceAdded(&'a DeviceAdded), DeviceRemoved(&'a DeviceRemoved), PropertyNotify(&'a PropertyNotify), StreamCollection(&'a StreamCollection), StreamsSelected(&'a StreamsSelected), Redirect(&'a Redirect), #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] DeviceChanged(&'a DeviceChanged), #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] InstantRateRequest(&'a InstantRateRequest), Other, } #[derive(Debug)] #[non_exhaustive] pub enum MessageViewMut<'a> { Eos(&'a mut Eos), Error(&'a mut Error), Warning(&'a mut Warning), Info(&'a mut Info), Tag(&'a mut Tag), Buffering(&'a mut Buffering), StateChanged(&'a mut StateChanged), StateDirty(&'a mut StateDirty), StepDone(&'a mut StepDone), ClockProvide(&'a mut ClockProvide), ClockLost(&'a mut ClockLost), NewClock(&'a mut NewClock), StructureChange(&'a mut StructureChange), StreamStatus(&'a mut StreamStatus), Application(&'a mut Application), Element(&'a mut Element), SegmentStart(&'a mut SegmentStart), SegmentDone(&'a mut SegmentDone), DurationChanged(&'a mut DurationChanged), Latency(&'a mut Latency), AsyncStart(&'a mut AsyncStart), AsyncDone(&'a mut AsyncDone), RequestState(&'a mut RequestState), StepStart(&'a mut StepStart), Qos(&'a mut Qos), Progress(&'a mut Progress), Toc(&'a mut Toc), ResetTime(&'a mut ResetTime), StreamStart(&'a mut StreamStart), NeedContext(&'a mut NeedContext), HaveContext(&'a mut HaveContext), DeviceAdded(&'a mut DeviceAdded), DeviceRemoved(&'a mut DeviceRemoved), PropertyNotify(&'a mut PropertyNotify), StreamCollection(&'a mut StreamCollection), StreamsSelected(&'a mut StreamsSelected), Redirect(&'a mut Redirect), #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] DeviceChanged(&'a mut DeviceChanged), #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] InstantRateRequest(&'a mut InstantRateRequest), Other, } macro_rules! declare_concrete_message( ($name:ident, $param:ident) => { #[repr(transparent)] pub struct $name<$param = MessageRef>($param); impl $name { #[inline] pub fn message(&self) -> &MessageRef { unsafe { &*(self as *const Self as *const MessageRef) } } #[inline] pub fn message_mut(&mut self) -> &mut MessageRef { unsafe { &mut *(self as *mut Self as *mut MessageRef) } } #[inline] unsafe fn view(message: &MessageRef) -> MessageView<'_> { let message = &*(message as *const MessageRef as *const Self); MessageView::$name(message) } #[inline] unsafe fn view_mut(message: &mut MessageRef) -> MessageViewMut<'_> { let message = &mut *(message as *mut MessageRef as *mut Self); MessageViewMut::$name(message) } } impl Deref for $name { type Target = MessageRef; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self as *const Self as *const Self::Target) } } } impl DerefMut for $name { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.message_mut() } } impl ToOwned for $name { type Owned = $name; #[inline] fn to_owned(&self) -> Self::Owned { $name::(self.copy()) } } impl $name { #[inline] pub fn get_mut(&mut self) -> Option<&mut $name> { self.0.get_mut().map(|message| unsafe { &mut *(message as *mut MessageRef as *mut $name) }) } } impl Deref for $name { type Target = $name; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self.0.as_ptr() as *const Self::Target) } } } impl DerefMut for $name { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { debug_assert!(self.0.is_writable()); unsafe { &mut *(self.0.as_mut_ptr() as *mut Self::Target) } } } impl Borrow<$name> for $name { #[inline] fn borrow(&self) -> &$name { &*self } } impl From<$name> for Message { #[inline] fn from(concrete: $name) -> Self { skip_assert_initialized!(); concrete.0 } } } ); declare_concrete_message!(Eos, T); impl Eos { #[doc(alias = "gst_message_new_eos")] #[allow(clippy::new_ret_no_self)] pub fn new() -> Message { skip_assert_initialized!(); Self::builder().build() } pub fn builder<'a>() -> EosBuilder<'a> { assert_initialized_main_thread!(); EosBuilder::new() } } impl std::fmt::Debug for Eos { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Eos") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .finish() } } impl std::fmt::Debug for Eos { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Eos::::fmt(self, f) } } declare_concrete_message!(Error, T); impl Error { #[doc(alias = "gst_message_new_error")] #[allow(clippy::new_ret_no_self)] pub fn new(error: T, message: &str) -> Message { skip_assert_initialized!(); Self::builder(error, message).build() } pub fn builder(error: T, message: &str) -> ErrorBuilder { assert_initialized_main_thread!(); ErrorBuilder::new(glib::Error::new(error, message)) } pub fn builder_from_error<'a>(error: glib::Error) -> ErrorBuilder<'a> { assert_initialized_main_thread!(); assert!([ crate::CoreError::domain(), crate::ResourceError::domain(), crate::StreamError::domain(), crate::LibraryError::domain(), ] .contains(&error.domain())); ErrorBuilder::new(error) } #[doc(alias = "get_error")] #[doc(alias = "gst_message_parse_error")] pub fn error(&self) -> glib::Error { unsafe { let mut error = ptr::null_mut(); ffi::gst_message_parse_error(self.as_mut_ptr(), &mut error, ptr::null_mut()); from_glib_full(error) } } #[doc(alias = "get_debug")] #[doc(alias = "gst_message_parse_error")] pub fn debug(&self) -> Option { unsafe { let mut debug = ptr::null_mut(); ffi::gst_message_parse_error(self.as_mut_ptr(), ptr::null_mut(), &mut debug); from_glib_full(debug) } } #[doc(alias = "get_details")] #[doc(alias = "gst_message_parse_error_details")] pub fn details(&self) -> Option<&StructureRef> { unsafe { let mut details = ptr::null(); ffi::gst_message_parse_error_details(self.as_mut_ptr(), &mut details); if details.is_null() { None } else { Some(StructureRef::from_glib_borrow(details)) } } } #[cfg(feature = "v1_26")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))] #[doc(alias = "gst_message_parse_error_writable_details")] pub fn writable_details(&mut self) -> &mut StructureRef { unsafe { let mut details = ptr::null_mut(); ffi::gst_message_parse_error_writable_details(self.as_mut_ptr(), &mut details); StructureRef::from_glib_borrow_mut(details) } } } impl std::fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.error()) } } impl std::fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Error") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("error", &self.error()) .field("debug", &self.debug()) .field("details", &self.details()) .finish() } } impl std::fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Error::::fmt(self, f) } } declare_concrete_message!(Warning, T); impl Warning { #[doc(alias = "gst_message_new_warning")] #[allow(clippy::new_ret_no_self)] pub fn new(error: T, message: &str) -> Message { skip_assert_initialized!(); Self::builder(error, message).build() } pub fn builder(error: T, message: &str) -> WarningBuilder { assert_initialized_main_thread!(); WarningBuilder::new(glib::Error::new(error, message)) } pub fn builder_from_error<'a>(error: glib::Error) -> WarningBuilder<'a> { assert_initialized_main_thread!(); assert!([ crate::CoreError::domain(), crate::ResourceError::domain(), crate::StreamError::domain(), crate::LibraryError::domain(), ] .contains(&error.domain())); WarningBuilder::new(error) } #[doc(alias = "get_error")] #[doc(alias = "gst_message_parse_warning")] pub fn error(&self) -> glib::Error { unsafe { let mut error = ptr::null_mut(); ffi::gst_message_parse_warning(self.as_mut_ptr(), &mut error, ptr::null_mut()); from_glib_full(error) } } #[doc(alias = "get_debug")] #[doc(alias = "gst_message_parse_warning")] pub fn debug(&self) -> Option { unsafe { let mut debug = ptr::null_mut(); ffi::gst_message_parse_warning(self.as_mut_ptr(), ptr::null_mut(), &mut debug); from_glib_full(debug) } } #[doc(alias = "get_details")] #[doc(alias = "gst_message_parse_warning_details")] pub fn details(&self) -> Option<&StructureRef> { unsafe { let mut details = ptr::null(); ffi::gst_message_parse_warning_details(self.as_mut_ptr(), &mut details); if details.is_null() { None } else { Some(StructureRef::from_glib_borrow(details)) } } } #[cfg(feature = "v1_26")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))] #[doc(alias = "gst_message_parse_warning_writable_details")] pub fn writable_details(&mut self) -> &mut StructureRef { unsafe { let mut details = ptr::null_mut(); ffi::gst_message_parse_warning_writable_details(self.as_mut_ptr(), &mut details); StructureRef::from_glib_borrow_mut(details) } } } impl std::fmt::Display for Warning { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.error()) } } impl std::fmt::Debug for Warning { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Warning") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("error", &self.error()) .field("debug", &self.debug()) .field("details", &self.details()) .finish() } } impl std::fmt::Debug for Warning { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Warning::::fmt(self, f) } } declare_concrete_message!(Info, T); impl Info { #[doc(alias = "gst_message_new_info")] #[allow(clippy::new_ret_no_self)] pub fn new(error: T, message: &str) -> Message { skip_assert_initialized!(); Self::builder(error, message).build() } pub fn builder(error: T, message: &str) -> InfoBuilder { assert_initialized_main_thread!(); InfoBuilder::new(glib::Error::new(error, message)) } pub fn builder_from_error<'a>(error: glib::Error) -> InfoBuilder<'a> { assert_initialized_main_thread!(); assert!([ crate::CoreError::domain(), crate::ResourceError::domain(), crate::StreamError::domain(), crate::LibraryError::domain(), ] .contains(&error.domain())); InfoBuilder::new(error) } #[doc(alias = "get_error")] #[doc(alias = "gst_message_parse_info")] pub fn error(&self) -> glib::Error { unsafe { let mut error = ptr::null_mut(); ffi::gst_message_parse_info(self.as_mut_ptr(), &mut error, ptr::null_mut()); from_glib_full(error) } } #[doc(alias = "get_debug")] #[doc(alias = "gst_message_parse_info")] pub fn debug(&self) -> Option { unsafe { let mut debug = ptr::null_mut(); ffi::gst_message_parse_info(self.as_mut_ptr(), ptr::null_mut(), &mut debug); from_glib_full(debug) } } #[doc(alias = "get_details")] #[doc(alias = "gst_message_parse_info_details")] pub fn details(&self) -> Option<&StructureRef> { unsafe { let mut details = ptr::null(); ffi::gst_message_parse_info_details(self.as_mut_ptr(), &mut details); if details.is_null() { None } else { Some(StructureRef::from_glib_borrow(details)) } } } #[cfg(feature = "v1_26")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))] #[doc(alias = "gst_message_parse_info_writable_details")] pub fn writable_details(&mut self) -> &mut StructureRef { unsafe { let mut details = ptr::null_mut(); ffi::gst_message_parse_info_writable_details(self.as_mut_ptr(), &mut details); StructureRef::from_glib_borrow_mut(details) } } } impl std::fmt::Display for Info { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.error()) } } impl std::fmt::Debug for Info { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Info") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("error", &self.error()) .field("debug", &self.debug()) .field("details", &self.details()) .finish() } } impl std::fmt::Debug for Info { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Info::::fmt(self, f) } } declare_concrete_message!(Tag, T); impl Tag { #[doc(alias = "gst_message_new_tag")] #[allow(clippy::new_ret_no_self)] pub fn new(tags: &TagList) -> Message { skip_assert_initialized!(); Self::builder(tags).build() } pub fn builder(tags: &TagList) -> TagBuilder { assert_initialized_main_thread!(); TagBuilder::new(tags) } #[doc(alias = "get_tags")] #[doc(alias = "gst_message_parse_tag")] pub fn tags(&self) -> TagList { unsafe { let mut tags = ptr::null_mut(); ffi::gst_message_parse_tag(self.as_mut_ptr(), &mut tags); from_glib_full(tags) } } } impl std::fmt::Debug for Tag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Tag") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("tags", &self.tags()) .finish() } } impl std::fmt::Debug for Tag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Tag::::fmt(self, f) } } declare_concrete_message!(Buffering, T); impl Buffering { #[doc(alias = "gst_message_new_buffering")] #[allow(clippy::new_ret_no_self)] pub fn new(percent: i32) -> Message { skip_assert_initialized!(); Self::builder(percent).build() } pub fn builder<'a>(percent: i32) -> BufferingBuilder<'a> { assert_initialized_main_thread!(); BufferingBuilder::new(percent) } #[doc(alias = "get_percent")] #[doc(alias = "gst_message_parse_buffering")] pub fn percent(&self) -> i32 { unsafe { let mut p = mem::MaybeUninit::uninit(); ffi::gst_message_parse_buffering(self.as_mut_ptr(), p.as_mut_ptr()); p.assume_init() } } #[doc(alias = "get_buffering_stats")] #[doc(alias = "gst_message_parse_buffering_stats")] pub fn buffering_stats(&self) -> (crate::BufferingMode, i32, i32, i64) { unsafe { let mut mode = mem::MaybeUninit::uninit(); let mut avg_in = mem::MaybeUninit::uninit(); let mut avg_out = mem::MaybeUninit::uninit(); let mut buffering_left = mem::MaybeUninit::uninit(); ffi::gst_message_parse_buffering_stats( self.as_mut_ptr(), mode.as_mut_ptr(), avg_in.as_mut_ptr(), avg_out.as_mut_ptr(), buffering_left.as_mut_ptr(), ); ( from_glib(mode.assume_init()), avg_in.assume_init(), avg_out.assume_init(), buffering_left.assume_init(), ) } } } impl std::fmt::Debug for Buffering { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Buffering") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("percent", &self.percent()) .field("buffering-stats", &self.buffering_stats()) .finish() } } impl std::fmt::Debug for Buffering { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Buffering::::fmt(self, f) } } declare_concrete_message!(StateChanged, T); impl StateChanged { #[doc(alias = "gst_message_new_state_changed")] #[allow(clippy::new_ret_no_self)] pub fn new(old: crate::State, new: crate::State, pending: crate::State) -> Message { skip_assert_initialized!(); Self::builder(old, new, pending).build() } pub fn builder<'a>( old: crate::State, new: crate::State, pending: crate::State, ) -> StateChangedBuilder<'a> { assert_initialized_main_thread!(); StateChangedBuilder::new(old, new, pending) } #[doc(alias = "get_old")] #[doc(alias = "gst_message_parse_state_changed")] pub fn old(&self) -> crate::State { unsafe { let mut state = mem::MaybeUninit::uninit(); ffi::gst_message_parse_state_changed( self.as_mut_ptr(), state.as_mut_ptr(), ptr::null_mut(), ptr::null_mut(), ); from_glib(state.assume_init()) } } #[doc(alias = "get_current")] #[doc(alias = "gst_message_parse_state_changed")] pub fn current(&self) -> crate::State { unsafe { let mut state = mem::MaybeUninit::uninit(); ffi::gst_message_parse_state_changed( self.as_mut_ptr(), ptr::null_mut(), state.as_mut_ptr(), ptr::null_mut(), ); from_glib(state.assume_init()) } } #[doc(alias = "get_pending")] #[doc(alias = "gst_message_parse_state_changed")] pub fn pending(&self) -> crate::State { unsafe { let mut state = mem::MaybeUninit::uninit(); ffi::gst_message_parse_state_changed( self.as_mut_ptr(), ptr::null_mut(), ptr::null_mut(), state.as_mut_ptr(), ); from_glib(state.assume_init()) } } } impl std::fmt::Debug for StateChanged { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StateChanged") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("old", &self.old()) .field("current", &self.current()) .field("pending", &self.pending()) .finish() } } impl std::fmt::Debug for StateChanged { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StateChanged::::fmt(self, f) } } declare_concrete_message!(StateDirty, T); impl StateDirty { #[doc(alias = "gst_message_new_state_dirty")] #[allow(clippy::new_ret_no_self)] pub fn new() -> Message { skip_assert_initialized!(); Self::builder().build() } pub fn builder<'a>() -> StateDirtyBuilder<'a> { assert_initialized_main_thread!(); StateDirtyBuilder::new() } } impl std::fmt::Debug for StateDirty { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StateDirty") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .finish() } } impl std::fmt::Debug for StateDirty { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StateDirty::::fmt(self, f) } } declare_concrete_message!(StepDone, T); impl StepDone { #[doc(alias = "gst_message_new_step_done")] #[allow(clippy::new_ret_no_self)] pub fn new( amount: impl FormattedValue, rate: f64, flush: bool, intermediate: bool, duration: impl Into>, eos: bool, ) -> Message { skip_assert_initialized!(); Self::builder(amount, rate, flush, intermediate, duration, eos).build() } pub fn builder<'a>( amount: impl FormattedValue, rate: f64, flush: bool, intermediate: bool, duration: impl Into>, eos: bool, ) -> StepDoneBuilder<'a> { assert_initialized_main_thread!(); StepDoneBuilder::new( amount.into(), rate, flush, intermediate, duration.into(), eos, ) } #[doc(alias = "gst_message_parse_step_done")] pub fn get( &self, ) -> ( GenericFormattedValue, f64, bool, bool, Option, bool, ) { unsafe { let mut format = mem::MaybeUninit::uninit(); let mut amount = mem::MaybeUninit::uninit(); let mut rate = mem::MaybeUninit::uninit(); let mut flush = mem::MaybeUninit::uninit(); let mut intermediate = mem::MaybeUninit::uninit(); let mut duration = mem::MaybeUninit::uninit(); let mut eos = mem::MaybeUninit::uninit(); ffi::gst_message_parse_step_done( self.as_mut_ptr(), format.as_mut_ptr(), amount.as_mut_ptr(), rate.as_mut_ptr(), flush.as_mut_ptr(), intermediate.as_mut_ptr(), duration.as_mut_ptr(), eos.as_mut_ptr(), ); ( GenericFormattedValue::new( from_glib(format.assume_init()), amount.assume_init() as i64, ), rate.assume_init(), from_glib(flush.assume_init()), from_glib(intermediate.assume_init()), from_glib(duration.assume_init()), from_glib(eos.assume_init()), ) } } } impl std::fmt::Debug for StepDone { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (format, rate, flush, intermediate, duration, eos) = self.get(); f.debug_struct("StepDone") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("format", &format) .field("rate", &rate) .field("flush", &flush) .field("intermediate", &intermediate) .field("duration", &duration) .field("eos", &eos) .finish() } } impl std::fmt::Debug for StepDone { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StepDone::::fmt(self, f) } } declare_concrete_message!(ClockProvide, T); impl ClockProvide { #[doc(alias = "gst_message_new_clock_provide")] #[allow(clippy::new_ret_no_self)] pub fn new(clock: &crate::Clock, ready: bool) -> Message { skip_assert_initialized!(); Self::builder(clock, ready).build() } pub fn builder(clock: &crate::Clock, ready: bool) -> ClockProvideBuilder { assert_initialized_main_thread!(); ClockProvideBuilder::new(clock, ready) } #[doc(alias = "get_clock")] #[doc(alias = "gst_message_parse_clock_provide")] pub fn clock(&self) -> Option { let mut clock = ptr::null_mut(); unsafe { ffi::gst_message_parse_clock_provide(self.as_mut_ptr(), &mut clock, ptr::null_mut()); from_glib_none(clock) } } #[doc(alias = "get_ready")] #[doc(alias = "gst_message_parse_clock_provide")] pub fn is_ready(&self) -> bool { unsafe { let mut ready = mem::MaybeUninit::uninit(); ffi::gst_message_parse_clock_provide( self.as_mut_ptr(), ptr::null_mut(), ready.as_mut_ptr(), ); from_glib(ready.assume_init()) } } } impl std::fmt::Debug for ClockProvide { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ClockProvide") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("clock", &self.clock()) .field("is-ready", &self.is_ready()) .finish() } } impl std::fmt::Debug for ClockProvide { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ClockProvide::::fmt(self, f) } } declare_concrete_message!(ClockLost, T); impl ClockLost { #[doc(alias = "gst_message_new_clock_lost")] #[allow(clippy::new_ret_no_self)] pub fn new(clock: &crate::Clock) -> Message { skip_assert_initialized!(); Self::builder(clock).build() } pub fn builder(clock: &crate::Clock) -> ClockLostBuilder { assert_initialized_main_thread!(); ClockLostBuilder::new(clock) } #[doc(alias = "get_clock")] #[doc(alias = "gst_message_parse_clock_lost")] pub fn clock(&self) -> Option { let mut clock = ptr::null_mut(); unsafe { ffi::gst_message_parse_clock_lost(self.as_mut_ptr(), &mut clock); from_glib_none(clock) } } } impl std::fmt::Debug for ClockLost { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ClockLost") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("clock", &self.clock()) .finish() } } impl std::fmt::Debug for ClockLost { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ClockLost::::fmt(self, f) } } declare_concrete_message!(NewClock, T); impl NewClock { #[doc(alias = "gst_message_new_new_clock")] #[allow(clippy::new_ret_no_self)] pub fn new(clock: &crate::Clock) -> Message { skip_assert_initialized!(); Self::builder(clock).build() } pub fn builder(clock: &crate::Clock) -> NewClockBuilder { assert_initialized_main_thread!(); NewClockBuilder::new(clock) } #[doc(alias = "get_clock")] #[doc(alias = "gst_message_parse_new_clock")] pub fn clock(&self) -> Option { let mut clock = ptr::null_mut(); unsafe { ffi::gst_message_parse_new_clock(self.as_mut_ptr(), &mut clock); from_glib_none(clock) } } } impl std::fmt::Debug for NewClock { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("NewClock") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("clock", &self.clock()) .finish() } } impl std::fmt::Debug for NewClock { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { NewClock::::fmt(self, f) } } declare_concrete_message!(StructureChange, T); impl StructureChange { #[doc(alias = "gst_message_new_structure_change")] #[allow(clippy::new_ret_no_self)] pub fn new(type_: crate::StructureChangeType, owner: &crate::Element, busy: bool) -> Message { skip_assert_initialized!(); Self::builder(type_, owner, busy).build() } pub fn builder( type_: crate::StructureChangeType, owner: &crate::Element, busy: bool, ) -> StructureChangeBuilder { assert_initialized_main_thread!(); StructureChangeBuilder::new(type_, owner, busy) } #[doc(alias = "gst_message_parse_structure_change")] pub fn get(&self) -> (crate::StructureChangeType, crate::Element, bool) { unsafe { let mut type_ = mem::MaybeUninit::uninit(); let mut owner = ptr::null_mut(); let mut busy = mem::MaybeUninit::uninit(); ffi::gst_message_parse_structure_change( self.as_mut_ptr(), type_.as_mut_ptr(), &mut owner, busy.as_mut_ptr(), ); ( from_glib(type_.assume_init()), from_glib_none(owner), from_glib(busy.assume_init()), ) } } } impl std::fmt::Debug for StructureChange { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (type_, owner, busy) = self.get(); f.debug_struct("StructureChange") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("type", &type_) .field("owner", &owner) .field("busy", &busy) .finish() } } impl std::fmt::Debug for StructureChange { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StructureChange::::fmt(self, f) } } declare_concrete_message!(StreamStatus, T); impl StreamStatus { #[doc(alias = "gst_message_new_stream_status")] #[allow(clippy::new_ret_no_self)] pub fn new(type_: crate::StreamStatusType, owner: &crate::Element) -> Message { skip_assert_initialized!(); Self::builder(type_, owner).build() } pub fn builder(type_: crate::StreamStatusType, owner: &crate::Element) -> StreamStatusBuilder { assert_initialized_main_thread!(); StreamStatusBuilder::new(type_, owner) } #[doc(alias = "gst_message_parse_stream_status")] pub fn get(&self) -> (crate::StreamStatusType, crate::Element) { unsafe { let mut type_ = mem::MaybeUninit::uninit(); let mut owner = ptr::null_mut(); ffi::gst_message_parse_stream_status(self.as_mut_ptr(), type_.as_mut_ptr(), &mut owner); (from_glib(type_.assume_init()), from_glib_none(owner)) } } #[doc(alias = "get_stream_status_object")] #[doc(alias = "gst_message_get_stream_status_object")] pub fn stream_status_object(&self) -> Option { unsafe { let value = ffi::gst_message_get_stream_status_object(self.as_mut_ptr()); from_glib_none(value) } } } impl std::fmt::Debug for StreamStatus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StreamStatus") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("status", &self.stream_status_object()) .finish() } } impl std::fmt::Debug for StreamStatus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StreamStatus::::fmt(self, f) } } declare_concrete_message!(Application, T); impl Application { #[doc(alias = "gst_message_new_application")] #[allow(clippy::new_ret_no_self)] pub fn new(structure: crate::Structure) -> Message { skip_assert_initialized!(); Self::builder(structure).build() } pub fn builder<'a>(structure: crate::Structure) -> ApplicationBuilder<'a> { assert_initialized_main_thread!(); ApplicationBuilder::new(structure) } } impl std::fmt::Debug for Application { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Application") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .finish() } } impl std::fmt::Debug for Application { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Application::::fmt(self, f) } } declare_concrete_message!(Element, T); impl Element { #[doc(alias = "gst_message_new_element")] #[allow(clippy::new_ret_no_self)] pub fn new(structure: crate::Structure) -> Message { skip_assert_initialized!(); Self::builder(structure).build() } pub fn builder<'a>(structure: crate::Structure) -> ElementBuilder<'a> { assert_initialized_main_thread!(); ElementBuilder::new(structure) } } impl std::fmt::Debug for Element { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Element") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .finish() } } impl std::fmt::Debug for Element { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Element::::fmt(self, f) } } declare_concrete_message!(SegmentStart, T); impl SegmentStart { #[doc(alias = "gst_message_new_segment_start")] #[allow(clippy::new_ret_no_self)] pub fn new(position: impl FormattedValue) -> Message { skip_assert_initialized!(); Self::builder(position).build() } pub fn builder<'a>(position: impl FormattedValue) -> SegmentStartBuilder<'a> { assert_initialized_main_thread!(); SegmentStartBuilder::new(position.into()) } #[doc(alias = "gst_message_parse_segment_start")] pub fn get(&self) -> GenericFormattedValue { unsafe { let mut format = mem::MaybeUninit::uninit(); let mut position = mem::MaybeUninit::uninit(); ffi::gst_message_parse_segment_start( self.as_mut_ptr(), format.as_mut_ptr(), position.as_mut_ptr(), ); GenericFormattedValue::new(from_glib(format.assume_init()), position.assume_init()) } } } impl std::fmt::Debug for SegmentStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SegmentStart") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("segment", &self.get()) .finish() } } impl std::fmt::Debug for SegmentStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { SegmentStart::::fmt(self, f) } } declare_concrete_message!(SegmentDone, T); impl SegmentDone { #[doc(alias = "gst_message_new_segment_done")] #[allow(clippy::new_ret_no_self)] pub fn new(position: impl FormattedValue) -> Message { skip_assert_initialized!(); Self::builder(position).build() } pub fn builder<'a>(position: impl FormattedValue) -> SegmentDoneBuilder<'a> { assert_initialized_main_thread!(); SegmentDoneBuilder::new(position.into()) } #[doc(alias = "gst_message_parse_segment_done")] pub fn get(&self) -> GenericFormattedValue { unsafe { let mut format = mem::MaybeUninit::uninit(); let mut position = mem::MaybeUninit::uninit(); ffi::gst_message_parse_segment_done( self.as_mut_ptr(), format.as_mut_ptr(), position.as_mut_ptr(), ); GenericFormattedValue::new(from_glib(format.assume_init()), position.assume_init()) } } } impl std::fmt::Debug for SegmentDone { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SegmentDone") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("segment", &self.get()) .finish() } } impl std::fmt::Debug for SegmentDone { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { SegmentDone::::fmt(self, f) } } declare_concrete_message!(DurationChanged, T); impl DurationChanged { #[doc(alias = "gst_message_new_duration_changed")] #[allow(clippy::new_ret_no_self)] pub fn new() -> Message { skip_assert_initialized!(); Self::builder().build() } pub fn builder<'a>() -> DurationChangedBuilder<'a> { assert_initialized_main_thread!(); DurationChangedBuilder::new() } } impl std::fmt::Debug for DurationChanged { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DurationChanged") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .finish() } } impl std::fmt::Debug for DurationChanged { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { DurationChanged::::fmt(self, f) } } declare_concrete_message!(Latency, T); impl Latency { #[doc(alias = "gst_message_new_latency")] #[allow(clippy::new_ret_no_self)] pub fn new() -> Message { skip_assert_initialized!(); Self::builder().build() } pub fn builder<'a>() -> LatencyBuilder<'a> { assert_initialized_main_thread!(); LatencyBuilder::new() } } impl std::fmt::Debug for Latency { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Latency") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .finish() } } impl std::fmt::Debug for Latency { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Latency::::fmt(self, f) } } declare_concrete_message!(AsyncStart, T); impl AsyncStart { #[doc(alias = "gst_message_new_async_start")] #[allow(clippy::new_ret_no_self)] pub fn new() -> Message { skip_assert_initialized!(); Self::builder().build() } pub fn builder<'a>() -> AsyncStartBuilder<'a> { assert_initialized_main_thread!(); AsyncStartBuilder::new() } } impl std::fmt::Debug for AsyncStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AsyncStart") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .finish() } } impl std::fmt::Debug for AsyncStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { AsyncStart::::fmt(self, f) } } declare_concrete_message!(AsyncDone, T); impl AsyncDone { #[doc(alias = "gst_message_new_async_done")] #[allow(clippy::new_ret_no_self)] pub fn new(running_time: impl Into>) -> Message { skip_assert_initialized!(); Self::builder().running_time(running_time).build() } pub fn builder<'a>() -> AsyncDoneBuilder<'a> { assert_initialized_main_thread!(); AsyncDoneBuilder::new() } #[doc(alias = "get_running_time")] #[doc(alias = "gst_message_parse_async_done")] pub fn running_time(&self) -> Option { unsafe { let mut running_time = mem::MaybeUninit::uninit(); ffi::gst_message_parse_async_done(self.as_mut_ptr(), running_time.as_mut_ptr()); from_glib(running_time.assume_init()) } } } impl std::fmt::Debug for AsyncDone { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AsyncDone") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("running-time", &self.running_time()) .finish() } } impl std::fmt::Debug for AsyncDone { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { AsyncDone::::fmt(self, f) } } declare_concrete_message!(RequestState, T); impl RequestState { #[doc(alias = "gst_message_new_request_state")] #[allow(clippy::new_ret_no_self)] pub fn new(state: crate::State) -> Message { skip_assert_initialized!(); Self::builder(state).build() } pub fn builder<'a>(state: crate::State) -> RequestStateBuilder<'a> { assert_initialized_main_thread!(); RequestStateBuilder::new(state) } #[doc(alias = "get_requested_state")] #[doc(alias = "gst_message_parse_request_state")] pub fn requested_state(&self) -> crate::State { unsafe { let mut state = mem::MaybeUninit::uninit(); ffi::gst_message_parse_request_state(self.as_mut_ptr(), state.as_mut_ptr()); from_glib(state.assume_init()) } } } impl std::fmt::Debug for RequestState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RequestState") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("requested-state", &self.requested_state()) .finish() } } impl std::fmt::Debug for RequestState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { RequestState::::fmt(self, f) } } declare_concrete_message!(StepStart, T); impl StepStart { #[doc(alias = "gst_message_new_step_start")] #[allow(clippy::new_ret_no_self)] pub fn new( active: bool, amount: impl FormattedValue, rate: f64, flush: bool, intermediate: bool, ) -> Message { skip_assert_initialized!(); Self::builder(active, amount, rate, flush, intermediate).build() } pub fn builder<'a>( active: bool, amount: impl FormattedValue, rate: f64, flush: bool, intermediate: bool, ) -> StepStartBuilder<'a> { assert_initialized_main_thread!(); StepStartBuilder::new(active, amount.into(), rate, flush, intermediate) } #[doc(alias = "gst_message_parse_step_start")] pub fn get(&self) -> (bool, GenericFormattedValue, f64, bool, bool) { unsafe { let mut active = mem::MaybeUninit::uninit(); let mut format = mem::MaybeUninit::uninit(); let mut amount = mem::MaybeUninit::uninit(); let mut rate = mem::MaybeUninit::uninit(); let mut flush = mem::MaybeUninit::uninit(); let mut intermediate = mem::MaybeUninit::uninit(); ffi::gst_message_parse_step_start( self.as_mut_ptr(), active.as_mut_ptr(), format.as_mut_ptr(), amount.as_mut_ptr(), rate.as_mut_ptr(), flush.as_mut_ptr(), intermediate.as_mut_ptr(), ); ( from_glib(active.assume_init()), GenericFormattedValue::new( from_glib(format.assume_init()), amount.assume_init() as i64, ), rate.assume_init(), from_glib(flush.assume_init()), from_glib(intermediate.assume_init()), ) } } } impl std::fmt::Debug for StepStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (active, amount, rate, flush, intermediate) = self.get(); f.debug_struct("StepStart") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("active", &active) .field("amount", &amount) .field("rate", &rate) .field("flush", &flush) .field("intermediate", &intermediate) .finish() } } impl std::fmt::Debug for StepStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StepStart::::fmt(self, f) } } declare_concrete_message!(Qos, T); impl Qos { #[doc(alias = "gst_message_new_qos")] #[allow(clippy::new_ret_no_self)] pub fn new( live: bool, running_time: impl Into>, stream_time: impl Into>, timestamp: impl Into>, duration: impl Into>, ) -> Message { skip_assert_initialized!(); Self::builder(live) .running_time(running_time) .stream_time(stream_time) .timestamp(timestamp) .duration(duration) .build() } pub fn builder<'a>(live: bool) -> QosBuilder<'a> { assert_initialized_main_thread!(); QosBuilder::new(live) } #[doc(alias = "gst_message_parse_qos")] pub fn get( &self, ) -> ( bool, Option, Option, Option, Option, ) { unsafe { let mut live = mem::MaybeUninit::uninit(); let mut running_time = mem::MaybeUninit::uninit(); let mut stream_time = mem::MaybeUninit::uninit(); let mut timestamp = mem::MaybeUninit::uninit(); let mut duration = mem::MaybeUninit::uninit(); ffi::gst_message_parse_qos( self.as_mut_ptr(), live.as_mut_ptr(), running_time.as_mut_ptr(), stream_time.as_mut_ptr(), timestamp.as_mut_ptr(), duration.as_mut_ptr(), ); ( from_glib(live.assume_init()), from_glib(running_time.assume_init()), from_glib(stream_time.assume_init()), from_glib(timestamp.assume_init()), from_glib(duration.assume_init()), ) } } #[doc(alias = "get_values")] #[doc(alias = "gst_message_parse_qos_values")] pub fn values(&self) -> (i64, f64, i32) { unsafe { let mut jitter = mem::MaybeUninit::uninit(); let mut proportion = mem::MaybeUninit::uninit(); let mut quality = mem::MaybeUninit::uninit(); ffi::gst_message_parse_qos_values( self.as_mut_ptr(), jitter.as_mut_ptr(), proportion.as_mut_ptr(), quality.as_mut_ptr(), ); ( jitter.assume_init(), proportion.assume_init(), quality.assume_init(), ) } } #[doc(alias = "get_stats")] #[doc(alias = "gst_message_parse_qos_stats")] pub fn stats(&self) -> (GenericFormattedValue, GenericFormattedValue) { unsafe { let mut format = mem::MaybeUninit::uninit(); let mut processed = mem::MaybeUninit::uninit(); let mut dropped = mem::MaybeUninit::uninit(); ffi::gst_message_parse_qos_stats( self.as_mut_ptr(), format.as_mut_ptr(), processed.as_mut_ptr(), dropped.as_mut_ptr(), ); ( GenericFormattedValue::new( from_glib(format.assume_init()), processed.assume_init() as i64, ), GenericFormattedValue::new( from_glib(format.assume_init()), dropped.assume_init() as i64, ), ) } } } impl std::fmt::Debug for Qos { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (live, running_time, stream_time, timestamp, duration) = self.get(); let (jitter, proportion, quality) = self.values(); let (processed, dropped) = self.stats(); f.debug_struct("Qos") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("live", &live) .field("running-time", &running_time) .field("stream-time", &stream_time) .field("timestamp", ×tamp) .field("duration", &duration) .field("jitter", &jitter) .field("proportion", &proportion) .field("quality", &quality) .field("processed", &processed) .field("dropped", &dropped) .finish() } } impl std::fmt::Debug for Qos { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Qos::::fmt(self, f) } } declare_concrete_message!(Progress, T); impl Progress { #[doc(alias = "gst_message_new_progress")] #[allow(clippy::new_ret_no_self)] pub fn new(type_: crate::ProgressType, code: &str, text: &str) -> Message { skip_assert_initialized!(); Self::builder(type_, code, text).build() } pub fn builder<'a>( type_: crate::ProgressType, code: &'a str, text: &'a str, ) -> ProgressBuilder<'a> { assert_initialized_main_thread!(); ProgressBuilder::new(type_, code, text) } #[doc(alias = "gst_message_parse_progress")] pub fn get(&self) -> (crate::ProgressType, &str, &str) { unsafe { let mut type_ = mem::MaybeUninit::uninit(); let mut code = ptr::null_mut(); let mut text = ptr::null_mut(); ffi::gst_message_parse_progress( self.as_mut_ptr(), type_.as_mut_ptr(), &mut code, &mut text, ); let code = CStr::from_ptr(code).to_str().unwrap(); let text = CStr::from_ptr(text).to_str().unwrap(); (from_glib(type_.assume_init()), code, text) } } } impl std::fmt::Debug for Progress { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (type_, code, text) = self.get(); f.debug_struct("Progress") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("type", &type_) .field("code", &code) .field("text", &text) .finish() } } impl std::fmt::Debug for Progress { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Progress::::fmt(self, f) } } declare_concrete_message!(Toc, T); impl Toc { // FIXME could use false for updated as default // Even better: use an enum for updated so that it is more explicit than true / false #[doc(alias = "gst_message_new_toc")] #[allow(clippy::new_ret_no_self)] pub fn new(toc: &crate::Toc, updated: bool) -> Message { skip_assert_initialized!(); Self::builder(toc, updated).build() } pub fn builder(toc: &crate::Toc, updated: bool) -> TocBuilder { assert_initialized_main_thread!(); TocBuilder::new(toc, updated) } #[doc(alias = "get_toc")] #[doc(alias = "gst_message_parse_toc")] pub fn toc(&self) -> (crate::Toc, bool) { unsafe { let mut toc = ptr::null_mut(); let mut updated = mem::MaybeUninit::uninit(); ffi::gst_message_parse_toc(self.as_mut_ptr(), &mut toc, updated.as_mut_ptr()); (from_glib_full(toc), from_glib(updated.assume_init())) } } } impl std::fmt::Debug for Toc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Toc") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("toc", &self.toc()) .finish() } } impl std::fmt::Debug for Toc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Toc::::fmt(self, f) } } declare_concrete_message!(ResetTime, T); impl ResetTime { #[doc(alias = "gst_message_new_reset_time")] #[allow(clippy::new_ret_no_self)] pub fn new(running_time: crate::ClockTime) -> Message { skip_assert_initialized!(); Self::builder(running_time).build() } pub fn builder<'a>(running_time: crate::ClockTime) -> ResetTimeBuilder<'a> { assert_initialized_main_thread!(); ResetTimeBuilder::new(running_time) } #[doc(alias = "get_running_time")] #[doc(alias = "gst_message_parse_reset_time")] pub fn running_time(&self) -> crate::ClockTime { unsafe { let mut running_time = mem::MaybeUninit::uninit(); ffi::gst_message_parse_reset_time(self.as_mut_ptr(), running_time.as_mut_ptr()); try_from_glib(running_time.assume_init()).expect("undefined running_time") } } } impl std::fmt::Debug for ResetTime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ResetTime") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("running-time", &self.running_time()) .finish() } } impl std::fmt::Debug for ResetTime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ResetTime::::fmt(self, f) } } declare_concrete_message!(StreamStart, T); impl StreamStart { #[doc(alias = "gst_message_new_stream_start")] #[allow(clippy::new_ret_no_self)] pub fn new() -> Message { skip_assert_initialized!(); Self::builder().build() } pub fn builder<'a>() -> StreamStartBuilder<'a> { assert_initialized_main_thread!(); StreamStartBuilder::new() } #[doc(alias = "get_group_id")] #[doc(alias = "gst_message_parse_group_id")] pub fn group_id(&self) -> Option { unsafe { let mut group_id = mem::MaybeUninit::uninit(); if from_glib(ffi::gst_message_parse_group_id( self.as_mut_ptr(), group_id.as_mut_ptr(), )) { let group_id = group_id.assume_init(); if group_id == 0 { None } else { Some(GroupId(NonZeroU32::new_unchecked(group_id))) } } else { None } } } #[doc(alias = "gst_message_set_group_id")] pub fn set_group_id(&mut self, group_id: GroupId) { unsafe { ffi::gst_message_set_group_id(self.as_mut_ptr(), group_id.0.get()); } } } impl std::fmt::Debug for StreamStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StreamStart") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("group-id", &self.group_id()) .finish() } } impl std::fmt::Debug for StreamStart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StreamStart::::fmt(self, f) } } declare_concrete_message!(NeedContext, T); impl NeedContext { #[doc(alias = "gst_message_new_need_context")] #[allow(clippy::new_ret_no_self)] pub fn new(context_type: &str) -> Message { skip_assert_initialized!(); Self::builder(context_type).build() } pub fn builder(context_type: &str) -> NeedContextBuilder { assert_initialized_main_thread!(); NeedContextBuilder::new(context_type) } #[doc(alias = "get_context_type")] #[doc(alias = "gst_message_parse_context_type")] pub fn context_type(&self) -> &str { unsafe { let mut context_type = ptr::null(); ffi::gst_message_parse_context_type(self.as_mut_ptr(), &mut context_type); CStr::from_ptr(context_type).to_str().unwrap() } } } impl std::fmt::Debug for NeedContext { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("NeedContext") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("context-type", &self.context_type()) .finish() } } impl std::fmt::Debug for NeedContext { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { NeedContext::::fmt(self, f) } } declare_concrete_message!(HaveContext, T); impl HaveContext { #[doc(alias = "gst_message_new_have_context")] #[allow(clippy::new_ret_no_self)] pub fn new(context: crate::Context) -> Message { skip_assert_initialized!(); Self::builder(context).build() } pub fn builder<'a>(context: crate::Context) -> HaveContextBuilder<'a> { assert_initialized_main_thread!(); HaveContextBuilder::new(context) } #[doc(alias = "get_context")] #[doc(alias = "gst_message_parse_have_context")] pub fn context(&self) -> crate::Context { unsafe { let mut context = ptr::null_mut(); ffi::gst_message_parse_have_context(self.as_mut_ptr(), &mut context); from_glib_full(context) } } } impl std::fmt::Debug for HaveContext { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("HaveContext") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("context", &self.context()) .finish() } } impl std::fmt::Debug for HaveContext { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { HaveContext::::fmt(self, f) } } declare_concrete_message!(DeviceAdded, T); impl DeviceAdded { #[doc(alias = "gst_message_new_device_added")] #[allow(clippy::new_ret_no_self)] pub fn new(device: &crate::Device) -> Message { skip_assert_initialized!(); Self::builder(device).build() } pub fn builder(device: &crate::Device) -> DeviceAddedBuilder { assert_initialized_main_thread!(); DeviceAddedBuilder::new(device) } #[doc(alias = "get_device")] #[doc(alias = "gst_message_parse_device_added")] pub fn device(&self) -> crate::Device { unsafe { let mut device = ptr::null_mut(); ffi::gst_message_parse_device_added(self.as_mut_ptr(), &mut device); from_glib_full(device) } } } impl std::fmt::Debug for DeviceAdded { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DeviceAdded") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("device", &self.device()) .finish() } } impl std::fmt::Debug for DeviceAdded { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { DeviceAdded::::fmt(self, f) } } declare_concrete_message!(DeviceRemoved, T); impl DeviceRemoved { #[doc(alias = "gst_message_new_device_removed")] #[allow(clippy::new_ret_no_self)] pub fn new(device: &crate::Device) -> Message { skip_assert_initialized!(); Self::builder(device).build() } pub fn builder(device: &crate::Device) -> DeviceRemovedBuilder { assert_initialized_main_thread!(); DeviceRemovedBuilder::new(device) } #[doc(alias = "get_device")] #[doc(alias = "gst_message_parse_device_removed")] pub fn device(&self) -> crate::Device { unsafe { let mut device = ptr::null_mut(); ffi::gst_message_parse_device_removed(self.as_mut_ptr(), &mut device); from_glib_full(device) } } } impl std::fmt::Debug for DeviceRemoved { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DeviceRemoved") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("device", &self.device()) .finish() } } impl std::fmt::Debug for DeviceRemoved { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { DeviceRemoved::::fmt(self, f) } } declare_concrete_message!(PropertyNotify, T); impl PropertyNotify { #[doc(alias = "gst_message_new_property_notify")] #[allow(clippy::new_ret_no_self)] pub fn new(object: &impl IsA, property_name: &str) -> Message { skip_assert_initialized!(); Self::builder(object, property_name).build() } pub fn builder<'a>( object: &'a impl IsA, property_name: &'a str, ) -> PropertyNotifyBuilder<'a> { assert_initialized_main_thread!(); PropertyNotifyBuilder::new(property_name).src(object) } #[doc(alias = "gst_message_parse_property_notify")] pub fn get(&self) -> (Object, &str, Option<&glib::Value>) { unsafe { let mut object = ptr::null_mut(); let mut property_name = ptr::null(); let mut value = ptr::null(); ffi::gst_message_parse_property_notify( self.as_mut_ptr(), &mut object, &mut property_name, &mut value, ); ( from_glib_none(object), CStr::from_ptr(property_name).to_str().unwrap(), if value.is_null() { None } else { Some(&*(value as *const glib::Value)) }, ) } } } impl std::fmt::Debug for PropertyNotify { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (object, property_name, value) = self.get(); f.debug_struct("PropertyNotify") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("object", &object) .field("property-name", &property_name) .field("value", &value) .finish() } } impl std::fmt::Debug for PropertyNotify { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { PropertyNotify::::fmt(self, f) } } declare_concrete_message!(StreamCollection, T); impl StreamCollection { #[doc(alias = "gst_message_new_stream_collection")] #[allow(clippy::new_ret_no_self)] pub fn new(collection: &crate::StreamCollection) -> Message { skip_assert_initialized!(); Self::builder(collection).build() } pub fn builder(collection: &crate::StreamCollection) -> StreamCollectionBuilder { assert_initialized_main_thread!(); StreamCollectionBuilder::new(collection) } #[doc(alias = "get_stream_collection")] #[doc(alias = "gst_message_parse_stream_collection")] pub fn stream_collection(&self) -> crate::StreamCollection { unsafe { let mut collection = ptr::null_mut(); ffi::gst_message_parse_stream_collection(self.as_mut_ptr(), &mut collection); from_glib_full(collection) } } } impl std::fmt::Debug for StreamCollection { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StreamCollection") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("stream-collection", &self.stream_collection()) .finish() } } impl std::fmt::Debug for StreamCollection { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StreamCollection::::fmt(self, f) } } declare_concrete_message!(StreamsSelected, T); impl StreamsSelected { #[doc(alias = "gst_message_new_streams_selected")] #[allow(clippy::new_ret_no_self)] pub fn new(collection: &crate::StreamCollection) -> Message { skip_assert_initialized!(); Self::builder(collection).build() } pub fn builder(collection: &crate::StreamCollection) -> StreamsSelectedBuilder { assert_initialized_main_thread!(); StreamsSelectedBuilder::new(collection) } #[doc(alias = "get_stream_collection")] #[doc(alias = "gst_message_parse_streams_selected")] pub fn stream_collection(&self) -> crate::StreamCollection { unsafe { let mut collection = ptr::null_mut(); ffi::gst_message_parse_streams_selected(self.as_mut_ptr(), &mut collection); from_glib_full(collection) } } #[doc(alias = "get_streams")] #[doc(alias = "gst_message_streams_selected_get_size")] #[doc(alias = "gst_message_streams_selected_get_stream")] pub fn streams(&self) -> Vec { unsafe { let n = ffi::gst_message_streams_selected_get_size(self.as_mut_ptr()); (0..n) .map(|i| { from_glib_full(ffi::gst_message_streams_selected_get_stream( self.as_mut_ptr(), i, )) }) .collect() } } } impl std::fmt::Debug for StreamsSelected { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("StreamsSelected") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("stream-collection", &self.stream_collection()) .field("streams", &self.streams()) .finish() } } impl std::fmt::Debug for StreamsSelected { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { StreamsSelected::::fmt(self, f) } } declare_concrete_message!(Redirect, T); impl Redirect { #[doc(alias = "gst_message_new_redirect")] #[allow(clippy::new_ret_no_self)] pub fn new(location: &str) -> Message { skip_assert_initialized!(); Self::builder(location).build() } pub fn builder(location: &str) -> RedirectBuilder { assert_initialized_main_thread!(); RedirectBuilder::new(location) } #[doc(alias = "get_entries")] #[doc(alias = "gst_message_get_num_redirect_entries")] #[doc(alias = "gst_message_parse_redirect_entry")] pub fn entries(&self) -> Vec<(&str, Option, Option<&StructureRef>)> { unsafe { let n = ffi::gst_message_get_num_redirect_entries(self.as_mut_ptr()); (0..n) .map(|i| { let mut location = ptr::null(); let mut tags = ptr::null_mut(); let mut structure = ptr::null(); ffi::gst_message_parse_redirect_entry( self.as_mut_ptr(), i, &mut location, &mut tags, &mut structure, ); let structure = if structure.is_null() { None } else { Some(StructureRef::from_glib_borrow(structure)) }; ( CStr::from_ptr(location).to_str().unwrap(), from_glib_none(tags), structure, ) }) .collect() } } } impl std::fmt::Debug for Redirect { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Redirect") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("entries", &self.entries()) .finish() } } impl std::fmt::Debug for Redirect { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Redirect::::fmt(self, f) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] declare_concrete_message!(DeviceChanged, T); #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] impl DeviceChanged { #[doc(alias = "gst_message_new_device_changed")] #[allow(clippy::new_ret_no_self)] pub fn new(device: &crate::Device, changed_device: &crate::Device) -> Message { skip_assert_initialized!(); Self::builder(device, changed_device).build() } pub fn builder<'a>( device: &'a crate::Device, changed_device: &'a crate::Device, ) -> DeviceChangedBuilder<'a> { assert_initialized_main_thread!(); DeviceChangedBuilder::new(device, changed_device) } #[doc(alias = "get_device_changed")] #[doc(alias = "gst_message_parse_device_changed")] pub fn device_changed(&self) -> (crate::Device, crate::Device) { unsafe { let mut device = ptr::null_mut(); let mut changed_device = ptr::null_mut(); ffi::gst_message_parse_device_changed( self.as_mut_ptr(), &mut device, &mut changed_device, ); (from_glib_full(device), from_glib_full(changed_device)) } } } #[cfg(feature = "v1_16")] impl std::fmt::Debug for DeviceChanged { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DeviceChanged") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("device-changed", &self.device_changed()) .finish() } } #[cfg(feature = "v1_16")] impl std::fmt::Debug for DeviceChanged { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { DeviceChanged::::fmt(self, f) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] declare_concrete_message!(InstantRateRequest, T); #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl InstantRateRequest { #[doc(alias = "gst_message_new_instant_rate_request")] #[allow(clippy::new_ret_no_self)] pub fn new(rate_multiplier: f64) -> Message { skip_assert_initialized!(); Self::builder(rate_multiplier).build() } pub fn builder<'a>(rate_multiplier: f64) -> InstantRateRequestBuilder<'a> { assert_initialized_main_thread!(); InstantRateRequestBuilder::new(rate_multiplier) } #[doc(alias = "parse_instant_rate_request")] #[doc(alias = "gst_message_parse_instant_rate_request")] pub fn rate_multiplier(&self) -> f64 { unsafe { let mut rate_multiplier = mem::MaybeUninit::uninit(); ffi::gst_message_parse_instant_rate_request( self.as_mut_ptr(), rate_multiplier.as_mut_ptr(), ); rate_multiplier.assume_init() } } } #[cfg(feature = "v1_18")] impl std::fmt::Debug for InstantRateRequest { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("InstantRateRequest") .field("structure", &self.message().structure()) .field("source", &self.src().map(|obj| (obj, obj.name()))) .field("rate-multiplier", &self.rate_multiplier()) .finish() } } #[cfg(feature = "v1_18")] impl std::fmt::Debug for InstantRateRequest { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { InstantRateRequest::::fmt(self, f) } } struct MessageBuilder<'a> { src: Option, seqnum: Option, #[cfg(feature = "v1_26")] details: Option, other_fields: Vec<(&'a str, glib::SendValue)>, } impl<'a> MessageBuilder<'a> { fn new() -> Self { Self { src: None, seqnum: None, #[cfg(feature = "v1_26")] details: None, other_fields: Vec::new(), } } pub fn src + Cast + Clone>(self, src: &O) -> Self { Self { src: Some(src.clone().upcast::()), ..self } } fn seqnum(self, seqnum: Seqnum) -> Self { Self { seqnum: Some(seqnum), ..self } } #[cfg(feature = "v1_26")] fn details(self, details: Structure) -> Self { Self { details: Some(details), ..self } } fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self { let mut other_fields = self.other_fields; other_fields.push((name, value.to_send_value())); Self { other_fields, ..self } } fn other_fields(self, other_fields: &[(&'a str, &'a (dyn ToSendValue + Sync))]) -> Self { let mut s = self; for (name, value) in other_fields { s = s.other_field(name, value.to_send_value()); } s } } macro_rules! message_builder_generic_impl { ($new_fn:expr) => { #[allow(clippy::needless_update)] pub fn src + Cast + Clone>(self, src: &O) -> Self { Self { builder: self.builder.src(src), ..self } } #[allow(clippy::needless_update)] pub fn src_if + Cast + Clone>(self, src: &O, predicate: bool) -> Self { if predicate { self.src(src) } else { self } } #[allow(clippy::needless_update)] pub fn src_if_some + Cast + Clone>(self, src: Option<&O>) -> Self { if let Some(src) = src { self.src(src) } else { self } } #[doc(alias = "gst_message_set_seqnum")] #[allow(clippy::needless_update)] pub fn seqnum(self, seqnum: Seqnum) -> Self { Self { builder: self.builder.seqnum(seqnum), ..self } } #[doc(alias = "gst_message_set_seqnum")] #[allow(clippy::needless_update)] pub fn seqnum_if(self, seqnum: Seqnum, predicate: bool) -> Self { if predicate { self.seqnum(seqnum) } else { self } } #[doc(alias = "gst_message_set_seqnum")] #[allow(clippy::needless_update)] pub fn seqnum_if_some(self, seqnum: Option) -> Self { if let Some(seqnum) = seqnum { self.seqnum(seqnum) } else { self } } #[cfg(feature = "v1_26")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))] #[doc(alias = "gst_message_set_details")] #[allow(clippy::needless_update)] pub fn details(self, details: Structure) -> Self { Self { builder: self.builder.details(details), ..self } } #[cfg(feature = "v1_26")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))] #[doc(alias = "gst_message_set_details")] #[allow(clippy::needless_update)] pub fn details_if(self, details: Structure, predicate: bool) -> Self { if predicate { self.details(details) } else { self } } #[cfg(feature = "v1_26")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_26")))] #[doc(alias = "gst_message_set_details")] #[allow(clippy::needless_update)] pub fn details_if_some(self, details: Option) -> Self { if let Some(details) = details { self.details(details) } else { self } } // rustdoc-stripper-ignore-next /// Sets field `name` to the given value `value`. /// /// Overrides any default or previously defined value for `name`. #[allow(clippy::needless_update)] pub fn other_field(self, name: &'a str, value: impl ToSendValue) -> Self { Self { builder: self.builder.other_field(name, value), ..self } } impl_builder_gvalue_extra_setters!(other_field); #[deprecated = "use build.other_field() instead"] #[allow(clippy::needless_update)] pub fn other_fields( self, other_fields: &[(&'a str, &'a (dyn ToSendValue + Sync))], ) -> Self { Self { builder: self.builder.other_fields(other_fields), ..self } } #[must_use = "Building the message without using it has no effect"] #[allow(clippy::redundant_closure_call)] pub fn build(mut self) -> Message { unsafe { let src = self.builder.src.to_glib_none().0; let msg = $new_fn(&mut self, src); if let Some(seqnum) = self.builder.seqnum { ffi::gst_message_set_seqnum(msg, seqnum.0.get()); } #[cfg(feature = "v1_26")] if let Some(details) = self.builder.details { ffi::gst_message_set_details(msg, details.into_glib_ptr()); } if !self.builder.other_fields.is_empty() { let structure = ffi::gst_message_writable_structure(msg); if !structure.is_null() { let structure = StructureRef::from_glib_borrow_mut(structure as *mut _); for (k, v) in self.builder.other_fields { structure.set_value(k, v); } } } from_glib_full(msg) } } }; } #[must_use = "The builder must be built to be used"] pub struct EosBuilder<'a> { builder: MessageBuilder<'a>, } impl<'a> EosBuilder<'a> { fn new() -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), } } message_builder_generic_impl!(|_, src| ffi::gst_message_new_eos(src)); } pub trait MessageErrorDomain: glib::error::ErrorDomain {} impl MessageErrorDomain for crate::CoreError {} impl MessageErrorDomain for crate::ResourceError {} impl MessageErrorDomain for crate::StreamError {} impl MessageErrorDomain for crate::LibraryError {} #[must_use = "The builder must be built to be used"] pub struct ErrorBuilder<'a> { builder: MessageBuilder<'a>, error: glib::Error, debug: Option<&'a str>, #[allow(unused)] details: Option, } impl<'a> ErrorBuilder<'a> { fn new(error: glib::Error) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), error, debug: None, details: None, } } pub fn debug(self, debug: &'a str) -> Self { Self { debug: Some(debug), ..self } } pub fn debug_if(self, debug: &'a str, predicate: bool) -> Self { if predicate { self.debug(debug) } else { self } } pub fn debug_if_some(self, debug: Option<&'a str>) -> Self { if let Some(debug) = debug { self.debug(debug) } else { self } } #[cfg(not(feature = "v1_26"))] pub fn details(self, details: Structure) -> Self { Self { details: Some(details), ..self } } #[cfg(not(feature = "v1_26"))] pub fn details_if(self, details: Structure, predicate: bool) -> Self { if predicate { self.details(details) } else { self } } #[cfg(not(feature = "v1_26"))] pub fn details_if_some(self, details: Option) -> Self { if let Some(details) = details { self.details(details) } else { self } } message_builder_generic_impl!(|s: &mut Self, src| { let details = match s.details.take() { None => ptr::null_mut(), Some(details) => details.into_glib_ptr(), }; ffi::gst_message_new_error_with_details( src, mut_override(s.error.to_glib_none().0), s.debug.to_glib_none().0, details, ) }); } #[must_use = "The builder must be built to be used"] pub struct WarningBuilder<'a> { builder: MessageBuilder<'a>, error: glib::Error, debug: Option<&'a str>, #[allow(unused)] details: Option, } impl<'a> WarningBuilder<'a> { fn new(error: glib::Error) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), error, debug: None, details: None, } } pub fn debug(self, debug: &'a str) -> Self { Self { debug: Some(debug), ..self } } pub fn debug_if(self, debug: &'a str, predicate: bool) -> Self { if predicate { self.debug(debug) } else { self } } pub fn debug_if_some(self, debug: Option<&'a str>) -> Self { if let Some(debug) = debug { self.debug(debug) } else { self } } #[cfg(not(feature = "v1_26"))] pub fn details(self, details: Structure) -> Self { Self { details: Some(details), ..self } } #[cfg(not(feature = "v1_26"))] pub fn details_if(self, details: Structure, predicate: bool) -> Self { if predicate { self.details(details) } else { self } } #[cfg(not(feature = "v1_26"))] pub fn details_if_some(self, details: Option) -> Self { if let Some(details) = details { self.details(details) } else { self } } message_builder_generic_impl!(|s: &mut Self, src| { let details = match s.details.take() { None => ptr::null_mut(), Some(details) => details.into_glib_ptr(), }; ffi::gst_message_new_warning_with_details( src, mut_override(s.error.to_glib_none().0), s.debug.to_glib_none().0, details, ) }); } #[must_use = "The builder must be built to be used"] pub struct InfoBuilder<'a> { builder: MessageBuilder<'a>, error: glib::Error, debug: Option<&'a str>, #[allow(unused)] details: Option, } impl<'a> InfoBuilder<'a> { fn new(error: glib::Error) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), error, debug: None, details: None, } } pub fn debug(self, debug: &'a str) -> Self { Self { debug: Some(debug), ..self } } pub fn debug_if(self, debug: &'a str, predicate: bool) -> Self { if predicate { self.debug(debug) } else { self } } pub fn debug_if_some(self, debug: Option<&'a str>) -> Self { if let Some(debug) = debug { self.debug(debug) } else { self } } #[cfg(not(feature = "v1_26"))] pub fn details(self, details: Structure) -> Self { Self { details: Some(details), ..self } } #[cfg(not(feature = "v1_26"))] pub fn details_if(self, details: Structure, predicate: bool) -> Self { if predicate { self.details(details) } else { self } } #[cfg(not(feature = "v1_26"))] pub fn details_if_some(self, details: Option) -> Self { if let Some(details) = details { self.details(details) } else { self } } message_builder_generic_impl!(|s: &mut Self, src| { let details = match s.details.take() { None => ptr::null_mut(), Some(details) => details.into_glib_ptr(), }; ffi::gst_message_new_info_with_details( src, mut_override(s.error.to_glib_none().0), s.debug.to_glib_none().0, details, ) }); } #[must_use = "The builder must be built to be used"] pub struct TagBuilder<'a> { builder: MessageBuilder<'a>, tags: &'a TagList, } impl<'a> TagBuilder<'a> { fn new(tags: &'a TagList) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), tags, } } message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_tag( src, s.tags.to_glib_full() )); } #[must_use = "The builder must be built to be used"] pub struct BufferingBuilder<'a> { builder: MessageBuilder<'a>, percent: i32, stats: Option<(crate::BufferingMode, i32, i32, i64)>, } impl<'a> BufferingBuilder<'a> { fn new(percent: i32) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), percent, stats: None, } } pub fn stats( self, mode: crate::BufferingMode, avg_in: i32, avg_out: i32, buffering_left: i64, ) -> Self { skip_assert_initialized!(); Self { stats: Some((mode, avg_in, avg_out, buffering_left)), ..self } } message_builder_generic_impl!(|s: &mut Self, src| { let msg = ffi::gst_message_new_buffering(src, s.percent); if let Some((mode, avg_in, avg_out, buffering_left)) = s.stats { ffi::gst_message_set_buffering_stats( msg, mode.into_glib(), avg_in, avg_out, buffering_left, ); } msg }); } #[must_use = "The builder must be built to be used"] pub struct StateChangedBuilder<'a> { builder: MessageBuilder<'a>, old: crate::State, new: crate::State, pending: crate::State, } impl<'a> StateChangedBuilder<'a> { fn new(old: crate::State, new: crate::State, pending: crate::State) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), old, new, pending, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_state_changed( src, s.old.into_glib(), s.new.into_glib(), s.pending.into_glib(), )); } #[must_use = "The builder must be built to be used"] pub struct StateDirtyBuilder<'a> { builder: MessageBuilder<'a>, } impl<'a> StateDirtyBuilder<'a> { fn new() -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), } } message_builder_generic_impl!(|_, src| ffi::gst_message_new_state_dirty(src)); } #[must_use = "The builder must be built to be used"] pub struct StepDoneBuilder<'a> { builder: MessageBuilder<'a>, amount: GenericFormattedValue, rate: f64, flush: bool, intermediate: bool, duration: Option, eos: bool, } impl<'a> StepDoneBuilder<'a> { fn new( amount: GenericFormattedValue, rate: f64, flush: bool, intermediate: bool, duration: Option, eos: bool, ) -> Self { skip_assert_initialized!(); assert_eq!(amount.format(), duration.format()); Self { builder: MessageBuilder::new(), amount, rate, flush, intermediate, duration, eos, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_step_done( src, s.amount.format().into_glib(), s.amount.value() as u64, s.rate, s.flush.into_glib(), s.intermediate.into_glib(), s.duration.into_raw_value() as u64, s.eos.into_glib(), )); } #[must_use = "The builder must be built to be used"] pub struct ClockProvideBuilder<'a> { builder: MessageBuilder<'a>, clock: &'a crate::Clock, ready: bool, } impl<'a> ClockProvideBuilder<'a> { fn new(clock: &'a crate::Clock, ready: bool) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), clock, ready, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_clock_provide( src, s.clock.to_glib_none().0, s.ready.into_glib() )); } #[must_use = "The builder must be built to be used"] pub struct ClockLostBuilder<'a> { builder: MessageBuilder<'a>, clock: &'a crate::Clock, } impl<'a> ClockLostBuilder<'a> { fn new(clock: &'a crate::Clock) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), clock, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_clock_lost( src, s.clock.to_glib_none().0 )); } #[must_use = "The builder must be built to be used"] pub struct NewClockBuilder<'a> { builder: MessageBuilder<'a>, clock: &'a crate::Clock, } impl<'a> NewClockBuilder<'a> { fn new(clock: &'a crate::Clock) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), clock, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_new_clock( src, s.clock.to_glib_none().0 )); } #[must_use = "The builder must be built to be used"] pub struct StructureChangeBuilder<'a> { builder: MessageBuilder<'a>, type_: crate::StructureChangeType, owner: &'a crate::Element, busy: bool, } impl<'a> StructureChangeBuilder<'a> { fn new(type_: crate::StructureChangeType, owner: &'a crate::Element, busy: bool) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), type_, owner, busy, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_structure_change( src, s.type_.into_glib(), s.owner.to_glib_none().0, s.busy.into_glib(), )); } #[must_use = "The builder must be built to be used"] pub struct StreamStatusBuilder<'a> { builder: MessageBuilder<'a>, type_: crate::StreamStatusType, owner: &'a crate::Element, status_object: Option, } impl<'a> StreamStatusBuilder<'a> { fn new(type_: crate::StreamStatusType, owner: &'a crate::Element) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), type_, owner, status_object: None, } } pub fn status_object(self, status_object: impl ToSendValue) -> Self { Self { status_object: Some(status_object.to_send_value()), ..self } } pub fn status_object_if(self, status_object: impl ToSendValue, predicate: bool) -> Self { if predicate { self.status_object(status_object) } else { self } } pub fn status_object_if_some(self, status_object: Option) -> Self { if let Some(status_object) = status_object { self.status_object(status_object) } else { self } } message_builder_generic_impl!(|s: &mut Self, src| { let msg = ffi::gst_message_new_stream_status(src, s.type_.into_glib(), s.owner.to_glib_none().0); if let Some(ref status_object) = s.status_object { ffi::gst_message_set_stream_status_object(msg, status_object.to_glib_none().0); } msg }); } #[must_use = "The builder must be built to be used"] pub struct ApplicationBuilder<'a> { builder: MessageBuilder<'a>, structure: Option, } impl<'a> ApplicationBuilder<'a> { fn new(structure: crate::Structure) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), structure: Some(structure), } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_application( src, s.structure.take().unwrap().into_glib_ptr() )); } #[must_use = "The builder must be built to be used"] pub struct ElementBuilder<'a> { builder: MessageBuilder<'a>, structure: Option, } impl<'a> ElementBuilder<'a> { fn new(structure: crate::Structure) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), structure: Some(structure), } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_element( src, s.structure.take().unwrap().into_glib_ptr() )); } #[must_use = "The builder must be built to be used"] pub struct SegmentStartBuilder<'a> { builder: MessageBuilder<'a>, position: GenericFormattedValue, } impl<'a> SegmentStartBuilder<'a> { fn new(position: GenericFormattedValue) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), position, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_segment_start( src, s.position.format().into_glib(), s.position.value(), )); } #[must_use = "The builder must be built to be used"] pub struct SegmentDoneBuilder<'a> { builder: MessageBuilder<'a>, position: GenericFormattedValue, } impl<'a> SegmentDoneBuilder<'a> { fn new(position: GenericFormattedValue) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), position, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_segment_done( src, s.position.format().into_glib(), s.position.value(), )); } #[must_use = "The builder must be built to be used"] pub struct DurationChangedBuilder<'a> { builder: MessageBuilder<'a>, } impl<'a> DurationChangedBuilder<'a> { fn new() -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), } } message_builder_generic_impl!(|_, src| ffi::gst_message_new_duration_changed(src)); } #[must_use = "The builder must be built to be used"] pub struct LatencyBuilder<'a> { builder: MessageBuilder<'a>, } impl<'a> LatencyBuilder<'a> { fn new() -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), } } message_builder_generic_impl!(|_, src| ffi::gst_message_new_latency(src)); } #[must_use = "The builder must be built to be used"] pub struct AsyncStartBuilder<'a> { builder: MessageBuilder<'a>, } impl<'a> AsyncStartBuilder<'a> { fn new() -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), } } message_builder_generic_impl!(|_, src| ffi::gst_message_new_async_start(src)); } #[must_use = "The builder must be built to be used"] pub struct AsyncDoneBuilder<'a> { builder: MessageBuilder<'a>, running_time: Option, } impl<'a> AsyncDoneBuilder<'a> { fn new() -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), running_time: None, } } pub fn running_time(mut self, running_time: impl Into>) -> Self { self.running_time = running_time.into(); self } pub fn running_time_if(self, running_time: crate::ClockTime, predicate: bool) -> Self { if predicate { self.running_time(running_time) } else { self } } pub fn running_time_if_some(self, running_time: Option) -> Self { if let Some(running_time) = running_time { self.running_time(running_time) } else { self } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_async_done( src, s.running_time.into_glib() )); } #[must_use = "The builder must be built to be used"] pub struct RequestStateBuilder<'a> { builder: MessageBuilder<'a>, state: crate::State, } impl<'a> RequestStateBuilder<'a> { fn new(state: crate::State) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), state, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_request_state( src, s.state.into_glib() )); } #[must_use = "The builder must be built to be used"] pub struct StepStartBuilder<'a> { builder: MessageBuilder<'a>, active: bool, amount: GenericFormattedValue, rate: f64, flush: bool, intermediate: bool, } impl<'a> StepStartBuilder<'a> { fn new( active: bool, amount: GenericFormattedValue, rate: f64, flush: bool, intermediate: bool, ) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), active, amount, rate, flush, intermediate, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_step_start( src, s.active.into_glib(), s.amount.format().into_glib(), s.amount.value() as u64, s.rate, s.flush.into_glib(), s.intermediate.into_glib(), )); } #[must_use = "The builder must be built to be used"] pub struct QosBuilder<'a> { builder: MessageBuilder<'a>, live: bool, running_time: Option, stream_time: Option, timestamp: Option, duration: Option, values: Option<(i64, f64, i32)>, stats: Option<(GenericFormattedValue, GenericFormattedValue)>, } impl<'a> QosBuilder<'a> { fn new(live: bool) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), live, running_time: None, stream_time: None, timestamp: None, duration: None, values: None, stats: None, } } pub fn running_time(mut self, running_time: impl Into>) -> Self { self.running_time = running_time.into(); self } pub fn running_time_if(self, running_time: crate::ClockTime, predicate: bool) -> Self { if predicate { self.running_time(running_time) } else { self } } pub fn running_time_if_some(self, running_time: Option) -> Self { if let Some(running_time) = running_time { self.running_time(running_time) } else { self } } pub fn stream_time(mut self, stream_time: impl Into>) -> Self { self.stream_time = stream_time.into(); self } pub fn stream_time_if(self, stream_time: crate::ClockTime, predicate: bool) -> Self { if predicate { self.stream_time(stream_time) } else { self } } pub fn stream_time_if_some(self, stream_time: Option) -> Self { if let Some(stream_time) = stream_time { self.stream_time(stream_time) } else { self } } pub fn timestamp(mut self, timestamp: impl Into>) -> Self { self.timestamp = timestamp.into(); self } pub fn timestamp_if(self, timestamp: crate::ClockTime, predicate: bool) -> Self { if predicate { self.timestamp(timestamp) } else { self } } pub fn timestamp_if_some(self, timestamp: Option) -> Self { if let Some(timestamp) = timestamp { self.timestamp(timestamp) } else { self } } pub fn duration(mut self, duration: impl Into>) -> Self { self.duration = duration.into(); self } pub fn duration_if(self, duration: crate::ClockTime, predicate: bool) -> Self { if predicate { self.duration(duration) } else { self } } pub fn duration_if_some(self, duration: Option) -> Self { if let Some(duration) = duration { self.duration(duration) } else { self } } pub fn values(self, jitter: i64, proportion: f64, quality: i32) -> Self { Self { values: Some((jitter, proportion, quality)), ..self } } pub fn stats( self, processed: V, dropped: impl CompatibleFormattedValue, ) -> Self { let dropped = dropped.try_into_checked(processed).unwrap(); Self { stats: Some((processed.into(), dropped.into())), ..self } } message_builder_generic_impl!(|s: &mut Self, src| { let msg = ffi::gst_message_new_qos( src, s.live.into_glib(), s.running_time.into_glib(), s.stream_time.into_glib(), s.timestamp.into_glib(), s.duration.into_glib(), ); if let Some((jitter, proportion, quality)) = s.values { ffi::gst_message_set_qos_values(msg, jitter, proportion, quality); } if let Some((processed, dropped)) = s.stats { ffi::gst_message_set_qos_stats( msg, processed.format().into_glib(), processed.value() as u64, dropped.value() as u64, ); } msg }); } #[must_use = "The builder must be built to be used"] pub struct ProgressBuilder<'a> { builder: MessageBuilder<'a>, type_: crate::ProgressType, code: &'a str, text: &'a str, } impl<'a> ProgressBuilder<'a> { fn new(type_: crate::ProgressType, code: &'a str, text: &'a str) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), type_, code, text, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_progress( src, s.type_.into_glib(), s.code.to_glib_none().0, s.text.to_glib_none().0, )); } #[must_use = "The builder must be built to be used"] pub struct TocBuilder<'a> { builder: MessageBuilder<'a>, toc: &'a crate::Toc, updated: bool, } impl<'a> TocBuilder<'a> { fn new(toc: &'a crate::Toc, updated: bool) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), toc, updated, } } message_builder_generic_impl!(|s: &Self, src| ffi::gst_message_new_toc( src, s.toc.to_glib_none().0, s.updated.into_glib() )); } #[must_use = "The builder must be built to be used"] pub struct ResetTimeBuilder<'a> { builder: MessageBuilder<'a>, running_time: crate::ClockTime, } impl<'a> ResetTimeBuilder<'a> { fn new(running_time: crate::ClockTime) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), running_time, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_reset_time( src, s.running_time.into_glib() )); } #[must_use = "The builder must be built to be used"] pub struct StreamStartBuilder<'a> { builder: MessageBuilder<'a>, group_id: Option, } impl<'a> StreamStartBuilder<'a> { fn new() -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), group_id: None, } } pub fn group_id(self, group_id: GroupId) -> Self { Self { group_id: Some(group_id), ..self } } pub fn group_id_if(self, group_id: GroupId, predicate: bool) -> Self { if predicate { self.group_id(group_id) } else { self } } pub fn group_id_if_some(self, group_id: Option) -> Self { if let Some(group_id) = group_id { self.group_id(group_id) } else { self } } message_builder_generic_impl!(|s: &mut Self, src| { let msg = ffi::gst_message_new_stream_start(src); if let Some(group_id) = s.group_id { ffi::gst_message_set_group_id(msg, group_id.0.get()); } msg }); } #[must_use = "The builder must be built to be used"] pub struct NeedContextBuilder<'a> { builder: MessageBuilder<'a>, context_type: &'a str, } impl<'a> NeedContextBuilder<'a> { fn new(context_type: &'a str) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), context_type, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_need_context( src, s.context_type.to_glib_none().0 )); } #[must_use = "The builder must be built to be used"] pub struct HaveContextBuilder<'a> { builder: MessageBuilder<'a>, context: Option, } impl<'a> HaveContextBuilder<'a> { fn new(context: crate::Context) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), context: Some(context), } } message_builder_generic_impl!(|s: &mut Self, src| { let context = s.context.take().unwrap(); ffi::gst_message_new_have_context(src, context.into_glib_ptr()) }); } #[must_use = "The builder must be built to be used"] pub struct DeviceAddedBuilder<'a> { builder: MessageBuilder<'a>, device: &'a crate::Device, } impl<'a> DeviceAddedBuilder<'a> { fn new(device: &'a crate::Device) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), device, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_device_added( src, s.device.to_glib_none().0 )); } #[must_use = "The builder must be built to be used"] pub struct DeviceRemovedBuilder<'a> { builder: MessageBuilder<'a>, device: &'a crate::Device, } impl<'a> DeviceRemovedBuilder<'a> { fn new(device: &'a crate::Device) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), device, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_device_removed( src, s.device.to_glib_none().0 )); } #[must_use = "The builder must be built to be used"] pub struct PropertyNotifyBuilder<'a> { builder: MessageBuilder<'a>, property_name: &'a str, value: Option, } impl<'a> PropertyNotifyBuilder<'a> { fn new(property_name: &'a str) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), property_name, value: None, } } pub fn value(self, value: impl ToSendValue) -> Self { Self { value: Some(value.to_send_value()), ..self } } pub fn value_if(self, value: impl ToSendValue, predicate: bool) -> Self { if predicate { self.value(value) } else { self } } pub fn value_if_some(self, value: Option) -> Self { if let Some(value) = value { self.value(value) } else { self } } pub fn value_from_iter>( self, name: &'a str, iter: impl IntoIterator, ) -> Self { let iter = iter.into_iter().map(|item| item.to_send_value()); self.other_field(name, V::from_iter(iter)) } pub fn value_field_if_not_empty>( self, name: &'a str, iter: impl IntoIterator, ) -> Self { let mut iter = iter.into_iter().peekable(); if iter.peek().is_some() { let iter = iter.map(|item| item.to_send_value()); self.other_field(name, V::from_iter(iter)) } else { self } } message_builder_generic_impl!(|s: &mut Self, src| { let v = s.value.take(); ffi::gst_message_new_property_notify( src, s.property_name.to_glib_none().0, v.as_ref().map(|v| v.as_ptr()).unwrap_or(ptr::null_mut()), ) }); } #[must_use = "The builder must be built to be used"] pub struct StreamCollectionBuilder<'a> { builder: MessageBuilder<'a>, collection: &'a crate::StreamCollection, } impl<'a> StreamCollectionBuilder<'a> { fn new(collection: &'a crate::StreamCollection) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), collection, } } message_builder_generic_impl!(|s: &mut Self, src| { ffi::gst_message_new_stream_collection(src, s.collection.to_glib_none().0) }); } #[must_use = "The builder must be built to be used"] pub struct StreamsSelectedBuilder<'a> { builder: MessageBuilder<'a>, collection: &'a crate::StreamCollection, streams: Option>, } impl<'a> StreamsSelectedBuilder<'a> { fn new(collection: &'a crate::StreamCollection) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), collection, streams: None, } } pub fn streams( self, streams: impl IntoIterator>, ) -> Self { Self { streams: Some( streams .into_iter() .map(|s| s.borrow().clone()) .collect::>(), ), ..self } } pub fn streams_if( self, streams: impl IntoIterator>, predicate: bool, ) -> Self { if predicate { self.streams(streams) } else { self } } pub fn streams_if_some( self, streams: Option>>, ) -> Self { if let Some(streams) = streams { self.streams(streams) } else { self } } pub fn streams_if_not_empty( self, streams: impl IntoIterator>, ) -> Self { let mut streams = streams.into_iter().peekable(); if streams.peek().is_some() { self.streams(streams) } else { self } } message_builder_generic_impl!(|s: &mut Self, src| { let msg = ffi::gst_message_new_streams_selected(src, s.collection.to_glib_none().0); if let Some(ref streams) = s.streams { for stream in streams { ffi::gst_message_streams_selected_add(msg, stream.to_glib_none().0); } } msg }); } #[must_use = "The builder must be built to be used"] pub struct RedirectBuilder<'a> { builder: MessageBuilder<'a>, location: &'a str, tag_list: Option<&'a TagList>, entry_struct: Option, #[allow(clippy::type_complexity)] entries: Option<&'a [(&'a str, Option<&'a TagList>, Option<&'a Structure>)]>, } impl<'a> RedirectBuilder<'a> { fn new(location: &'a str) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), location, tag_list: None, entry_struct: None, entries: None, } } pub fn tag_list(self, tag_list: &'a TagList) -> Self { Self { tag_list: Some(tag_list), ..self } } pub fn tag_list_if(self, tag_list: &'a TagList, predicate: bool) -> Self { if predicate { self.tag_list(tag_list) } else { self } } pub fn tag_list_if_some(self, tag_list: Option<&'a TagList>) -> Self { if let Some(tag_list) = tag_list { self.tag_list(tag_list) } else { self } } pub fn entry_struct(self, entry_struct: Structure) -> Self { Self { entry_struct: Some(entry_struct), ..self } } pub fn entry_struct_if(self, entry_struct: Structure, predicate: bool) -> Self { if predicate { self.entry_struct(entry_struct) } else { self } } pub fn entry_struct_if_some(self, entry_struct: Option) -> Self { if let Some(entry_struct) = entry_struct { self.entry_struct(entry_struct) } else { self } } pub fn entries( self, entries: &'a [(&'a str, Option<&'a TagList>, Option<&'a Structure>)], ) -> Self { skip_assert_initialized!(); Self { entries: Some(entries), ..self } } #[allow(clippy::type_complexity)] pub fn entries_if( self, entries: &'a [(&'a str, Option<&'a TagList>, Option<&'a Structure>)], predicate: bool, ) -> Self { if predicate { self.entries(entries) } else { self } } #[allow(clippy::type_complexity)] pub fn entries_if_some( self, entries: Option<&'a [(&'a str, Option<&'a TagList>, Option<&'a Structure>)]>, ) -> Self { if let Some(entries) = entries { self.entries(entries) } else { self } } message_builder_generic_impl!(|s: &mut Self, src| { let entry_struct = s.entry_struct.take(); let entry_struct_ptr = if let Some(entry_struct) = entry_struct { entry_struct.into_glib_ptr() } else { ptr::null_mut() }; let msg = ffi::gst_message_new_redirect( src, s.location.to_glib_none().0, s.tag_list.to_glib_full(), entry_struct_ptr, ); if let Some(entries) = s.entries { for &(location, tag_list, entry_struct) in entries { let entry_struct = entry_struct.cloned(); let entry_struct_ptr = if let Some(entry_struct) = entry_struct { entry_struct.into_glib_ptr() } else { ptr::null_mut() }; ffi::gst_message_add_redirect_entry( msg, location.to_glib_none().0, tag_list.to_glib_full(), entry_struct_ptr, ); } } msg }); } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[must_use = "The builder must be built to be used"] pub struct DeviceChangedBuilder<'a> { builder: MessageBuilder<'a>, device: &'a crate::Device, changed_device: &'a crate::Device, } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] impl<'a> DeviceChangedBuilder<'a> { fn new(device: &'a crate::Device, changed_device: &'a crate::Device) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), device, changed_device, } } message_builder_generic_impl!(|s: &mut Self, src| ffi::gst_message_new_device_changed( src, s.device.to_glib_none().0, s.changed_device.to_glib_none().0, )); } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[must_use = "The builder must be built to be used"] pub struct InstantRateRequestBuilder<'a> { builder: MessageBuilder<'a>, rate_multiplier: f64, } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] impl<'a> InstantRateRequestBuilder<'a> { fn new(rate_multiplier: f64) -> Self { skip_assert_initialized!(); Self { builder: MessageBuilder::new(), rate_multiplier, } } message_builder_generic_impl!( |s: &mut Self, src| ffi::gst_message_new_instant_rate_request(src, s.rate_multiplier,) ); } #[cfg(test)] mod tests { use super::*; #[test] fn test_simple() { crate::init().unwrap(); // Message without arguments let seqnum = Seqnum::next(); let eos_msg = Eos::builder().seqnum(seqnum).build(); match eos_msg.view() { MessageView::Eos(eos_msg) => { assert_eq!(eos_msg.seqnum(), seqnum); assert!(eos_msg.structure().is_none()); } _ => panic!("eos_msg.view() is not a MessageView::Eos(_)"), } // Message with arguments let buffering_msg = Buffering::new(42); match buffering_msg.view() { MessageView::Buffering(buffering_msg) => { assert_eq!(buffering_msg.percent(), 42); } _ => panic!("buffering_msg.view() is not a MessageView::Buffering(_)"), } } #[test] #[allow(deprecated)] fn test_other_fields() { crate::init().unwrap(); let seqnum = Seqnum::next(); let eos_msg = Eos::builder() .other_fields(&[("extra-field", &true)]) .seqnum(seqnum) .build(); match eos_msg.view() { MessageView::Eos(eos_msg) => { assert_eq!(eos_msg.seqnum(), seqnum); if let Some(other_fields) = eos_msg.structure() { assert!(other_fields.has_field("extra-field")); } } _ => panic!("eos_msg.view() is not a MessageView::Eos(_)"), } let buffering_msg = Buffering::builder(42) .other_field("extra-field", true) .build(); match buffering_msg.view() { MessageView::Buffering(buffering_msg) => { assert_eq!(buffering_msg.percent(), 42); if let Some(other_fields) = buffering_msg.structure() { assert!(other_fields.has_field("extra-field")); } } _ => panic!("buffering_msg.view() is not a MessageView::Buffering(_)"), } } #[test] fn test_get_seqnum_valid() { crate::init().unwrap(); let msg = StreamStart::new(); let seqnum = Seqnum( NonZeroU32::new(unsafe { ffi::gst_message_get_seqnum(msg.as_mut_ptr()) }).unwrap(), ); match msg.view() { MessageView::StreamStart(stream_start) => assert_eq!(seqnum, stream_start.seqnum()), _ => panic!(), } } #[test] fn test_get_seqnum_invalid() { crate::init().unwrap(); let msg = StreamStart::new(); let seqnum_init = msg.seqnum(); // Invalid the seqnum unsafe { (*msg.as_mut_ptr()).seqnum = ffi::GST_SEQNUM_INVALID as u32; assert_eq!(0, (*msg.as_ptr()).seqnum); }; match msg.view() { MessageView::StreamStart(stream_start) => { // get_seqnum is expected to return a new Seqnum, // further in the sequence than the last known seqnum. assert!(seqnum_init < stream_start.seqnum()); } _ => panic!(), } } } gstreamer-0.23.5/src/meta.rs000064400000000000000000001112011046102023000137630ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] use std::ptr; use std::{ fmt, marker::PhantomData, ops::{self, Bound, RangeBounds}, }; use glib::translate::*; use crate::{ffi, Buffer, BufferRef, Caps, CapsRef, ClockTime}; pub unsafe trait MetaAPI: Sync + Send + Sized { type GstType; #[doc(alias = "get_meta_api")] fn meta_api() -> glib::Type; } pub trait MetaAPIExt: MetaAPI { #[inline] unsafe fn from_ptr(buffer: &BufferRef, ptr: *const Self::GstType) -> MetaRef { debug_assert!(!ptr.is_null()); let meta_api = Self::meta_api(); if meta_api != glib::Type::INVALID { debug_assert_eq!( meta_api, from_glib((*(*(ptr as *const ffi::GstMeta)).info).api) ) } MetaRef { meta: &*(ptr as *const Self), buffer, } } #[inline] unsafe fn from_mut_ptr( buffer: &mut BufferRef, ptr: *mut Self::GstType, ) -> MetaRefMut { debug_assert!(!ptr.is_null()); let meta_api = Self::meta_api(); if meta_api != glib::Type::INVALID { debug_assert_eq!( meta_api, from_glib((*(*(ptr as *const ffi::GstMeta)).info).api) ) } MetaRefMut { meta: &mut *(ptr as *mut Self), buffer, mode: PhantomData, } } } impl MetaAPIExt for A {} #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] pub struct MetaSeqnum(u64); pub struct MetaRef<'a, T: 'a> { meta: &'a T, buffer: &'a BufferRef, } pub enum Standalone {} pub enum Iterated {} pub struct MetaRefMut<'a, T: 'a, U> { meta: &'a mut T, buffer: &'a mut BufferRef, mode: PhantomData, } impl<'a, T: fmt::Debug + 'a> fmt::Debug for MetaRef<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MetaRef") .field("meta", &self.meta) .field("buffer", &self.buffer) .finish() } } impl<'a, T: fmt::Debug + 'a, U> fmt::Debug for MetaRefMut<'a, T, U> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MetaRef") .field("meta", &self.meta) .field("buffer", &self.buffer) .field("mode", &self.mode) .finish() } } impl ops::Deref for MetaRef<'_, T> { type Target = T; #[inline] fn deref(&self) -> &T { self.meta } } impl<'a, T> AsRef> for MetaRef<'a, T> { #[inline] fn as_ref(&self) -> &MetaRef<'a, T> { self } } impl AsRef for MetaRef<'_, T> { #[inline] fn as_ref(&self) -> &T { self.meta } } impl<'a, T: 'a> Clone for MetaRef<'a, T> { fn clone(&self) -> Self { MetaRef { meta: self.meta, buffer: self.buffer, } } } impl ops::Deref for MetaRefMut<'_, T, U> { type Target = T; #[inline] fn deref(&self) -> &T { self.meta } } impl ops::DerefMut for MetaRefMut<'_, T, U> { #[inline] fn deref_mut(&mut self) -> &mut T { self.meta } } impl<'a, T, U> AsRef> for MetaRefMut<'a, T, U> { #[inline] fn as_ref(&self) -> &MetaRef<'a, T> { unsafe { &*(self as *const MetaRefMut<'a, T, U> as *const MetaRef<'a, T>) } } } impl AsMut for MetaRefMut<'_, T, U> { #[inline] fn as_mut(&mut self) -> &mut T { self.meta } } impl<'a, T> MetaRef<'a, T> { #[doc(alias = "get_api")] #[inline] pub fn api(&self) -> glib::Type { unsafe { let meta = self.meta as *const _ as *const ffi::GstMeta; let info = (*meta).info; glib::Type::from_glib((*info).api) } } #[inline] pub fn flags(&self) -> crate::MetaFlags { unsafe { let meta = self.meta as *const _ as *const ffi::GstMeta; from_glib((*meta).flags) } } #[inline] pub fn type_(&self) -> glib::Type { unsafe { let meta = self.meta as *const _ as *const ffi::GstMeta; let info = (*meta).info; glib::Type::from_glib((*info).type_) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "get_seqnum")] #[doc(alias = "gst_meta_get_seqnum")] #[inline] pub fn seqnum(&self) -> MetaSeqnum { unsafe { let meta = self.meta as *const _ as *const ffi::GstMeta; MetaSeqnum(ffi::gst_meta_get_seqnum(meta)) } } #[inline] #[doc(alias = "gst_meta_api_type_has_tag")] pub fn has_tag(&self) -> bool { self.has_tag_by_quark(MT::quark()) } #[inline] pub fn has_tag_by_quark(&self, tag: glib::Quark) -> bool { meta_api_type_has_tag_by_quark(self.api(), tag) } #[inline] #[doc(alias = "gst_meta_api_type_get_tags")] pub fn tags<'b>(&self) -> &'b [glib::GStringPtr] { meta_api_type_get_tags(self.api()) } #[inline] pub fn upcast_ref(&self) -> &MetaRef<'a, Meta> { unsafe { &*(self as *const MetaRef<'a, T> as *const MetaRef<'a, Meta>) } } pub fn transform(&self, buffer: &mut BufferRef, data: &'a MT) -> Result<(), glib::BoolError> where T: MetaAPI, MT: MetaTransform<'a>, { unsafe { let info = *(*self.upcast_ref().as_ptr()).info; let Some(transform_func) = info.transform_func else { return Err(glib::bool_error!( "Can't copy meta without transform function" )); }; let data = data.to_raw(self)?; glib::result_from_gboolean!( transform_func( buffer.as_mut_ptr(), mut_override(self.upcast_ref().as_ptr()), mut_override(self.buffer.as_ptr()), MT::quark().into_glib(), mut_override(&data) as *mut _, ), "Failed to transform meta" ) } } #[inline] pub fn as_ptr(&self) -> *const T::GstType where T: MetaAPI, { self.meta as *const _ as *const ::GstType } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_meta_serialize")] pub fn serialize( &self, writer: &mut B, ) -> Result { unsafe { #[repr(C)] struct Writer<'a, B: ?Sized> { iface_: ffi::GstByteArrayInterface, writer: &'a mut B, } unsafe extern "C" fn resize( iface_: *mut ffi::GstByteArrayInterface, size: usize, ) -> glib::ffi::gboolean { let iface_ = &mut *(iface_ as *mut Writer); match iface_.writer.resize(size) { Some(new_data) => { iface_.iface_.data = new_data.as_mut_ptr(); iface_.iface_.len = size; glib::ffi::GTRUE } None => glib::ffi::GFALSE, } } let initial_len = writer.initial_len(); let mut iface_ = Writer { iface_: ffi::GstByteArrayInterface { data: writer.as_mut().as_mut_ptr(), len: initial_len, resize: Some(resize::), _gst_reserved: [ptr::null_mut(); 4], }, writer: &mut *writer, }; let res = bool::from_glib(ffi::gst_meta_serialize( self.meta as *const T as *const ffi::GstMeta, &mut iface_.iface_, )); if !res { return Err(glib::bool_error!("Failed to serialize meta")); } assert!(iface_.iface_.len >= initial_len); Ok(iface_.iface_.len - initial_len) } } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] pub trait ByteArrayInterface: AsMut<[u8]> { fn initial_len(&self) -> usize; fn resize(&mut self, size: usize) -> Option<&mut [u8]>; } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] impl ByteArrayInterface for Vec { fn initial_len(&self) -> usize { self.len() } fn resize(&mut self, size: usize) -> Option<&mut [u8]> { self.resize(size, 0); Some(&mut self[0..size]) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] impl> ByteArrayInterface for smallvec::SmallVec { fn initial_len(&self) -> usize { self.len() } fn resize(&mut self, size: usize) -> Option<&mut [u8]> { self.resize(size, 0); Some(&mut self[0..size]) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] impl ByteArrayInterface for &mut [u8] { fn initial_len(&self) -> usize { 0 } fn resize(&mut self, size: usize) -> Option<&mut [u8]> { if self.len() < size { return None; } Some(&mut self[0..size]) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] impl ByteArrayInterface for [u8; N] { fn initial_len(&self) -> usize { 0 } fn resize(&mut self, size: usize) -> Option<&mut [u8]> { if N < size { return None; } Some(&mut self[0..size]) } } impl<'a> MetaRef<'a, Meta> { #[inline] pub fn downcast_ref(&self) -> Option<&MetaRef<'a, T>> { let target_type = T::meta_api(); let type_ = self.api(); if type_ == glib::Type::INVALID || target_type == type_ { Some(unsafe { &*(self as *const MetaRef<'a, Meta> as *const MetaRef<'a, T>) }) } else { None } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[inline] pub fn try_as_custom_meta(&self) -> Option<&MetaRef<'a, CustomMeta>> { unsafe { if ffi::gst_meta_info_is_custom(&*self.0.info) == glib::ffi::GFALSE { return None; } Some(&*(self as *const MetaRef<'a, Meta> as *const MetaRef<'a, CustomMeta>)) } } } impl<'a, T, U> MetaRefMut<'a, T, U> { #[doc(alias = "get_api")] #[inline] pub fn api(&self) -> glib::Type { self.as_meta_ref().api() } #[inline] pub fn flags(&self) -> crate::MetaFlags { self.as_meta_ref().flags() } #[inline] pub fn type_(&self) -> glib::Type { self.as_meta_ref().type_() } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "get_seqnum")] #[doc(alias = "gst_meta_get_seqnum")] #[inline] pub fn seqnum(&self) -> MetaSeqnum { self.as_meta_ref().seqnum() } #[inline] #[doc(alias = "gst_meta_api_type_has_tag")] pub fn has_tag(&self) -> bool { self.as_meta_ref().has_tag::() } #[inline] pub fn has_tag_by_quark(&self, tag: glib::Quark) -> bool { self.as_meta_ref().has_tag_by_quark(tag) } #[inline] #[doc(alias = "gst_meta_api_type_get_tags")] pub fn tags<'b>(&self) -> &'b [glib::GStringPtr] { self.as_meta_ref().tags() } #[inline] pub fn upcast_ref(&self) -> &MetaRef<'a, Meta> { unsafe { &*(self as *const MetaRefMut<'a, T, U> as *const MetaRef<'a, Meta>) } } #[inline] pub fn upcast_mut(&mut self) -> &mut MetaRefMut<'a, Meta, U> { unsafe { &mut *(self as *mut MetaRefMut<'a, T, U> as *mut MetaRefMut<'a, Meta, U>) } } #[inline] pub fn as_meta_ref(&self) -> MetaRef { MetaRef { meta: self.meta, buffer: self.buffer, } } pub fn transform( &'a self, buffer: &mut BufferRef, data: &'a MT, ) -> Result<(), glib::BoolError> where T: MetaAPI, MT: MetaTransform<'a>, { self.as_meta_ref().transform(buffer, data) } #[inline] pub fn as_ptr(&self) -> *const T::GstType where T: MetaAPI, { self.meta as *const _ as *const ::GstType } #[inline] pub fn as_mut_ptr(&mut self) -> *mut T::GstType where T: MetaAPI, { self.meta as *mut _ as *mut ::GstType } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_meta_serialize")] pub fn serialize( &self, writer: &mut B, ) -> Result { self.as_meta_ref().serialize(writer) } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] pub fn clear(&mut self) -> Result<(), glib::BoolError> where T: MetaAPI, { unsafe { let info = *(*self.upcast_ref().as_ptr()).info; if let Some(clear_func) = info.clear_func { clear_func(self.buffer.as_mut_ptr(), self.upcast_mut().as_mut_ptr()); Ok(()) } else { Err(glib::bool_error!("Failed to clear meta")) } } } } impl MetaRefMut<'_, T, Standalone> { #[doc(alias = "gst_buffer_remove_meta")] pub fn remove(self) -> Result<(), glib::BoolError> { if self.flags().contains(crate::MetaFlags::LOCKED) { return Err(glib::bool_error!("Can't remove locked meta")); } unsafe { let res = ffi::gst_buffer_remove_meta( self.buffer.as_mut_ptr(), self.meta as *mut T as *mut ffi::GstMeta, ); debug_assert_ne!(res, glib::ffi::GFALSE); Ok(()) } } } impl<'a, U> MetaRefMut<'a, Meta, U> { #[inline] pub fn downcast_ref(&mut self) -> Option<&MetaRefMut<'a, T, U>> { let target_type = T::meta_api(); let type_ = self.api(); if type_ == glib::Type::INVALID || target_type == type_ { Some(unsafe { &*(self as *mut MetaRefMut<'a, Meta, U> as *const MetaRefMut<'a, T, U>) }) } else { None } } #[inline] pub fn downcast_mut(&mut self) -> Option<&mut MetaRefMut<'a, T, U>> { let target_type = T::meta_api(); let type_ = self.api(); if type_ == glib::Type::INVALID || target_type == type_ { Some(unsafe { &mut *(self as *mut MetaRefMut<'a, Meta, U> as *mut MetaRefMut<'a, T, U>) }) } else { None } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[inline] pub fn try_as_custom_meta(&self) -> Option<&MetaRefMut<'a, CustomMeta, U>> { unsafe { if ffi::gst_meta_info_is_custom(&*self.0.info) == glib::ffi::GFALSE { return None; } Some(&*(self as *const MetaRefMut<'a, Meta, U> as *const MetaRefMut<'a, CustomMeta, U>)) } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[inline] pub fn try_as_mut_custom_meta(&mut self) -> Option<&mut MetaRefMut<'a, CustomMeta, U>> { unsafe { if ffi::gst_meta_info_is_custom(&*self.0.info) == glib::ffi::GFALSE { return None; } Some(&mut *(self as *mut MetaRefMut<'a, Meta, U> as *mut MetaRefMut<'a, CustomMeta, U>)) } } } #[repr(transparent)] #[doc(alias = "GstMeta")] pub struct Meta(ffi::GstMeta); unsafe impl Send for Meta {} unsafe impl Sync for Meta {} unsafe impl MetaAPI for Meta { type GstType = ffi::GstMeta; #[inline] fn meta_api() -> glib::Type { glib::Type::INVALID } } impl fmt::Debug for Meta { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Meta") .field("api", &unsafe { glib::Type::from_glib((*self.0.info).api) }) .field("type", &unsafe { glib::Type::from_glib((*self.0.info).type_) }) .field("flags", &unsafe { crate::MetaFlags::from_glib(self.0.flags) }) .finish() } } impl Meta { #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_meta_deserialize")] pub fn deserialize<'a>( buffer: &'a mut BufferRef, data: &[u8], consumed: &mut usize, ) -> Result, glib::BoolError> { skip_assert_initialized!(); unsafe { use std::mem; let mut consumed_u32 = mem::MaybeUninit::uninit(); let res = ffi::gst_meta_deserialize( buffer.as_mut_ptr(), data.as_ptr(), data.len(), consumed_u32.as_mut_ptr(), ); *consumed = consumed_u32.assume_init() as usize; if res.is_null() { return Err(glib::bool_error!("Failed to deserialize meta")); } Ok(MetaRefMut { meta: &mut *(res as *mut Self), buffer, mode: PhantomData, }) } } } #[repr(transparent)] #[doc(alias = "GstParentBufferMeta")] pub struct ParentBufferMeta(ffi::GstParentBufferMeta); unsafe impl Send for ParentBufferMeta {} unsafe impl Sync for ParentBufferMeta {} impl ParentBufferMeta { #[doc(alias = "gst_buffer_add_parent_buffer_meta")] pub fn add<'a>(buffer: &'a mut BufferRef, parent: &Buffer) -> MetaRefMut<'a, Self, Standalone> { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_add_parent_buffer_meta( buffer.as_mut_ptr(), parent.to_glib_none().0, ); Self::from_mut_ptr(buffer, meta) } } #[doc(alias = "get_parent")] #[inline] pub fn parent(&self) -> &BufferRef { unsafe { BufferRef::from_ptr(self.0.buffer) } } #[doc(alias = "get_parent_owned")] #[inline] pub fn parent_owned(&self) -> Buffer { unsafe { from_glib_none(self.0.buffer) } } } unsafe impl MetaAPI for ParentBufferMeta { type GstType = ffi::GstParentBufferMeta; #[doc(alias = "gst_parent_buffer_meta_api_get_type")] #[inline] fn meta_api() -> glib::Type { unsafe { from_glib(ffi::gst_parent_buffer_meta_api_get_type()) } } } impl fmt::Debug for ParentBufferMeta { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ParentBufferMeta") .field("parent", &self.parent()) .finish() } } #[repr(transparent)] #[doc(alias = "GstProtectionMeta")] pub struct ProtectionMeta(ffi::GstProtectionMeta); unsafe impl Send for ProtectionMeta {} unsafe impl Sync for ProtectionMeta {} impl ProtectionMeta { #[doc(alias = "gst_buffer_add_protection_meta")] pub fn add(buffer: &mut BufferRef, info: crate::Structure) -> MetaRefMut { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_add_protection_meta(buffer.as_mut_ptr(), info.into_glib_ptr()); Self::from_mut_ptr(buffer, meta) } } #[doc(alias = "get_info")] #[inline] pub fn info(&self) -> &crate::StructureRef { unsafe { crate::StructureRef::from_glib_borrow(self.0.info) } } #[doc(alias = "get_info_mut")] #[inline] pub fn info_mut(&mut self) -> &mut crate::StructureRef { unsafe { crate::StructureRef::from_glib_borrow_mut(self.0.info) } } } unsafe impl MetaAPI for ProtectionMeta { type GstType = ffi::GstProtectionMeta; #[doc(alias = "gst_protection_meta_api_get_type")] #[inline] fn meta_api() -> glib::Type { unsafe { from_glib(ffi::gst_protection_meta_api_get_type()) } } } impl fmt::Debug for ProtectionMeta { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ProtectionMeta") .field("info", &self.info()) .finish() } } #[repr(transparent)] #[doc(alias = "GstReferenceTimestampMeta")] pub struct ReferenceTimestampMeta(ffi::GstReferenceTimestampMeta); unsafe impl Send for ReferenceTimestampMeta {} unsafe impl Sync for ReferenceTimestampMeta {} impl ReferenceTimestampMeta { #[doc(alias = "gst_buffer_add_reference_timestamp_meta")] pub fn add<'a>( buffer: &'a mut BufferRef, reference: &Caps, timestamp: ClockTime, duration: impl Into>, ) -> MetaRefMut<'a, Self, Standalone> { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_add_reference_timestamp_meta( buffer.as_mut_ptr(), reference.to_glib_none().0, timestamp.into_glib(), duration.into().into_glib(), ); Self::from_mut_ptr(buffer, meta) } } #[doc(alias = "get_reference")] #[inline] pub fn reference(&self) -> &CapsRef { unsafe { CapsRef::from_ptr(self.0.reference) } } #[doc(alias = "get_reference_owned")] #[inline] pub fn reference_owned(&self) -> Caps { unsafe { from_glib_none(self.0.reference) } } #[doc(alias = "get_timestamp")] #[inline] pub fn timestamp(&self) -> ClockTime { unsafe { try_from_glib(self.0.timestamp).expect("undefined timestamp") } } #[doc(alias = "get_duration")] #[inline] pub fn duration(&self) -> Option { unsafe { from_glib(self.0.duration) } } } unsafe impl MetaAPI for ReferenceTimestampMeta { type GstType = ffi::GstReferenceTimestampMeta; #[doc(alias = "gst_reference_timestamp_meta_api_get_type")] #[inline] fn meta_api() -> glib::Type { unsafe { from_glib(ffi::gst_reference_timestamp_meta_api_get_type()) } } } impl fmt::Debug for ReferenceTimestampMeta { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use crate::utils::Displayable; f.debug_struct("ReferenceTimestampMeta") .field("reference", &self.reference()) .field("timestamp", &self.timestamp().display()) .field("duration", &self.duration().display()) .finish() } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[repr(transparent)] #[doc(alias = "GstCustomMeta")] pub struct CustomMeta(ffi::GstCustomMeta); #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] unsafe impl Send for CustomMeta {} #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] unsafe impl Sync for CustomMeta {} #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl CustomMeta { #[doc(alias = "gst_meta_register_custom")] pub fn register(name: &str, tags: &[&str]) { assert_initialized_main_thread!(); unsafe { ffi::gst_meta_register_custom( name.to_glib_none().0, tags.to_glib_none().0, None, ptr::null_mut(), None, ); } } #[doc(alias = "gst_meta_register_custom")] pub fn register_with_transform< F: Fn(&mut BufferRef, &CustomMeta, &BufferRef, glib::Quark) -> bool + Send + Sync + 'static, >( name: &str, tags: &[&str], transform_func: F, ) { assert_initialized_main_thread!(); unsafe extern "C" fn transform_func_trampoline< F: Fn(&mut BufferRef, &CustomMeta, &BufferRef, glib::Quark) -> bool + Send + Sync + 'static, >( dest: *mut ffi::GstBuffer, meta: *mut ffi::GstCustomMeta, src: *mut ffi::GstBuffer, type_: glib::ffi::GQuark, _data: glib::ffi::gpointer, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let func = &*(user_data as *const F); let res = func( BufferRef::from_mut_ptr(dest), &*(meta as *const CustomMeta), BufferRef::from_ptr(src), from_glib(type_), ); res.into_glib() } unsafe extern "C" fn transform_func_free(ptr: glib::ffi::gpointer) { let _ = Box::from_raw(ptr as *mut F); } unsafe { ffi::gst_meta_register_custom( name.to_glib_none().0, tags.to_glib_none().0, Some(transform_func_trampoline::), Box::into_raw(Box::new(transform_func)) as glib::ffi::gpointer, Some(transform_func_free::), ); } } #[doc(alias = "gst_meta_register_simple")] pub fn register_simple(name: &str) { assert_initialized_main_thread!(); unsafe { ffi::gst_meta_register_custom( name.to_glib_none().0, [ptr::null()].as_mut_ptr(), None, ptr::null_mut(), None, ); } } pub fn is_registered(name: &str) -> bool { assert_initialized_main_thread!(); unsafe { name.run_with_gstr(|name| !ffi::gst_meta_get_info(name.as_ptr()).is_null()) } } #[doc(alias = "gst_buffer_add_custom_meta")] pub fn add<'a>( buffer: &'a mut BufferRef, name: &str, ) -> Result, glib::BoolError> { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_add_custom_meta(buffer.as_mut_ptr(), name.to_glib_none().0); if meta.is_null() { return Err(glib::bool_error!("Failed to add custom meta")); } Ok(MetaRefMut { meta: &mut *(meta as *mut Self), buffer, mode: PhantomData, }) } } #[doc(alias = "gst_buffer_get_custom_meta")] pub fn from_buffer<'a>( buffer: &'a BufferRef, name: &str, ) -> Result, glib::BoolError> { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_get_custom_meta(buffer.as_mut_ptr(), name.to_glib_none().0); if meta.is_null() { return Err(glib::bool_error!("Failed to get custom meta")); } Ok(MetaRef { meta: &*(meta as *const Self), buffer, }) } } #[doc(alias = "gst_buffer_get_custom_meta")] pub fn from_mut_buffer<'a>( buffer: &'a mut BufferRef, name: &str, ) -> Result, glib::BoolError> { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_get_custom_meta(buffer.as_mut_ptr(), name.to_glib_none().0); if meta.is_null() { return Err(glib::bool_error!("Failed to get custom meta")); } Ok(MetaRefMut { meta: &mut *(meta as *mut Self), buffer, mode: PhantomData, }) } } #[doc(alias = "gst_custom_meta_get_structure")] #[inline] pub fn structure(&self) -> &crate::StructureRef { unsafe { crate::StructureRef::from_glib_borrow(ffi::gst_custom_meta_get_structure(mut_override( &self.0, ))) } } #[doc(alias = "gst_custom_meta_get_structure")] #[inline] pub fn mut_structure(&mut self) -> &mut crate::StructureRef { unsafe { crate::StructureRef::from_glib_borrow_mut(ffi::gst_custom_meta_get_structure( &mut self.0, )) } } #[doc(alias = "gst_custom_meta_has_name")] #[inline] pub fn has_name(&self, name: &str) -> bool { unsafe { from_glib(ffi::gst_custom_meta_has_name( mut_override(&self.0), name.to_glib_none().0, )) } } } pub trait MetaTag { const TAG_NAME: &'static glib::GStr; fn quark() -> glib::Quark; } #[macro_export] macro_rules! impl_meta_tag( ($name:ident, $gst_tag:path) => { pub enum $name {} impl $crate::meta::MetaTag for $name { const TAG_NAME: &'static glib::GStr = unsafe { glib::GStr::from_utf8_with_nul_unchecked($gst_tag) }; fn quark() -> glib::Quark { static QUARK: std::sync::OnceLock = std::sync::OnceLock::new(); *QUARK.get_or_init(|| glib::Quark::from_static_str(Self::TAG_NAME)) } } }; ); pub mod tags { impl_meta_tag!(Memory, crate::ffi::GST_META_TAG_MEMORY_STR); impl_meta_tag!( MemoryReference, crate::ffi::GST_META_TAG_MEMORY_REFERENCE_STR ); } pub unsafe trait MetaTransform<'a> { type GLibType; fn quark() -> glib::Quark; fn to_raw(&self, meta: &MetaRef) -> Result; } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MetaTransformCopy { range: (Bound, Bound), region: bool, } impl MetaTransformCopy { pub fn new(region: bool, range: impl RangeBounds) -> Self { skip_assert_initialized!(); MetaTransformCopy { range: (range.start_bound().cloned(), range.end_bound().cloned()), region, } } } unsafe impl MetaTransform<'_> for MetaTransformCopy { type GLibType = ffi::GstMetaTransformCopy; fn quark() -> glib::Quark { static QUARK: std::sync::OnceLock = std::sync::OnceLock::new(); *QUARK.get_or_init(|| glib::Quark::from_static_str(glib::gstr!("gst-copy"))) } fn to_raw( &self, meta: &MetaRef, ) -> Result { let (offset, size) = meta.buffer.byte_range_into_offset_len(self.range)?; Ok(ffi::GstMetaTransformCopy { region: self.region.into_glib(), offset, size, }) } } #[inline] #[doc(alias = "gst_meta_api_type_has_tag")] pub fn meta_api_type_has_tag(type_: glib::Type) -> bool { skip_assert_initialized!(); meta_api_type_has_tag_by_quark(type_, MT::quark()) } #[inline] #[doc(alias = "gst_meta_api_type_has_tag")] pub fn meta_api_type_has_tag_by_quark(type_: glib::Type, tag: glib::Quark) -> bool { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_meta_api_type_has_tag( type_.into_glib(), tag.into_glib(), )) } } #[inline] #[doc(alias = "gst_meta_api_type_get_tags")] pub fn meta_api_type_get_tags<'b>(type_: glib::Type) -> &'b [glib::GStringPtr] { skip_assert_initialized!(); unsafe { glib::StrV::from_glib_borrow(ffi::gst_meta_api_type_get_tags(type_.into_glib())) } } #[cfg(feature = "v1_26")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_meta_api_type_aggregate_params")] pub fn meta_api_type_aggregate_params( type_: glib::Type, params1: &crate::StructureRef, params2: &crate::StructureRef, ) -> Result, glib::BoolError> { skip_assert_initialized!(); unsafe { let mut new_params = ptr::null_mut(); let res = bool::from_glib(ffi::gst_meta_api_type_aggregate_params( type_.into_glib(), &mut new_params, params1.as_ptr(), params2.as_ptr(), )); if res { Ok(from_glib_full(new_params)) } else { Err(glib::bool_error!("Failed to aggregate meta type params")) } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_add_get_iterate_meta() { crate::init().unwrap(); let mut buffer = crate::Buffer::new(); let parent = crate::Buffer::new(); { let meta = ParentBufferMeta::add(buffer.get_mut().unwrap(), &parent); assert_eq!(meta.parent().as_ptr(), parent.as_ptr()); } { let metas = buffer.iter_meta::(); assert_eq!(metas.count(), 1); } { let metas = buffer.get_mut().unwrap().iter_meta_mut::(); assert_eq!(metas.count(), 1); } { let metas = buffer.iter_meta::().collect::>(); assert_eq!(metas.len(), 1); assert_eq!(metas[0].parent().as_ptr(), parent.as_ptr()); } { let metas = buffer .get_mut() .unwrap() .iter_meta_mut::() .collect::>(); assert_eq!(metas.len(), 1); assert_eq!(metas[0].parent().as_ptr(), parent.as_ptr()); assert!(!metas[0].has_tag_by_quark(glib::Quark::from_str("video"))); assert!(metas[0].has_tag::()); assert_eq!(metas[0].tags().len(), 1); assert_eq!(metas[0].tags(), metas[0].upcast_ref().tags()); } { let meta = buffer .get_mut() .unwrap() .meta_mut::() .unwrap(); assert_eq!(meta.parent().as_ptr(), parent.as_ptr()); meta.remove().unwrap(); } { let metas = buffer.iter_meta::(); assert_eq!(metas.count(), 0); } { let metas = buffer.get_mut().unwrap().iter_meta_mut::(); assert_eq!(metas.count(), 0); } { let metas = buffer.iter_meta::(); assert_eq!(metas.count(), 0); } { let metas = buffer .get_mut() .unwrap() .iter_meta_mut::(); assert_eq!(metas.count(), 0); } assert!(buffer.meta::().is_none()); } #[test] fn test_copy_reference_timestamp_meta() { crate::init().unwrap(); let caps = crate::Caps::new_empty_simple("timestamp/x-ntp"); let mut buffer = crate::Buffer::new(); { ReferenceTimestampMeta::add( buffer.get_mut().unwrap(), &caps, crate::ClockTime::from_seconds(1), crate::ClockTime::NONE, ); } let mut buffer_dest = crate::Buffer::new(); { let meta = buffer.meta::().unwrap(); let buffer_dest = buffer_dest.get_mut().unwrap(); meta.transform(buffer_dest, &MetaTransformCopy::new(false, ..)) .unwrap(); } let meta = buffer_dest.meta::().unwrap(); assert_eq!(meta.reference(), &caps); assert_eq!(meta.timestamp(), crate::ClockTime::from_seconds(1)); assert_eq!(meta.duration(), crate::ClockTime::NONE); } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[test] fn test_meta_serialize() { use smallvec::SmallVec; crate::init().unwrap(); let caps = crate::Caps::new_empty_simple("timestamp/x-ntp"); let mut buffer = crate::Buffer::new(); let meta = ReferenceTimestampMeta::add( buffer.get_mut().unwrap(), &caps, crate::ClockTime::from_seconds(1), crate::ClockTime::NONE, ); let mut data_1 = Vec::new(); let mut data_2 = [0u8; 128]; let mut data_3 = SmallVec::<[u8; 128]>::new(); let len_1 = meta.serialize(&mut data_1).unwrap(); let len_2 = meta.serialize(&mut data_2).unwrap(); let len_3 = meta.serialize(&mut data_3).unwrap(); assert_eq!(&data_1[..len_1], &data_2[..len_2]); assert_eq!(&data_1[..len_1], &data_3[..len_3]); assert!(meta.serialize(&mut [0]).is_err()); let mut buffer_dest = crate::Buffer::new(); let mut consumed = 0; let mut meta = Meta::deserialize(buffer_dest.get_mut().unwrap(), &data_1, &mut consumed).unwrap(); assert_eq!(consumed, len_1); let meta = meta.downcast_ref::().unwrap(); assert_eq!(meta.reference(), &caps); assert_eq!(meta.timestamp(), crate::ClockTime::from_seconds(1)); assert_eq!(meta.duration(), crate::ClockTime::NONE); let mut consumed = 0; assert!( Meta::deserialize(buffer_dest.get_mut().unwrap(), &[0, 1, 2], &mut consumed).is_err() ); assert_eq!(consumed, 0); } } gstreamer-0.23.5/src/miniobject.rs000064400000000000000000000616451046102023000152000ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::fmt; use crate::{ffi, prelude::*}; use glib::translate::*; pub trait IsMiniObject: AsRef + FromGlibPtrFull<*mut Self::FfiType> + Send + Sync + 'static { type RefType; type FfiType; } #[macro_export] macro_rules! mini_object_wrapper ( ($name:ident, $ref_name:ident, $ffi_name:path) => { #[repr(transparent)] pub struct $name { obj: std::ptr::NonNull<$ffi_name>, } #[repr(transparent)] pub struct $ref_name($ffi_name); impl $crate::miniobject::IsMiniObject for $name { type RefType = $ref_name; type FfiType = $ffi_name; } impl $name { #[inline] pub unsafe fn from_glib_ptr_borrow( ptr: &*mut $ffi_name, ) -> &Self { debug_assert_eq!(std::mem::size_of::<$name>(), std::mem::size_of::<$crate::glib::ffi::gpointer>()); debug_assert!(!ptr.is_null()); &*(ptr as *const *mut $ffi_name as *const $name) } #[inline] pub unsafe fn from_glib_none(ptr: *const $ffi_name) -> Self { skip_assert_initialized!(); debug_assert!(!ptr.is_null()); $crate::ffi::gst_mini_object_ref(ptr as *mut $crate::ffi::GstMiniObject); $name { obj: std::ptr::NonNull::new_unchecked(ptr as *mut $ffi_name), } } #[inline] pub unsafe fn from_glib_full(ptr: *const $ffi_name) -> Self { skip_assert_initialized!(); debug_assert!(!ptr.is_null()); $name { obj: std::ptr::NonNull::new_unchecked(ptr as *mut $ffi_name), } } #[inline] pub unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> $crate::glib::translate::Borrowed { skip_assert_initialized!(); debug_assert!(!ptr.is_null()); $crate::glib::translate::Borrowed::new($name { obj: std::ptr::NonNull::new_unchecked(ptr as *mut $ffi_name), }) } #[inline] pub unsafe fn replace_ptr(&mut self, ptr: *mut $ffi_name) { debug_assert!(!ptr.is_null()); self.obj = std::ptr::NonNull::new_unchecked(ptr); } #[inline] #[doc(alias = "gst_mini_object_make_writable")] pub fn make_mut(&mut self) -> &mut $ref_name { unsafe { if self.is_writable() { return &mut *(self.obj.as_mut() as *mut $ffi_name as *mut $ref_name); } let ptr = $crate::ffi::gst_mini_object_make_writable( self.as_mut_ptr() as *mut $crate::ffi::GstMiniObject ); self.replace_ptr(ptr as *mut $ffi_name); debug_assert!(self.is_writable()); &mut *(self.obj.as_mut() as *mut $ffi_name as *mut $ref_name) } } #[inline] pub fn get_mut(&mut self) -> Option<&mut $ref_name> { if self.is_writable() { Some(unsafe { &mut *(self.obj.as_mut() as *mut $ffi_name as *mut $ref_name) }) } else { None } } #[doc(alias = "gst_mini_object_is_writable")] #[inline] pub fn is_writable(&self) -> bool { unsafe { $crate::glib::translate::from_glib($crate::ffi::gst_mini_object_is_writable( self.as_ptr() as *const $crate::ffi::GstMiniObject )) } } #[must_use] #[inline] pub fn upcast(self) -> $crate::miniobject::MiniObject { use $crate::glib::translate::IntoGlibPtr; unsafe { from_glib_full(self.into_glib_ptr() as *mut $crate::ffi::GstMiniObject) } } } impl $crate::glib::translate::IntoGlibPtr<*mut $ffi_name> for $name { #[inline] unsafe fn into_glib_ptr(self) -> *mut $ffi_name { let s = std::mem::ManuallyDrop::new(self); s.as_mut_ptr() } } impl Clone for $name { #[inline] fn clone(&self) -> Self { unsafe { $name::from_glib_none(self.as_ptr()) } } } impl Drop for $name { #[inline] fn drop(&mut self) { unsafe { $crate::ffi::gst_mini_object_unref(self.as_mut_ptr() as *mut $crate::ffi::GstMiniObject); } } } impl std::ops::Deref for $name { type Target = $ref_name; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self.obj.as_ref() as *const $ffi_name as *const $ref_name) } } } impl AsRef<$ref_name> for $name { #[inline] fn as_ref(&self) -> &$ref_name { &*self } } impl std::borrow::Borrow<$ref_name> for $name { #[inline] fn borrow(&self) -> &$ref_name { &*self } } impl<'a> $crate::glib::translate::ToGlibPtr<'a, *const $ffi_name> for $name { type Storage = std::marker::PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> $crate::glib::translate::Stash<'a, *const $ffi_name, Self> { $crate::glib::translate::Stash(self.as_ptr(), std::marker::PhantomData) } #[inline] fn to_glib_full(&self) -> *const $ffi_name { unsafe { $crate::ffi::gst_mini_object_ref(self.as_mut_ptr() as *mut $crate::ffi::GstMiniObject); self.as_ptr() } } } impl<'a> $crate::glib::translate::ToGlibPtr<'a, *mut $ffi_name> for $name { type Storage = std::marker::PhantomData<&'a Self>; #[inline] fn to_glib_none(&'a self) -> $crate::glib::translate::Stash<'a, *mut $ffi_name, Self> { $crate::glib::translate::Stash(self.as_mut_ptr(), std::marker::PhantomData) } #[inline] fn to_glib_full(&self) -> *mut $ffi_name { unsafe { $crate::ffi::gst_mini_object_ref(self.as_mut_ptr() as *mut $crate::ffi::GstMiniObject); self.as_mut_ptr() } } } impl<'a> $crate::glib::translate::ToGlibPtrMut<'a, *mut $ffi_name> for $name { type Storage = std::marker::PhantomData<&'a mut Self>; #[inline] fn to_glib_none_mut(&'_ mut self) -> $crate::glib::translate::StashMut<*mut $ffi_name, Self> { self.make_mut(); $crate::glib::translate::StashMut(self.as_mut_ptr(), std::marker::PhantomData) } } impl<'a> $crate::glib::translate::ToGlibContainerFromSlice<'a, *mut *mut $ffi_name> for $name { #[allow(clippy::type_complexity)] type Storage = ( std::marker::PhantomData<&'a [$name]>, Option>, ); fn to_glib_none_from_slice(t: &'a [$name]) -> (*mut *mut $ffi_name, Self::Storage) { skip_assert_initialized!(); let mut v_ptr = Vec::with_capacity(t.len() + 1); unsafe { let ptr = v_ptr.as_mut_ptr(); std::ptr::copy_nonoverlapping(t.as_ptr() as *mut *mut $ffi_name, ptr, t.len()); std::ptr::write(ptr.add(t.len()), std::ptr::null_mut()); v_ptr.set_len(t.len() + 1); } (v_ptr.as_ptr() as *mut *mut $ffi_name, (std::marker::PhantomData, Some(v_ptr))) } fn to_glib_container_from_slice(t: &'a [$name]) -> (*mut *mut $ffi_name, Self::Storage) { skip_assert_initialized!(); let v_ptr = unsafe { let v_ptr = $crate::glib::ffi::g_malloc(std::mem::size_of::<*mut $ffi_name>() * t.len() + 1) as *mut *mut $ffi_name; std::ptr::copy_nonoverlapping(t.as_ptr() as *mut *mut $ffi_name, v_ptr, t.len()); std::ptr::write(v_ptr.add(t.len()), std::ptr::null_mut()); v_ptr }; (v_ptr, (std::marker::PhantomData, None)) } fn to_glib_full_from_slice(t: &[$name]) -> *mut *mut $ffi_name { skip_assert_initialized!(); unsafe { let v_ptr = $crate::glib::ffi::g_malloc(std::mem::size_of::<*mut $ffi_name>() * t.len() + 1) as *mut *mut $ffi_name; for (i, s) in t.iter().enumerate() { std::ptr::write(v_ptr.add(i), $crate::glib::translate::ToGlibPtr::to_glib_full(s)); } std::ptr::write(v_ptr.add(t.len()), std::ptr::null_mut()); v_ptr } } } impl<'a> $crate::glib::translate::ToGlibContainerFromSlice<'a, *const *mut $ffi_name> for $name { #[allow(clippy::type_complexity)] type Storage = ( std::marker::PhantomData<&'a [$name]>, Option>, ); fn to_glib_none_from_slice(t: &'a [$name]) -> (*const *mut $ffi_name, Self::Storage) { skip_assert_initialized!(); let (ptr, stash) = $crate::glib::translate::ToGlibContainerFromSlice::<'a, *mut *mut $ffi_name>::to_glib_none_from_slice(t); (ptr as *const *mut $ffi_name, stash) } fn to_glib_container_from_slice(_: &'a [$name]) -> (*const *mut $ffi_name, Self::Storage) { skip_assert_initialized!(); // Can't have consumer free a *const pointer unimplemented!() } fn to_glib_full_from_slice(_: &[$name]) -> *const *mut $ffi_name { skip_assert_initialized!(); // Can't have consumer free a *const pointer unimplemented!() } } impl $crate::glib::translate::FromGlibPtrNone<*const $ffi_name> for $name { #[inline] unsafe fn from_glib_none(ptr: *const $ffi_name) -> Self { Self::from_glib_none(ptr) } } impl $crate::glib::translate::FromGlibPtrNone<*mut $ffi_name> for $name { #[inline] unsafe fn from_glib_none(ptr: *mut $ffi_name) -> Self { Self::from_glib_none(ptr) } } impl $crate::glib::translate::FromGlibPtrFull<*const $ffi_name> for $name { #[inline] unsafe fn from_glib_full(ptr: *const $ffi_name) -> Self { Self::from_glib_full(ptr) } } impl $crate::glib::translate::FromGlibPtrFull<*mut $ffi_name> for $name { #[inline] unsafe fn from_glib_full(ptr: *mut $ffi_name) -> Self { Self::from_glib_full(ptr) } } impl $crate::glib::translate::FromGlibPtrBorrow<*const $ffi_name> for $name { #[inline] unsafe fn from_glib_borrow(ptr: *const $ffi_name) -> $crate::glib::translate::Borrowed { Self::from_glib_borrow(ptr) } } impl $crate::glib::translate::FromGlibPtrBorrow<*mut $ffi_name> for $name { #[inline] unsafe fn from_glib_borrow(ptr: *mut $ffi_name) -> $crate::glib::translate::Borrowed { Self::from_glib_borrow(ptr) } } impl $crate::glib::translate::FromGlibContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::::with_capacity(num); let res_ptr = res.as_mut_ptr(); for i in 0..num { ::std::ptr::write(res_ptr.add(i), $crate::glib::translate::from_glib_none(std::ptr::read(ptr.add(i)))); } res.set_len(num); res } unsafe fn from_glib_container_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { let res = $crate::glib::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, num); $crate::glib::ffi::g_free(ptr as *mut _); res } unsafe fn from_glib_full_num_as_vec(ptr: *mut *mut $ffi_name, num: usize) -> Vec { if num == 0 || ptr.is_null() { return Vec::new(); } let mut res = Vec::with_capacity(num); let res_ptr = res.as_mut_ptr(); ::std::ptr::copy_nonoverlapping(ptr as *mut Self, res_ptr, num); res.set_len(num); $crate::glib::ffi::g_free(ptr as *mut _); res } } impl $crate::glib::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *mut *mut $ffi_name> for $name { unsafe fn from_glib_none_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::glib::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr, glib::translate::c_ptr_array_len(ptr)) } unsafe fn from_glib_container_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::glib::translate::FromGlibContainerAsVec::from_glib_container_num_as_vec(ptr, glib::translate::c_ptr_array_len(ptr)) } unsafe fn from_glib_full_as_vec(ptr: *mut *mut $ffi_name) -> Vec { $crate::glib::translate::FromGlibContainerAsVec::from_glib_full_num_as_vec(ptr, glib::translate::c_ptr_array_len(ptr)) } } impl $crate::glib::translate::FromGlibContainerAsVec<*mut $ffi_name, *const *mut $ffi_name> for $name { unsafe fn from_glib_none_num_as_vec(ptr: *const *mut $ffi_name, num: usize) -> Vec { $crate::glib::translate::FromGlibContainerAsVec::from_glib_none_num_as_vec(ptr as *mut *mut _, num) } unsafe fn from_glib_container_num_as_vec(_: *const *mut $ffi_name, _: usize) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_num_as_vec(_: *const *mut $ffi_name, _: usize) -> Vec { // Can't free a *const unimplemented!() } } impl $crate::glib::translate::FromGlibPtrArrayContainerAsVec<*mut $ffi_name, *const *mut $ffi_name> for $name { unsafe fn from_glib_none_as_vec(ptr: *const *mut $ffi_name) -> Vec { $crate::glib::translate::FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(ptr as *mut *mut _) } unsafe fn from_glib_container_as_vec(_: *const *mut $ffi_name) -> Vec { // Can't free a *const unimplemented!() } unsafe fn from_glib_full_as_vec(_: *const *mut $ffi_name) -> Vec { // Can't free a *const unimplemented!() } } impl $crate::glib::translate::GlibPtrDefault for $name { type GlibType = *mut $ffi_name; } unsafe impl $crate::glib::translate::TransparentPtrType for $name {} impl $ref_name { #[inline] pub fn as_ptr(&self) -> *const $ffi_name { self as *const Self as *const $ffi_name } #[inline] pub fn as_mut_ptr(&self) -> *mut $ffi_name { self as *const Self as *mut $ffi_name } #[inline] pub unsafe fn from_ptr<'a>(ptr: *const $ffi_name) -> &'a Self { debug_assert!(!ptr.is_null()); &*(ptr as *const Self) } #[inline] pub unsafe fn from_mut_ptr<'a>(ptr: *mut $ffi_name) -> &'a mut Self { debug_assert!(!ptr.is_null()); debug_assert_ne!( $crate::ffi::gst_mini_object_is_writable(ptr as *mut $crate::ffi::GstMiniObject), $crate::glib::ffi::GFALSE ); &mut *(ptr as *mut Self) } #[doc(alias = "gst_mini_object_copy")] #[inline] pub fn copy(&self) -> $name { unsafe { $name::from_glib_full($crate::ffi::gst_mini_object_copy( self.as_ptr() as *const $crate::ffi::GstMiniObject ) as *const $ffi_name) } } #[inline] pub fn upcast_ref(&self) -> &$crate::miniobject::MiniObjectRef { unsafe { &*(self.as_ptr() as *const $crate::miniobject::MiniObjectRef) } } #[inline] pub fn upcast_mut(&mut self) -> &mut $crate::miniobject::MiniObjectRef { unsafe { &mut *(self.as_mut_ptr() as *mut $crate::miniobject::MiniObjectRef) } } #[inline] pub fn ptr_eq(this: &$ref_name, other: &$ref_name) -> bool { skip_assert_initialized!(); this.as_ptr() == other.as_ptr() } } impl $crate::glib::translate::GlibPtrDefault for $ref_name { type GlibType = *mut $ffi_name; } impl ToOwned for $ref_name { type Owned = $name; #[inline] fn to_owned(&self) -> $name { self.copy() } } unsafe impl Sync for $ref_name {} unsafe impl Send for $ref_name {} unsafe impl Sync for $name {} unsafe impl Send for $name {} }; ($name:ident, $ref_name:ident, $ffi_name:path, $get_type:expr) => { $crate::mini_object_wrapper!($name, $ref_name, $ffi_name); impl $crate::glib::types::StaticType for $name { #[inline] fn static_type() -> $crate::glib::types::Type { $ref_name::static_type() } } #[allow(clippy::redundant_closure_call)] impl $crate::glib::types::StaticType for $ref_name { #[inline] fn static_type() -> $crate::glib::types::Type { #[allow(clippy::macro_metavars_in_unsafe)] unsafe { $crate::glib::translate::from_glib($get_type()) } } } impl glib::value::ValueType for $name { type Type = Self; } impl glib::value::ValueTypeOptional for $name { } unsafe impl<'a> $crate::glib::value::FromValue<'a> for $name { type Checker = $crate::glib::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a $crate::glib::Value) -> Self { skip_assert_initialized!(); $crate::glib::translate::from_glib_none( $crate::glib::gobject_ffi::g_value_get_boxed($crate::glib::translate::ToGlibPtr::to_glib_none(value).0) as *mut $ffi_name ) } } unsafe impl<'a> $crate::glib::value::FromValue<'a> for &'a $name { type Checker = $crate::glib::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a $crate::glib::Value) -> Self { skip_assert_initialized!(); let value = &*(value as *const $crate::glib::Value as *const $crate::glib::gobject_ffi::GValue); $name::from_glib_ptr_borrow(&*(&value.data[0].v_pointer as *const $crate::glib::ffi::gpointer as *const *mut $ffi_name)) } } impl $crate::glib::value::ToValue for $name { #[inline] fn to_value(&self) -> $crate::glib::Value { let mut value = $crate::glib::Value::for_value_type::(); unsafe { $crate::glib::gobject_ffi::g_value_set_boxed( $crate::glib::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::glib::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(self).0 as *mut _, ) } value } #[inline] fn value_type(&self) -> $crate::glib::Type { ::static_type() } } impl $crate::glib::value::ToValueOptional for $name { #[inline] fn to_value_optional(s: Option<&Self>) -> $crate::glib::Value { skip_assert_initialized!(); let mut value = $crate::glib::Value::for_value_type::(); unsafe { $crate::glib::gobject_ffi::g_value_set_boxed( $crate::glib::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::glib::translate::ToGlibPtr::<*const $ffi_name>::to_glib_none(&s).0 as *mut _, ) } value } } impl From<$name> for $crate::glib::Value { #[inline] fn from(v: $name) -> $crate::glib::Value { skip_assert_initialized!(); let mut value = $crate::glib::Value::for_value_type::<$name>(); unsafe { $crate::glib::gobject_ffi::g_value_take_boxed( $crate::glib::translate::ToGlibPtrMut::to_glib_none_mut(&mut value).0, $crate::glib::translate::IntoGlibPtr::<*mut $ffi_name>::into_glib_ptr(v) as *mut _, ) } value } } unsafe impl<'a> $crate::glib::value::FromValue<'a> for &'a $ref_name { type Checker = $crate::glib::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a $crate::glib::Value) -> Self { skip_assert_initialized!(); &*($crate::glib::gobject_ffi::g_value_get_boxed($crate::glib::translate::ToGlibPtr::to_glib_none(value).0) as *const $ref_name) } } // Can't have SetValue/SetValueOptional impls as otherwise one could use it to get // immutable references from a mutable reference without borrowing via the value impl $crate::glib::prelude::HasParamSpec for $name { type ParamSpec = $crate::glib::ParamSpecBoxed; type SetValue = Self; type BuilderFn = fn(&str) -> $crate::glib::ParamSpecBoxedBuilder; fn param_spec_builder() -> Self::BuilderFn { |name| Self::ParamSpec::builder(name) } } }; ); #[cfg(not(any(feature = "v1_20", docsrs)))] mini_object_wrapper!(MiniObject, MiniObjectRef, ffi::GstMiniObject); #[cfg(feature = "v1_20")] mini_object_wrapper!(MiniObject, MiniObjectRef, ffi::GstMiniObject, || { ffi::gst_mini_object_get_type() }); impl MiniObject { #[inline] pub fn downcast(self) -> Result { if self.type_().is_a(T::static_type()) { unsafe { Ok(from_glib_full(self.into_glib_ptr() as *mut T::FfiType)) } } else { Err(self) } } } impl fmt::Debug for MiniObject { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_ref().fmt(f) } } impl fmt::Debug for MiniObjectRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("MiniObject") .field("ptr", &self.as_ptr()) .field("type", &self.type_()) .finish() } } impl MiniObjectRef { #[inline] pub fn type_(&self) -> glib::Type { unsafe { from_glib((*self.as_ptr()).type_) } } #[inline] pub fn downcast_ref(&self) -> Option<&T::RefType> { if self.type_().is_a(T::static_type()) { unsafe { Some(&*(self as *const Self as *const T::RefType)) } } else { None } } #[inline] pub fn downcast_mut(&mut self) -> Option<&mut T::RefType> { if self.type_().is_a(T::static_type()) { unsafe { Some(&mut *(self as *mut Self as *mut T::RefType)) } } else { None } } } gstreamer-0.23.5/src/object.rs000064400000000000000000000106751046102023000143200ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::{prelude::*, signal::SignalHandlerId, translate::*}; use crate::{ffi, ClockTime, Object, ObjectFlags}; mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait GstObjectExtManual: sealed::Sealed + IsA + 'static { #[doc(alias = "deep-notify")] fn connect_deep_notify< F: Fn(&Self, &crate::Object, &glib::ParamSpec) + Send + Sync + 'static, >( &self, name: Option<&str>, f: F, ) -> SignalHandlerId { let signal_name = if let Some(name) = name { format!("deep-notify::{name}") } else { "deep-notify".into() }; let obj: Borrowed = unsafe { from_glib_borrow(self.as_ptr() as *mut glib::gobject_ffi::GObject) }; obj.connect(signal_name.as_str(), false, move |values| { // It would be nice to display the actual signal name in the panic messages below, // but that would require to copy `signal_name` so as to move it into the closure // which seems too much for the messages of development errors let obj: Self = unsafe { values[0] .get::() .unwrap_or_else(|err| panic!("Object signal \"deep-notify\": values[0]: {err}")) .unsafe_cast() }; let prop_obj: crate::Object = values[1] .get() .unwrap_or_else(|err| panic!("Object signal \"deep-notify\": values[1]: {err}")); let pspec = unsafe { let pspec = glib::gobject_ffi::g_value_get_param(values[2].to_glib_none().0); from_glib_none(pspec) }; f(&obj, &prop_obj, &pspec); None }) } fn set_object_flags(&self, flags: ObjectFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags |= flags.into_glib(); } } fn unset_object_flags(&self, flags: ObjectFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags &= !flags.into_glib(); } } #[doc(alias = "get_object_flags")] fn object_flags(&self) -> ObjectFlags { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); from_glib((*ptr).flags) } } #[doc(alias = "get_g_value_array")] #[doc(alias = "gst_object_get_g_value_array")] fn g_value_array( &self, property_name: &str, timestamp: ClockTime, interval: ClockTime, values: &mut [glib::Value], ) -> Result<(), glib::error::BoolError> { let n_values = values.len() as u32; unsafe { glib::result_from_gboolean!( ffi::gst_object_get_g_value_array( self.as_ref().to_glib_none().0, property_name.to_glib_none().0, timestamp.into_glib(), interval.into_glib(), n_values, values.as_mut_ptr() as *mut glib::gobject_ffi::GValue, ), "Failed to get value array" ) } } #[inline] fn object_lock(&self) -> crate::utils::ObjectLockGuard { crate::utils::ObjectLockGuard::acquire(self) } } impl> GstObjectExtManual for O {} #[cfg(test)] mod tests { use std::sync::{Arc, Mutex}; use super::*; use crate::prelude::*; #[test] fn test_deep_notify() { crate::init().unwrap(); let bin = crate::Bin::new(); let identity = crate::ElementFactory::make("identity") .name("id") .build() .unwrap(); bin.add(&identity).unwrap(); let notify = Arc::new(Mutex::new(None)); let notify_clone = notify.clone(); bin.connect_deep_notify(None, move |_, id, prop| { *notify_clone.lock().unwrap() = Some((id.clone(), prop.name())); }); identity.set_property("silent", false); assert_eq!( *notify.lock().unwrap(), Some((identity.upcast::(), "silent")) ); } } gstreamer-0.23.5/src/pad.rs000064400000000000000000002605031046102023000136130ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ mem, num::NonZeroU64, ops::ControlFlow, panic::{self, AssertUnwindSafe}, ptr, }; use glib::{ffi::gpointer, prelude::*, translate::*}; use crate::{ ffi, format::{FormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic}, prelude::*, Buffer, BufferList, Event, FlowError, FlowReturn, FlowSuccess, Format, GenericFormattedValue, LoggableError, Pad, PadFlags, PadProbeReturn, PadProbeType, Query, QueryRef, StaticPadTemplate, }; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct PadProbeId(NonZeroU64); impl IntoGlib for PadProbeId { type GlibType = libc::c_ulong; #[inline] fn into_glib(self) -> libc::c_ulong { self.0.get() as libc::c_ulong } } impl FromGlib for PadProbeId { #[inline] unsafe fn from_glib(val: libc::c_ulong) -> PadProbeId { skip_assert_initialized!(); debug_assert_ne!(val, 0); PadProbeId(NonZeroU64::new_unchecked(val as _)) } } impl PadProbeId { #[inline] pub fn as_raw(&self) -> libc::c_ulong { self.0.get() as libc::c_ulong } } #[doc(alias = "GstPadProbeInfo")] #[derive(Debug)] pub struct PadProbeInfo<'a> { pub mask: PadProbeType, pub id: Option, pub offset: u64, pub size: u32, pub data: Option>, pub flow_res: Result, } impl PadProbeInfo<'_> { pub fn buffer(&self) -> Option<&Buffer> { match self.data { Some(PadProbeData::Buffer(ref buffer)) => Some(buffer), _ => None, } } pub fn buffer_mut(&mut self) -> Option<&mut Buffer> { match self.data { Some(PadProbeData::Buffer(ref mut buffer)) => Some(buffer), _ => None, } } pub fn buffer_list(&self) -> Option<&BufferList> { match self.data { Some(PadProbeData::BufferList(ref buffer_list)) => Some(buffer_list), _ => None, } } pub fn buffer_list_mut(&mut self) -> Option<&mut BufferList> { match self.data { Some(PadProbeData::BufferList(ref mut buffer_list)) => Some(buffer_list), _ => None, } } pub fn query(&self) -> Option<&QueryRef> { match self.data { Some(PadProbeData::Query(ref query)) => Some(*query), _ => None, } } pub fn query_mut(&mut self) -> Option<&mut QueryRef> { match self.data { Some(PadProbeData::Query(ref mut query)) => Some(*query), _ => None, } } pub fn event(&self) -> Option<&Event> { match self.data { Some(PadProbeData::Event(ref event)) => Some(event), _ => None, } } pub fn event_mut(&mut self) -> Option<&mut Event> { match self.data { Some(PadProbeData::Event(ref mut event)) => Some(event), _ => None, } } // rustdoc-stripper-ignore-next /// Takes over the buffer in the probe info. As the data is no longer valid for the caller, the /// probe will be considered dropped after this point. pub fn take_buffer(&mut self) -> Option { if matches!(self.data, Some(PadProbeData::Buffer(..))) { match self.data.take() { Some(PadProbeData::Buffer(b)) => Some(b), _ => unreachable!(), } } else { None } } // rustdoc-stripper-ignore-next /// Takes over the buffer in the probe info. As the data is no longer valid for the caller, the /// probe will be considered dropped after this point. pub fn take_buffer_list(&mut self) -> Option { if matches!(self.data, Some(PadProbeData::BufferList(..))) { match self.data.take() { Some(PadProbeData::BufferList(b)) => Some(b), _ => unreachable!(), } } else { None } } // rustdoc-stripper-ignore-next /// Takes over the event in the probe info. As the data is no longer valid for the caller, the /// probe will be considered dropped after this point. pub fn take_event(&mut self) -> Option { if matches!(self.data, Some(PadProbeData::Event(..))) { match self.data.take() { Some(PadProbeData::Event(e)) => Some(e), _ => unreachable!(), } } else { None } } } #[derive(Debug)] pub enum PadProbeData<'a> { Buffer(Buffer), BufferList(BufferList), Query(&'a mut QueryRef), Event(Event), #[doc(hidden)] __Unknown(*mut ffi::GstMiniObject), } unsafe impl Send for PadProbeData<'_> {} unsafe impl Sync for PadProbeData<'_> {} #[derive(Debug)] #[must_use = "if unused the StreamLock will immediately unlock"] pub struct StreamLock<'a>(&'a Pad); impl Drop for StreamLock<'_> { #[inline] fn drop(&mut self) { unsafe { let pad: *mut ffi::GstPad = self.0.to_glib_none().0; glib::ffi::g_rec_mutex_unlock(&mut (*pad).stream_rec_lock); } } } #[derive(Debug)] pub enum PadGetRangeSuccess { FilledBuffer, NewBuffer(crate::Buffer), } #[derive(Debug)] pub enum EventForeachAction { Keep, Remove, Replace(Event), } mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait PadExtManual: sealed::Sealed + IsA + 'static { #[doc(alias = "gst_pad_add_probe")] fn add_probe(&self, mask: PadProbeType, func: F) -> Option where F: Fn(&Self, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static, { unsafe { let func_box: Box = Box::new(func); let id = ffi::gst_pad_add_probe( self.as_ref().to_glib_none().0, mask.into_glib(), Some(trampoline_pad_probe::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); if id == 0 { None } else { Some(from_glib(id)) } } } #[doc(alias = "gst_pad_remove_probe")] fn remove_probe(&self, id: PadProbeId) { unsafe { ffi::gst_pad_remove_probe(self.as_ref().to_glib_none().0, id.into_glib()); } } #[doc(alias = "gst_pad_pull_range")] fn pull_range(&self, offset: u64, size: u32) -> Result { unsafe { let mut buffer = ptr::null_mut(); FlowSuccess::try_from_glib(ffi::gst_pad_pull_range( self.as_ref().to_glib_none().0, offset, size, &mut buffer, )) .map(|_| from_glib_full(buffer)) } } fn pull_range_fill( &self, offset: u64, buffer: &mut crate::BufferRef, size: u32, ) -> Result<(), FlowError> { assert!(buffer.size() >= size as usize); unsafe { let mut buffer_ref = buffer.as_mut_ptr(); FlowSuccess::try_from_glib(ffi::gst_pad_pull_range( self.as_ref().to_glib_none().0, offset, size, &mut buffer_ref, )) .and_then(|_| { if buffer.as_mut_ptr() != buffer_ref { ffi::gst_mini_object_unref(buffer_ref as *mut _); Err(crate::FlowError::Error) } else { Ok(()) } }) } } #[doc(alias = "get_range")] #[doc(alias = "gst_pad_get_range")] fn range(&self, offset: u64, size: u32) -> Result { unsafe { let mut buffer = ptr::null_mut(); FlowSuccess::try_from_glib(ffi::gst_pad_get_range( self.as_ref().to_glib_none().0, offset, size, &mut buffer, )) .map(|_| from_glib_full(buffer)) } } #[doc(alias = "get_range_fill")] fn range_fill( &self, offset: u64, buffer: &mut crate::BufferRef, size: u32, ) -> Result<(), FlowError> { assert!(buffer.size() >= size as usize); unsafe { let mut buffer_ref = buffer.as_mut_ptr(); FlowSuccess::try_from_glib(ffi::gst_pad_get_range( self.as_ref().to_glib_none().0, offset, size, &mut buffer_ref, )) .and_then(|_| { if buffer.as_mut_ptr() != buffer_ref { ffi::gst_mini_object_unref(buffer_ref as *mut _); Err(crate::FlowError::Error) } else { Ok(()) } }) } } #[doc(alias = "gst_pad_peer_query")] fn peer_query(&self, query: &mut QueryRef) -> bool { unsafe { from_glib(ffi::gst_pad_peer_query( self.as_ref().to_glib_none().0, query.as_mut_ptr(), )) } } #[doc(alias = "gst_pad_query")] fn query(&self, query: &mut QueryRef) -> bool { unsafe { from_glib(ffi::gst_pad_query( self.as_ref().to_glib_none().0, query.as_mut_ptr(), )) } } #[doc(alias = "gst_pad_proxy_query_caps")] fn proxy_query_caps(&self, query: &mut QueryRef) -> bool { unsafe { from_glib(ffi::gst_pad_proxy_query_caps( self.as_ref().to_glib_none().0, query.as_mut_ptr(), )) } } #[doc(alias = "gst_pad_proxy_query_accept_caps")] fn proxy_query_accept_caps(&self, query: &mut QueryRef) -> bool { unsafe { from_glib(ffi::gst_pad_proxy_query_accept_caps( self.as_ref().to_glib_none().0, query.as_mut_ptr(), )) } } #[doc(alias = "gst_pad_push_event")] fn push_event(&self, event: impl Into) -> bool { unsafe { from_glib(ffi::gst_pad_push_event( self.as_ref().to_glib_none().0, event.into().into_glib_ptr(), )) } } #[doc(alias = "gst_pad_send_event")] fn send_event(&self, event: impl Into) -> bool { unsafe { from_glib(ffi::gst_pad_send_event( self.as_ref().to_glib_none().0, event.into().into_glib_ptr(), )) } } #[doc(alias = "gst_pad_iterate_internal_links")] fn iterate_internal_links(&self) -> crate::Iterator { unsafe { from_glib_full(ffi::gst_pad_iterate_internal_links( self.as_ref().to_glib_none().0, )) } } fn stream_lock(&self) -> StreamLock { unsafe { let ptr: &mut ffi::GstPad = &mut *(self.as_ptr() as *mut _); glib::ffi::g_rec_mutex_lock(&mut ptr.stream_rec_lock); StreamLock(self.upcast_ref()) } } #[doc(alias = "gst_pad_set_activate_function")] #[doc(alias = "gst_pad_set_activate_function_full")] unsafe fn set_activate_function(&self, func: F) where F: Fn(&Self, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static, { let func_box: Box = Box::new(func); ffi::gst_pad_set_activate_function_full( self.as_ref().to_glib_none().0, Some(trampoline_activate_function::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); } #[doc(alias = "gst_pad_set_activatemode_function")] #[doc(alias = "gst_pad_set_activatemode_function_full")] unsafe fn set_activatemode_function(&self, func: F) where F: Fn(&Self, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError> + Send + Sync + 'static, { let func_box: Box = Box::new(func); ffi::gst_pad_set_activatemode_function_full( self.as_ref().to_glib_none().0, Some(trampoline_activatemode_function::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); } #[doc(alias = "gst_pad_set_chain_function")] #[doc(alias = "gst_pad_set_chain_function_full")] unsafe fn set_chain_function(&self, func: F) where F: Fn(&Self, Option<&crate::Object>, crate::Buffer) -> Result + Send + Sync + 'static, { let func_box: Box = Box::new(func); ffi::gst_pad_set_chain_function_full( self.as_ref().to_glib_none().0, Some(trampoline_chain_function::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); } #[doc(alias = "gst_pad_set_chain_list_function")] #[doc(alias = "gst_pad_set_chain_list_function_full")] unsafe fn set_chain_list_function(&self, func: F) where F: Fn(&Self, Option<&crate::Object>, crate::BufferList) -> Result + Send + Sync + 'static, { let func_box: Box = Box::new(func); ffi::gst_pad_set_chain_list_function_full( self.as_ref().to_glib_none().0, Some(trampoline_chain_list_function::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); } #[doc(alias = "gst_pad_set_event_function")] #[doc(alias = "gst_pad_set_event_function_full")] unsafe fn set_event_function(&self, func: F) where F: Fn(&Self, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static, { let func_box: Box = Box::new(func); ffi::gst_pad_set_event_function_full( self.as_ref().to_glib_none().0, Some(trampoline_event_function::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); } #[doc(alias = "gst_pad_set_event_full_function")] #[doc(alias = "gst_pad_set_event_full_function_full")] unsafe fn set_event_full_function(&self, func: F) where F: Fn(&Self, Option<&crate::Object>, crate::Event) -> Result + Send + Sync + 'static, { let func_box: Box = Box::new(func); ffi::gst_pad_set_event_full_function_full( self.as_ref().to_glib_none().0, Some(trampoline_event_full_function::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); } #[doc(alias = "gst_pad_set_getrange_function")] #[doc(alias = "gst_pad_set_getrange_function_full")] unsafe fn set_getrange_function(&self, func: F) where F: Fn( &Self, Option<&crate::Object>, u64, Option<&mut crate::BufferRef>, u32, ) -> Result + Send + Sync + 'static, { let func_box: Box = Box::new(func); ffi::gst_pad_set_getrange_function_full( self.as_ref().to_glib_none().0, Some(trampoline_getrange_function::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); } #[doc(alias = "gst_pad_set_iterate_internal_links_function")] #[doc(alias = "gst_pad_set_iterate_internal_links_function_full")] unsafe fn set_iterate_internal_links_function(&self, func: F) where F: Fn(&Self, Option<&crate::Object>) -> crate::Iterator + Send + Sync + 'static, { let func_box: Box = Box::new(func); ffi::gst_pad_set_iterate_internal_links_function_full( self.as_ref().to_glib_none().0, Some(trampoline_iterate_internal_links_function::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); } #[doc(alias = "gst_pad_set_link_function")] #[doc(alias = "gst_pad_set_link_function_full")] unsafe fn set_link_function(&self, func: F) where F: Fn( &Self, Option<&crate::Object>, &Pad, ) -> Result + Send + Sync + 'static, { let func_box: Box = Box::new(func); ffi::gst_pad_set_link_function_full( self.as_ref().to_glib_none().0, Some(trampoline_link_function::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); } #[doc(alias = "gst_pad_set_query_function")] #[doc(alias = "gst_pad_set_query_function_full")] unsafe fn set_query_function(&self, func: F) where F: Fn(&Self, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static, { let func_box: Box = Box::new(func); ffi::gst_pad_set_query_function_full( self.as_ref().to_glib_none().0, Some(trampoline_query_function::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); } #[doc(alias = "gst_pad_set_unlink_function")] #[doc(alias = "gst_pad_set_unlink_function_full")] unsafe fn set_unlink_function(&self, func: F) where F: Fn(&Self, Option<&crate::Object>) + Send + Sync + 'static, { let func_box: Box = Box::new(func); ffi::gst_pad_set_unlink_function_full( self.as_ref().to_glib_none().0, Some(trampoline_unlink_function::), Box::into_raw(func_box) as gpointer, Some(destroy_closure::), ); } #[doc(alias = "gst_pad_start_task")] fn start_task(&self, func: F) -> Result<(), glib::BoolError> { unsafe extern "C" fn trampoline_pad_task(func: gpointer) { let (func, pad) = &mut *(func as *mut (F, *mut ffi::GstPad)); let pad = Pad::from_glib_borrow(*pad); let result = panic::catch_unwind(AssertUnwindSafe(func)); if let Err(err) = result { let element = match pad.parent_element() { Some(element) => element, None => panic::resume_unwind(err), }; if pad.pause_task().is_err() { crate::error!(crate::CAT_RUST, "could not stop pad task on panic"); } crate::subclass::post_panic_error_message(&element, pad.upcast_ref(), Some(err)); } } fn into_raw_pad_task( func: F, pad: *mut ffi::GstPad, ) -> gpointer { #[allow(clippy::type_complexity)] let func: Box<(F, *mut ffi::GstPad)> = Box::new((func, pad)); Box::into_raw(func) as gpointer } unsafe extern "C" fn destroy_closure_pad_task(ptr: gpointer) { let _ = Box::<(F, *mut ffi::GstPad)>::from_raw(ptr as *mut _); } unsafe { glib::result_from_gboolean!( ffi::gst_pad_start_task( self.as_ref().to_glib_none().0, Some(trampoline_pad_task::), into_raw_pad_task(func, self.upcast_ref().as_ptr()), Some(destroy_closure_pad_task::), ), "Failed to start pad task", ) } } #[doc(alias = "gst_pad_peer_query_convert")] fn peer_query_convert( &self, src_val: impl FormattedValue, ) -> Option { unsafe { let mut dest_val = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_peer_query_convert( self.as_ref().to_glib_none().0, src_val.format().into_glib(), src_val.into_raw_value(), U::default_format().into_glib(), dest_val.as_mut_ptr(), )); if ret { Some(U::from_raw(U::default_format(), dest_val.assume_init())) } else { None } } } #[doc(alias = "gst_pad_peer_query_convert")] fn peer_query_convert_generic( &self, src_val: impl FormattedValue, dest_format: Format, ) -> Option { unsafe { let mut dest_val = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_peer_query_convert( self.as_ref().to_glib_none().0, src_val.format().into_glib(), src_val.into_raw_value(), dest_format.into_glib(), dest_val.as_mut_ptr(), )); if ret { Some(GenericFormattedValue::new( dest_format, dest_val.assume_init(), )) } else { None } } } #[doc(alias = "gst_pad_peer_query_duration")] fn peer_query_duration(&self) -> Option { unsafe { let mut duration = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_peer_query_duration( self.as_ref().to_glib_none().0, T::default_format().into_glib(), duration.as_mut_ptr(), )); if ret { try_from_glib(duration.assume_init()).ok() } else { None } } } #[doc(alias = "gst_pad_peer_query_duration")] fn peer_query_duration_generic(&self, format: Format) -> Option { unsafe { let mut duration = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_peer_query_duration( self.as_ref().to_glib_none().0, format.into_glib(), duration.as_mut_ptr(), )); if ret { Some(GenericFormattedValue::new(format, duration.assume_init())) } else { None } } } #[doc(alias = "gst_pad_peer_query_position")] fn peer_query_position(&self) -> Option { unsafe { let mut cur = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_peer_query_position( self.as_ref().to_glib_none().0, T::default_format().into_glib(), cur.as_mut_ptr(), )); if ret { try_from_glib(cur.assume_init()).ok() } else { None } } } #[doc(alias = "gst_pad_peer_query_position")] fn peer_query_position_generic(&self, format: Format) -> Option { unsafe { let mut cur = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_peer_query_position( self.as_ref().to_glib_none().0, format.into_glib(), cur.as_mut_ptr(), )); if ret { Some(GenericFormattedValue::new(format, cur.assume_init())) } else { None } } } #[doc(alias = "gst_pad_query_convert")] fn query_convert( &self, src_val: impl FormattedValue, ) -> Option { unsafe { let mut dest_val = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_query_convert( self.as_ref().to_glib_none().0, src_val.format().into_glib(), src_val.into_raw_value(), U::default_format().into_glib(), dest_val.as_mut_ptr(), )); if ret { Some(U::from_raw(U::default_format(), dest_val.assume_init())) } else { None } } } #[doc(alias = "gst_pad_query_convert")] fn query_convert_generic( &self, src_val: impl FormattedValue, dest_format: Format, ) -> Option { unsafe { let mut dest_val = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_query_convert( self.as_ref().to_glib_none().0, src_val.format().into_glib(), src_val.into_raw_value(), dest_format.into_glib(), dest_val.as_mut_ptr(), )); if ret { Some(GenericFormattedValue::new( dest_format, dest_val.assume_init(), )) } else { None } } } #[doc(alias = "gst_pad_query_duration")] fn query_duration(&self) -> Option { unsafe { let mut duration = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_query_duration( self.as_ref().to_glib_none().0, T::default_format().into_glib(), duration.as_mut_ptr(), )); if ret { try_from_glib(duration.assume_init()).ok() } else { None } } } #[doc(alias = "gst_pad_query_duration")] fn query_duration_generic(&self, format: Format) -> Option { unsafe { let mut duration = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_query_duration( self.as_ref().to_glib_none().0, format.into_glib(), duration.as_mut_ptr(), )); if ret { Some(GenericFormattedValue::new(format, duration.assume_init())) } else { None } } } #[doc(alias = "gst_pad_query_position")] fn query_position(&self) -> Option { unsafe { let mut cur = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_query_position( self.as_ref().to_glib_none().0, T::default_format().into_glib(), cur.as_mut_ptr(), )); if ret { try_from_glib(cur.assume_init()).ok() } else { None } } } #[doc(alias = "gst_pad_query_position")] fn query_position_generic(&self, format: Format) -> Option { unsafe { let mut cur = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_pad_query_position( self.as_ref().to_glib_none().0, format.into_glib(), cur.as_mut_ptr(), )); if ret { Some(GenericFormattedValue::new(format, cur.assume_init())) } else { None } } } #[doc(alias = "get_mode")] #[doc(alias = "GST_PAD_MODE")] fn mode(&self) -> crate::PadMode { unsafe { let ptr: &ffi::GstPad = &*(self.as_ptr() as *const _); from_glib(ptr.mode) } } #[doc(alias = "gst_pad_sticky_events_foreach")] fn sticky_events_foreach< F: FnMut(&Event) -> ControlFlow, >( &self, func: F, ) { unsafe extern "C" fn trampoline< F: FnMut(&Event) -> ControlFlow, >( _pad: *mut ffi::GstPad, event: *mut *mut ffi::GstEvent, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let func = user_data as *mut F; let res = (*func)(&from_glib_borrow(*event)); let (do_continue, ev_action) = match res { ControlFlow::Continue(ev_action) => (glib::ffi::GTRUE, ev_action), ControlFlow::Break(ev_action) => (glib::ffi::GFALSE, ev_action), }; use EventForeachAction::*; match ev_action { Keep => (), // do nothing Remove => { ffi::gst_mini_object_unref(*event as *mut _); *event = ptr::null_mut(); } Replace(ev) => { ffi::gst_mini_object_unref(*event as *mut _); *event = ev.into_glib_ptr(); } } do_continue } unsafe { let mut func = func; let func_ptr = &mut func as *mut F as glib::ffi::gpointer; ffi::gst_pad_sticky_events_foreach( self.as_ref().to_glib_none().0, Some(trampoline::), func_ptr, ); } } #[doc(alias = "gst_pad_get_sticky_event")] #[doc(alias = "get_sticky_event")] fn sticky_event(&self, idx: u32) -> Option { unsafe { let ptr = ffi::gst_pad_get_sticky_event( self.as_ref().to_glib_none().0, T::TYPE.into_glib(), idx, ); if ptr.is_null() { None } else { Some(T::from_event(from_glib_full(ptr))) } } } fn set_pad_flags(&self, flags: PadFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags |= flags.into_glib(); } } fn unset_pad_flags(&self, flags: PadFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags &= !flags.into_glib(); } } #[doc(alias = "get_pad_flags")] fn pad_flags(&self) -> PadFlags { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); from_glib((*ptr).flags) } } } impl> PadExtManual for O {} unsafe fn create_probe_info<'a>( info: *mut ffi::GstPadProbeInfo, ) -> (PadProbeInfo<'a>, Option) { let mut data_type = None; let flow_res = try_from_glib((*info).ABI.abi.flow_ret); let info = PadProbeInfo { mask: from_glib((*info).type_), id: Some(PadProbeId(NonZeroU64::new_unchecked((*info).id as _))), offset: (*info).offset, size: (*info).size, data: if (*info).data.is_null() { None } else { let data = (*info).data as *mut ffi::GstMiniObject; (*info).data = ptr::null_mut(); if (*data).type_ == Buffer::static_type().into_glib() { data_type = Some(Buffer::static_type()); Some(PadProbeData::Buffer(from_glib_full( data as *const ffi::GstBuffer, ))) } else if (*data).type_ == BufferList::static_type().into_glib() { data_type = Some(BufferList::static_type()); Some(PadProbeData::BufferList(from_glib_full( data as *const ffi::GstBufferList, ))) } else if (*data).type_ == Query::static_type().into_glib() { data_type = Some(Query::static_type()); Some(PadProbeData::Query(QueryRef::from_mut_ptr( data as *mut ffi::GstQuery, ))) } else if (*data).type_ == Event::static_type().into_glib() { data_type = Some(Event::static_type()); Some(PadProbeData::Event(from_glib_full( data as *const ffi::GstEvent, ))) } else { Some(PadProbeData::__Unknown(data)) } }, flow_res, }; (info, data_type) } unsafe fn update_probe_info( ret: PadProbeReturn, probe_info: PadProbeInfo, data_type: Option, info: *mut ffi::GstPadProbeInfo, ) { if ret == PadProbeReturn::Handled { // Handled queries need to be returned // Handled buffers and buffer lists are consumed // No other types can safely be used here match probe_info.data { Some(PadProbeData::Query(query)) => { assert_eq!(data_type, Some(Query::static_type())); (*info).data = query.as_mut_ptr() as *mut libc::c_void; } Some(PadProbeData::Buffer(_)) => { assert_eq!(data_type, Some(Buffer::static_type())); // Buffer not consumed by probe; consume it here } Some(PadProbeData::BufferList(_)) => { assert_eq!(data_type, Some(BufferList::static_type())); // BufferList not consumed by probe; consume it here } Some(PadProbeData::Event(_)) => { assert_eq!(data_type, Some(Event::static_type())); // Event not consumed by probe; consume it here } None if data_type == Some(Buffer::static_type()) || data_type == Some(BufferList::static_type()) || data_type == Some(Event::static_type()) => { // Buffer or Event consumed by probe (*info).data = ptr::null_mut(); } other => panic!("Bad data for {data_type:?} pad probe returning Handled: {other:?}"), } } else if ret == PadProbeReturn::Drop { // We may have consumed the object via PadProbeInfo::take_*() functions match probe_info.data { None if data_type == Some(Buffer::static_type()) || data_type == Some(BufferList::static_type()) || data_type == Some(Event::static_type()) => { (*info).data = ptr::null_mut(); } _ => { // Nothing to do, it's going to be dropped } } } else { match probe_info.data { Some(PadProbeData::Buffer(buffer)) => { assert_eq!(data_type, Some(Buffer::static_type())); (*info).data = buffer.into_glib_ptr() as *mut libc::c_void; } Some(PadProbeData::BufferList(bufferlist)) => { assert_eq!(data_type, Some(BufferList::static_type())); (*info).data = bufferlist.into_glib_ptr() as *mut libc::c_void; } Some(PadProbeData::Event(event)) => { assert_eq!(data_type, Some(Event::static_type())); (*info).data = event.into_glib_ptr() as *mut libc::c_void; } Some(PadProbeData::Query(query)) => { assert_eq!(data_type, Some(Query::static_type())); (*info).data = query.as_mut_ptr() as *mut libc::c_void; } Some(PadProbeData::__Unknown(ptr)) => { assert_eq!(data_type, None); (*info).data = ptr as *mut libc::c_void; } None => { assert_eq!(data_type, None); } } } let flow_ret: FlowReturn = probe_info.flow_res.into(); (*info).ABI.abi.flow_ret = flow_ret.into_glib(); } unsafe extern "C" fn trampoline_pad_probe< T, F: Fn(&T, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static, >( pad: *mut ffi::GstPad, info: *mut ffi::GstPadProbeInfo, func: gpointer, ) -> ffi::GstPadProbeReturn where T: IsA, { let func: &F = &*(func as *const F); let (mut probe_info, data_type) = create_probe_info(info); let ret = func( Pad::from_glib_borrow(pad).unsafe_cast_ref(), &mut probe_info, ); update_probe_info(ret, probe_info, data_type, info); ret.into_glib() } unsafe extern "C" fn trampoline_activate_function< T, F: Fn(&T, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static, >( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, ) -> glib::ffi::gboolean where T: IsA, { let func: &F = &*((*pad).activatedata as *const F); match func( Pad::from_glib_borrow(pad).unsafe_cast_ref(), Option::::from_glib_borrow(parent) .as_ref() .as_ref(), ) { Ok(()) => true, Err(err) => { err.log_with_object(&*Pad::from_glib_borrow(pad)); false } } .into_glib() } unsafe extern "C" fn trampoline_activatemode_function< T, F: Fn(&T, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError> + Send + Sync + 'static, >( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, mode: ffi::GstPadMode, active: glib::ffi::gboolean, ) -> glib::ffi::gboolean where T: IsA, { let func: &F = &*((*pad).activatemodedata as *const F); match func( Pad::from_glib_borrow(pad).unsafe_cast_ref(), Option::::from_glib_borrow(parent) .as_ref() .as_ref(), from_glib(mode), from_glib(active), ) { Ok(()) => true, Err(err) => { err.log_with_object(&*Pad::from_glib_borrow(pad)); false } } .into_glib() } unsafe extern "C" fn trampoline_chain_function< T, F: Fn(&T, Option<&crate::Object>, crate::Buffer) -> Result + Send + Sync + 'static, >( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, buffer: *mut ffi::GstBuffer, ) -> ffi::GstFlowReturn where T: IsA, { let func: &F = &*((*pad).chaindata as *const F); let res: FlowReturn = func( Pad::from_glib_borrow(pad).unsafe_cast_ref(), Option::::from_glib_borrow(parent) .as_ref() .as_ref(), from_glib_full(buffer), ) .into(); res.into_glib() } unsafe extern "C" fn trampoline_chain_list_function< T, F: Fn(&T, Option<&crate::Object>, crate::BufferList) -> Result + Send + Sync + 'static, >( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, list: *mut ffi::GstBufferList, ) -> ffi::GstFlowReturn where T: IsA, { let func: &F = &*((*pad).chainlistdata as *const F); let res: FlowReturn = func( Pad::from_glib_borrow(pad).unsafe_cast_ref(), Option::::from_glib_borrow(parent) .as_ref() .as_ref(), from_glib_full(list), ) .into(); res.into_glib() } unsafe extern "C" fn trampoline_event_function< T, F: Fn(&T, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static, >( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, event: *mut ffi::GstEvent, ) -> glib::ffi::gboolean where T: IsA, { let func: &F = &*((*pad).eventdata as *const F); func( Pad::from_glib_borrow(pad).unsafe_cast_ref(), Option::::from_glib_borrow(parent) .as_ref() .as_ref(), from_glib_full(event), ) .into_glib() } unsafe extern "C" fn trampoline_event_full_function< T, F: Fn(&T, Option<&crate::Object>, crate::Event) -> Result + Send + Sync + 'static, >( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, event: *mut ffi::GstEvent, ) -> ffi::GstFlowReturn where T: IsA, { let func: &F = &*((*pad).eventdata as *const F); let res: FlowReturn = func( Pad::from_glib_borrow(pad).unsafe_cast_ref(), Option::::from_glib_borrow(parent) .as_ref() .as_ref(), from_glib_full(event), ) .into(); res.into_glib() } #[allow(clippy::needless_option_as_deref)] unsafe extern "C" fn trampoline_getrange_function< T, F: Fn( &T, Option<&crate::Object>, u64, Option<&mut crate::BufferRef>, u32, ) -> Result + Send + Sync + 'static, >( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, offset: u64, length: u32, buffer: *mut *mut ffi::GstBuffer, ) -> ffi::GstFlowReturn where T: IsA, { let func: &F = &*((*pad).getrangedata as *const F); debug_assert!(!buffer.is_null()); let pad = Pad::from_glib_borrow(pad); let pad = pad.unsafe_cast_ref(); let mut passed_buffer = if (*buffer).is_null() { None } else { Some(crate::BufferRef::from_mut_ptr(*buffer)) }; match func( pad, Option::::from_glib_borrow(parent) .as_ref() .as_ref(), offset, passed_buffer.as_deref_mut(), length, ) { Ok(PadGetRangeSuccess::NewBuffer(new_buffer)) => { if let Some(passed_buffer) = passed_buffer { crate::debug!( crate::CAT_PERFORMANCE, obj = pad.unsafe_cast_ref::(), "Returned new buffer from getrange function, copying into passed buffer" ); let mut map = match passed_buffer.map_writable() { Ok(map) => map, Err(_) => { crate::error!( crate::CAT_RUST, obj = pad.unsafe_cast_ref::(), "Failed to map passed buffer writable" ); return ffi::GST_FLOW_ERROR; } }; let copied_size = new_buffer.copy_to_slice(0, &mut map); drop(map); if let Err(copied_size) = copied_size { passed_buffer.set_size(copied_size); } match new_buffer.copy_into(passed_buffer, crate::BUFFER_COPY_METADATA, ..) { Ok(_) => FlowReturn::Ok.into_glib(), Err(_) => { crate::error!( crate::CAT_RUST, obj = pad.unsafe_cast_ref::(), "Failed to copy buffer metadata" ); FlowReturn::Error.into_glib() } } } else { *buffer = new_buffer.into_glib_ptr(); FlowReturn::Ok.into_glib() } } Ok(PadGetRangeSuccess::FilledBuffer) => { assert!(passed_buffer.is_some()); FlowReturn::Ok.into_glib() } Err(ret) => FlowReturn::from_error(ret).into_glib(), } } unsafe extern "C" fn trampoline_iterate_internal_links_function< T, F: Fn(&T, Option<&crate::Object>) -> crate::Iterator + Send + Sync + 'static, >( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, ) -> *mut ffi::GstIterator where T: IsA, { let func: &F = &*((*pad).iterintlinkdata as *const F); // Steal the iterator and return it let ret = func( Pad::from_glib_borrow(pad).unsafe_cast_ref(), Option::::from_glib_borrow(parent) .as_ref() .as_ref(), ); ret.into_glib_ptr() } unsafe extern "C" fn trampoline_link_function< T, F: Fn( &T, Option<&crate::Object>, &crate::Pad, ) -> Result + Send + Sync + 'static, >( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, peer: *mut ffi::GstPad, ) -> ffi::GstPadLinkReturn where T: IsA, { let func: &F = &*((*pad).linkdata as *const F); let res: crate::PadLinkReturn = func( Pad::from_glib_borrow(pad).unsafe_cast_ref(), Option::::from_glib_borrow(parent) .as_ref() .as_ref(), &from_glib_borrow(peer), ) .into(); res.into_glib() } unsafe extern "C" fn trampoline_query_function< T, F: Fn(&T, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static, >( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, query: *mut ffi::GstQuery, ) -> glib::ffi::gboolean where T: IsA, { let func: &F = &*((*pad).querydata as *const F); func( Pad::from_glib_borrow(pad).unsafe_cast_ref(), Option::::from_glib_borrow(parent) .as_ref() .as_ref(), crate::QueryRef::from_mut_ptr(query), ) .into_glib() } unsafe extern "C" fn trampoline_unlink_function< T, F: Fn(&T, Option<&crate::Object>) + Send + Sync + 'static, >( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, ) where T: IsA, { let func: &F = &*((*pad).unlinkdata as *const F); func( Pad::from_glib_borrow(pad).unsafe_cast_ref(), Option::::from_glib_borrow(parent) .as_ref() .as_ref(), ) } unsafe extern "C" fn destroy_closure(ptr: gpointer) { let _ = Box::::from_raw(ptr as *mut _); } impl Pad { // rustdoc-stripper-ignore-next /// Creates a new [`Pad`] with the specified [`PadDirection`](crate::PadDirection). /// /// The [`Pad`] will be assigned the usual `gst::Object` generated unique name. /// /// Use [`Pad::builder()`] to get a [`PadBuilder`] and define options. #[doc(alias = "gst_pad_new")] pub fn new(direction: crate::PadDirection) -> Self { skip_assert_initialized!(); Self::builder(direction).build() } // rustdoc-stripper-ignore-next /// Creates a [`PadBuilder`] with the specified [`PadDirection`](crate::PadDirection). #[doc(alias = "gst_pad_new")] pub fn builder(direction: crate::PadDirection) -> PadBuilder { skip_assert_initialized!(); PadBuilder::new(direction) } // rustdoc-stripper-ignore-next /// Creates a new [`Pad`] from the [`StaticPadTemplate`](crate::StaticPadTemplate). /// /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `Pad` will automatically be named after the `name_template`. /// /// Use [`Pad::builder_from_static_template()`] to get a [`PadBuilder`] and define options. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. /// /// # Panics /// /// Panics if the `name_template` is a wildcard-name. #[doc(alias = "gst_pad_new_from_static_template")] pub fn from_static_template(templ: &StaticPadTemplate) -> Self { skip_assert_initialized!(); Self::builder_from_static_template(templ).build() } // rustdoc-stripper-ignore-next /// Creates a new [`PadBuilder`] from the [`StaticPadTemplate`](crate::StaticPadTemplate). /// /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `Pad` will automatically be named after the `name_template`. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. #[doc(alias = "gst_pad_new_from_static_template")] pub fn builder_from_static_template(templ: &StaticPadTemplate) -> PadBuilder { skip_assert_initialized!(); PadBuilder::from_static_template(templ) } // rustdoc-stripper-ignore-next /// Creates a new [`Pad`] from the [`PadTemplate`](crate::PadTemplate). /// /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `Pad` will automatically be named after the `name_template`. /// /// Use [`Pad::builder_from_template()`] to get a [`PadBuilder`] and define options. /// /// # Panics /// /// Panics if the `name_template` is a wildcard-name. #[doc(alias = "gst_pad_new_from_template")] pub fn from_template(templ: &crate::PadTemplate) -> Self { skip_assert_initialized!(); Self::builder_from_template(templ).build() } // rustdoc-stripper-ignore-next /// Creates a new [`PadBuilder`] from the [`PadTemplate`](crate::PadTemplate). /// /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `Pad` will automatically be named after the `name_template`. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. #[doc(alias = "gst_pad_new_from_template")] pub fn builder_from_template(templ: &crate::PadTemplate) -> PadBuilder { skip_assert_initialized!(); PadBuilder::from_template(templ) } #[doc(alias = "gst_pad_query_default")] pub fn query_default>( pad: &O, parent: Option<&impl IsA>, query: &mut QueryRef, ) -> bool { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_pad_query_default( pad.as_ref().to_glib_none().0, parent.map(|p| p.as_ref()).to_glib_none().0, query.as_mut_ptr(), )) } } #[doc(alias = "gst_pad_event_default")] pub fn event_default>( pad: &O, parent: Option<&impl IsA>, event: impl Into, ) -> bool { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_pad_event_default( pad.as_ref().to_glib_none().0, parent.map(|p| p.as_ref()).to_glib_none().0, event.into().into_glib_ptr(), )) } } #[doc(alias = "gst_pad_iterate_internal_links_default")] pub fn iterate_internal_links_default>( pad: &O, parent: Option<&impl IsA>, ) -> crate::Iterator { skip_assert_initialized!(); unsafe { from_glib_full(ffi::gst_pad_iterate_internal_links_default( pad.as_ref().to_glib_none().0, parent.map(|p| p.as_ref()).to_glib_none().0, )) } } } pub(crate) enum PadBuilderName { Undefined, KeepGenerated, UserDefined(String), CandidateForWildcardTemplate(String), } #[must_use = "The builder must be built to be used"] pub struct PadBuilder { pub(crate) pad: T, pub(crate) name: PadBuilderName, } impl + IsA + glib::object::IsClass> PadBuilder { // rustdoc-stripper-ignore-next /// Creates a `PadBuilder` with the specified [`PadDirection`](crate::PadDirection). pub fn new(direction: crate::PadDirection) -> Self { assert_initialized_main_thread!(); let pad = glib::Object::builder::() .property("direction", direction) .build(); // Ghost pads are a bit special if let Some(pad) = pad.dynamic_cast_ref::() { unsafe { let res = ffi::gst_ghost_pad_construct(pad.to_glib_none().0); // This can't really fail... debug_assert_ne!(res, glib::ffi::GFALSE, "Failed to construct ghost pad"); } } PadBuilder { pad, name: PadBuilderName::Undefined, } } // rustdoc-stripper-ignore-next /// Creates a `PadBuilder` from the specified [`StaticPadTemplate`](crate::StaticPadTemplate). /// /// If the [`StaticPadTemplate`](crate::StaticPadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `Pad` will automatically be named after the `name_template`. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. pub fn from_static_template(templ: &StaticPadTemplate) -> Self { skip_assert_initialized!(); let templ = templ.get(); Self::from_template(&templ) } // rustdoc-stripper-ignore-next /// Creates a `PadBuilder` from the specified [`PadTemplate`](crate::PadTemplate). /// /// If the [`PadTemplate`](crate::PadTemplate) has a specific `name_template`, /// i.e. if it's not a wildcard-name containing `%u`, `%s` or `%d`, /// the `Pad` will automatically be named after the `name_template`. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. pub fn from_template(templ: &crate::PadTemplate) -> Self { assert_initialized_main_thread!(); let mut type_ = T::static_type(); let gtype = templ.gtype(); if gtype == glib::Type::UNIT { // Nothing to be done, we can create any kind of pad } else if gtype.is_a(type_) { // We were asked to create a parent type of the template type, e.g. a gst::Pad for // a template that wants a gst_base::AggregatorPad. Not a problem: update the type type_ = gtype; } else { // Otherwise the requested type must be a subclass of the template pad type assert!(type_.is_a(gtype)); } let mut properties = [ ("direction", templ.direction().into()), ("template", templ.into()), ]; let pad = unsafe { glib::Object::with_mut_values(type_, &mut properties).unsafe_cast::() }; // Ghost pads are a bit special if let Some(pad) = pad.dynamic_cast_ref::() { unsafe { let res = ffi::gst_ghost_pad_construct(pad.to_glib_none().0); // This can't really fail... debug_assert_ne!(res, glib::ffi::GFALSE, "Failed to construct ghost pad"); } } PadBuilder { pad, name: PadBuilderName::Undefined, } } // rustdoc-stripper-ignore-next /// Uses the `gst::Object` generated unique name. pub fn generated_name(mut self) -> Self { self.name = PadBuilderName::KeepGenerated; self } // rustdoc-stripper-ignore-next /// Sets the name of the Pad. pub fn name(mut self, name: impl Into) -> Self { self.name = PadBuilderName::UserDefined(name.into()); self } // rustdoc-stripper-ignore-next /// Optionally sets the name of the Pad. /// /// This method is convenient when the `name` is provided as an `Option`. /// If the `name` is `None`, this has no effect. #[deprecated = "use `name_if_some()` instead"] pub fn maybe_name>(self, name: Option) -> Self { if let Some(name) = name { self.name(name) } else { self } } // rustdoc-stripper-ignore-next /// Optionally sets the name of the Pad. /// /// This method is convenient when the `name` is provided as an `Option`. /// If the `name` is `None`, this has no effect. pub fn name_if_some>(self, name: Option) -> Self { if let Some(name) = name { self.name(name) } else { self } } #[doc(alias = "gst_pad_set_activate_function")] pub fn activate_function(self, func: F) -> Self where F: Fn(&T, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static, { unsafe { self.pad.set_activate_function(func); } self } #[doc(alias = "gst_pad_set_activate_function")] pub fn activate_function_if_some(self, func: Option) -> Self where F: Fn(&T, Option<&crate::Object>) -> Result<(), LoggableError> + Send + Sync + 'static, { if let Some(func) = func { self.activate_function(func) } else { self } } #[doc(alias = "gst_pad_set_activatemode_function")] pub fn activatemode_function(self, func: F) -> Self where F: Fn(&T, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError> + Send + Sync + 'static, { unsafe { self.pad.set_activatemode_function(func); } self } #[doc(alias = "gst_pad_set_activatemode_function")] pub fn activatemode_function_if_some(self, func: Option) -> Self where F: Fn(&T, Option<&crate::Object>, crate::PadMode, bool) -> Result<(), LoggableError> + Send + Sync + 'static, { if let Some(func) = func { self.activatemode_function(func) } else { self } } #[doc(alias = "gst_pad_set_chain_function")] pub fn chain_function(self, func: F) -> Self where F: Fn(&T, Option<&crate::Object>, crate::Buffer) -> Result + Send + Sync + 'static, { unsafe { self.pad.set_chain_function(func); } self } #[doc(alias = "gst_pad_set_chain_function")] pub fn chain_function_if_some(self, func: Option) -> Self where F: Fn(&T, Option<&crate::Object>, crate::Buffer) -> Result + Send + Sync + 'static, { if let Some(func) = func { self.chain_function(func) } else { self } } #[doc(alias = "gst_pad_set_chain_list_function")] pub fn chain_list_function(self, func: F) -> Self where F: Fn(&T, Option<&crate::Object>, crate::BufferList) -> Result + Send + Sync + 'static, { unsafe { self.pad.set_chain_list_function(func); } self } #[doc(alias = "gst_pad_set_chain_list_function")] pub fn chain_list_function_if_some(self, func: Option) -> Self where F: Fn(&T, Option<&crate::Object>, crate::BufferList) -> Result + Send + Sync + 'static, { if let Some(func) = func { self.chain_list_function(func) } else { self } } #[doc(alias = "gst_pad_set_event_function")] pub fn event_function(self, func: F) -> Self where F: Fn(&T, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static, { unsafe { self.pad.set_event_function(func); } self } #[doc(alias = "gst_pad_set_event_function")] pub fn event_function_if_some(self, func: Option) -> Self where F: Fn(&T, Option<&crate::Object>, crate::Event) -> bool + Send + Sync + 'static, { if let Some(func) = func { self.event_function(func) } else { self } } #[doc(alias = "gst_pad_set_event_full_function")] pub fn event_full_function(self, func: F) -> Self where F: Fn(&T, Option<&crate::Object>, crate::Event) -> Result + Send + Sync + 'static, { unsafe { self.pad.set_event_full_function(func); } self } #[doc(alias = "gst_pad_set_event_full_function")] pub fn event_full_function_if_some(self, func: Option) -> Self where F: Fn(&T, Option<&crate::Object>, crate::Event) -> Result + Send + Sync + 'static, { if let Some(func) = func { self.event_full_function(func) } else { self } } #[doc(alias = "gst_pad_set_getrange_function")] pub fn getrange_function(self, func: F) -> Self where F: Fn( &T, Option<&crate::Object>, u64, Option<&mut crate::BufferRef>, u32, ) -> Result + Send + Sync + 'static, { unsafe { self.pad.set_getrange_function(func); } self } #[doc(alias = "gst_pad_set_getrange_function")] pub fn getrange_function_if_some(self, func: Option) -> Self where F: Fn( &T, Option<&crate::Object>, u64, Option<&mut crate::BufferRef>, u32, ) -> Result + Send + Sync + 'static, { if let Some(func) = func { self.getrange_function(func) } else { self } } #[doc(alias = "gst_pad_set_iterate_internal_links_function")] pub fn iterate_internal_links_function(self, func: F) -> Self where F: Fn(&T, Option<&crate::Object>) -> crate::Iterator + Send + Sync + 'static, { unsafe { self.pad.set_iterate_internal_links_function(func); } self } #[doc(alias = "gst_pad_set_iterate_internal_links_function")] pub fn iterate_internal_links_function_if_some(self, func: Option) -> Self where F: Fn(&T, Option<&crate::Object>) -> crate::Iterator + Send + Sync + 'static, { if let Some(func) = func { self.iterate_internal_links_function(func) } else { self } } #[doc(alias = "gst_pad_set_link_function")] pub fn link_function(self, func: F) -> Self where F: Fn( &T, Option<&crate::Object>, &Pad, ) -> Result + Send + Sync + 'static, { unsafe { self.pad.set_link_function(func); } self } #[doc(alias = "gst_pad_set_link_function")] pub fn link_function_if_some(self, func: Option) -> Self where F: Fn( &T, Option<&crate::Object>, &Pad, ) -> Result + Send + Sync + 'static, { if let Some(func) = func { self.link_function(func) } else { self } } #[doc(alias = "gst_pad_set_query_function")] pub fn query_function(self, func: F) -> Self where F: Fn(&T, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static, { unsafe { self.pad.set_query_function(func); } self } #[doc(alias = "gst_pad_set_query_function")] pub fn query_function_if_some(self, func: Option) -> Self where F: Fn(&T, Option<&crate::Object>, &mut crate::QueryRef) -> bool + Send + Sync + 'static, { if let Some(func) = func { self.query_function(func) } else { self } } #[doc(alias = "gst_pad_set_unlink_function")] pub fn unlink_function(self, func: F) -> Self where F: Fn(&T, Option<&crate::Object>) + Send + Sync + 'static, { unsafe { self.pad.set_unlink_function(func); } self } #[doc(alias = "gst_pad_set_unlink_function")] pub fn unlink_function_if_some(self, func: Option) -> Self where F: Fn(&T, Option<&crate::Object>) + Send + Sync + 'static, { if let Some(func) = func { self.unlink_function(func) } else { self } } pub fn flags(self, flags: PadFlags) -> Self { self.pad.set_pad_flags(flags); self } pub fn flags_if_some(self, flags: Option) -> Self { if let Some(flags) = flags { self.flags(flags) } else { self } } // rustdoc-stripper-ignore-next /// Builds the [`Pad`]. /// /// # Panics /// /// Panics if the [`Pad`] was built from a [`PadTemplate`](crate::PadTemplate) /// with a wildcard-name `name_template` (i.e. containing `%u`, `%s` or `%d`) /// and no specific `name` was provided using [`PadBuilder::name`] /// or [`PadBuilder::name_if_some`], or for [`GhostPad`s](crate::GhostPad), /// by defining a `target`. /// /// Use [`generated_name()`](crate::PadBuilder::generated_name`) to keep the `gst::Object` /// automatically generated unique name. #[must_use = "Building the pad without using it has no effect"] #[track_caller] pub fn build(self) -> T { let Self { pad, name } = self; let templ = pad.pad_template(); use PadBuilderName::*; match (name, templ) { (KeepGenerated, _) => (), (Undefined, None) => (), (Undefined, Some(templ)) => { if templ.name().find('%').is_some() { panic!(concat!( "Attempt to build a Pad from a wildcard-name template", " or with a target Pad with an incompatible name.", " Make sure to define a specific name using PadBuilder", " or opt-in to keep the automatically generated name.", )); } else { pad.set_property("name", templ.name()); } } (UserDefined(name), _) | (CandidateForWildcardTemplate(name), None) => { pad.set_property("name", name); } (CandidateForWildcardTemplate(name), Some(templ)) => { if templ.name().find('%').is_none() { // Not a widlcard template pad.set_property("name", templ.name()); } else { let mut can_assign_name = true; if templ.presence() == crate::PadPresence::Request { // Check if the name is compatible with the name template. use crate::CAT_RUST; let mut name_parts = name.split('_'); for templ_part in templ.name_template().split('_') { let Some(name_part) = name_parts.next() else { crate::debug!( CAT_RUST, "Not using Pad name '{name}': not enough parts compared to template '{}'", templ.name_template(), ); can_assign_name = false; break; }; if let Some(conv_spec_start) = templ_part.find('%') { if conv_spec_start > 0 && !name_part.starts_with(&templ_part[..conv_spec_start]) { crate::debug!( CAT_RUST, "Not using Pad name '{name}': mismatch template '{}' prefix", templ.name_template(), ); can_assign_name = false; break; } let conv_spec_pos = conv_spec_start + 1; match templ_part.get(conv_spec_pos..=conv_spec_pos) { Some("s") => { // *There can be only one* %s break; } Some("u") => { if name_part .get(conv_spec_start..) .map_or(true, |s| s.parse::().is_err()) { crate::debug!( CAT_RUST, "Not using Pad name '{name}': can't parse '%u' from '{name_part}' (template '{}')", templ.name_template(), ); can_assign_name = false; break; } } Some("d") => { if name_part .get(conv_spec_start..) .map_or(true, |s| s.parse::().is_err()) { crate::debug!( CAT_RUST, "Not using target Pad name '{name}': can't parse '%i' from '{name_part}' (template '{}')", templ.name_template(), ); can_assign_name = false; break; } } other => { unreachable!("Unexpected conversion specifier {other:?}") } } } else if name_part != templ_part { can_assign_name = false; } } } if can_assign_name { pad.set_property("name", name); } else { panic!(concat!( "Attempt to build a Pad from a wildcard-name template", " with a target Pad with an incompatible name.", " Make sure to define a specific name using PadBuilder", " or opt-in to keep the automatically generated name.", )); } } } } pad } } #[cfg(test)] mod tests { use std::sync::{atomic::AtomicUsize, mpsc::channel, Arc, Mutex}; use super::*; #[test] fn test_event_chain_functions() { crate::init().unwrap(); let events = Arc::new(Mutex::new(Vec::new())); let events_clone = events.clone(); let buffers = Arc::new(Mutex::new(Vec::new())); let buffers_clone = buffers.clone(); let pad = crate::Pad::builder(crate::PadDirection::Sink) .name("sink") .event_function(move |_, _, event| { let mut events = events_clone.lock().unwrap(); events.push(event); true }) .chain_function(move |_, _, buffer| { let mut buffers = buffers_clone.lock().unwrap(); buffers.push(buffer); Ok(FlowSuccess::Ok) }) .build(); pad.set_active(true).unwrap(); assert!(pad.send_event(crate::event::StreamStart::new("test"))); let segment = crate::FormattedSegment::::new(); assert!(pad.send_event(crate::event::Segment::new(segment.as_ref()))); assert_eq!(pad.chain(crate::Buffer::new()), Ok(FlowSuccess::Ok)); let events = events.lock().unwrap(); let buffers = buffers.lock().unwrap(); assert_eq!(events.len(), 2); assert_eq!(buffers.len(), 1); match events[0].view() { crate::EventView::StreamStart(..) => (), _ => unreachable!(), } match events[1].view() { crate::EventView::Segment(..) => (), _ => unreachable!(), } } #[test] fn test_getrange_function() { crate::init().unwrap(); let pad = crate::Pad::builder(crate::PadDirection::Src) .name("src") .activate_function(|pad, _parent| { pad.activate_mode(crate::PadMode::Pull, true) .map_err(|err| err.into()) }) .getrange_function(|_pad, _parent, offset, _buffer, size| { assert_eq!(offset, 0); assert_eq!(size, 5); let buffer = crate::Buffer::from_slice(b"abcde"); Ok(PadGetRangeSuccess::NewBuffer(buffer)) }) .build(); pad.set_active(true).unwrap(); let buffer = pad.range(0, 5).unwrap(); let map = buffer.map_readable().unwrap(); assert_eq!(&*map, b"abcde"); let mut buffer = crate::Buffer::with_size(5).unwrap(); pad.range_fill(0, buffer.get_mut().unwrap(), 5).unwrap(); let map = buffer.map_readable().unwrap(); assert_eq!(&*map, b"abcde"); pad.set_active(false).unwrap(); drop(pad); let pad = crate::Pad::builder(crate::PadDirection::Src) .name("src") .activate_function(|pad, _parent| { pad.activate_mode(crate::PadMode::Pull, true) .map_err(|err| err.into()) }) .getrange_function(|_pad, _parent, offset, buffer, size| { assert_eq!(offset, 0); assert_eq!(size, 5); if let Some(buffer) = buffer { buffer.copy_from_slice(0, b"fghij").unwrap(); Ok(PadGetRangeSuccess::FilledBuffer) } else { let buffer = crate::Buffer::from_slice(b"abcde"); Ok(PadGetRangeSuccess::NewBuffer(buffer)) } }) .build(); pad.set_active(true).unwrap(); let buffer = pad.range(0, 5).unwrap(); let map = buffer.map_readable().unwrap(); assert_eq!(&*map, b"abcde"); let mut buffer = crate::Buffer::with_size(5).unwrap(); pad.range_fill(0, buffer.get_mut().unwrap(), 5).unwrap(); let map = buffer.map_readable().unwrap(); assert_eq!(&*map, b"fghij"); } #[test] fn test_task() { crate::init().unwrap(); let pad = crate::Pad::builder(crate::PadDirection::Sink) .name("sink") .build(); let (sender, receiver) = channel(); let mut i = 0; let pad_clone = pad.clone(); pad.start_task(move || { i += 1; if i == 3 { sender.send(i).unwrap(); pad_clone.pause_task().unwrap(); } }) .unwrap(); assert_eq!(receiver.recv().unwrap(), 3); } #[test] fn test_remove_probe_from_probe() { crate::init().unwrap(); let src_pad = crate::Pad::builder(crate::PadDirection::Src) .name("src") .build(); let sink_pad = crate::Pad::builder(crate::PadDirection::Sink) .name("sink") .chain_function(|_pad, _parent, _buffer| Ok(crate::FlowSuccess::Ok)) .build(); src_pad.link(&sink_pad).unwrap(); let counter = Arc::new(AtomicUsize::new(0)); let counter_clone = counter.clone(); src_pad.add_probe(crate::PadProbeType::BUFFER, move |pad, info| { if let Some(PadProbeData::Buffer(_)) = info.data { counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst); pad.remove_probe(info.id.take().expect("no pad probe id")); } else { unreachable!(); } crate::PadProbeReturn::Handled }); sink_pad.set_active(true).unwrap(); src_pad.set_active(true).unwrap(); assert!(src_pad.push_event(crate::event::StreamStart::new("test"))); let segment = crate::FormattedSegment::::new(); assert!(src_pad.push_event(crate::event::Segment::new(segment.as_ref()))); assert_eq!(src_pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok)); assert_eq!(src_pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok)); assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1); } fn do_probe_with_return(probe_return: crate::PadProbeReturn) { skip_assert_initialized!(); crate::init().unwrap(); let (major, minor, micro, _) = crate::version(); let pad = crate::Pad::builder(crate::PadDirection::Src) .name("src") .build(); let events = Arc::new(Mutex::new(Vec::new())); let buffers = Arc::new(Mutex::new(Vec::new())); let flow_override = if (major, minor, micro) >= (1, 16, 1) { Err(FlowError::Eos) } else { // Broken on 1.16.0 // https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/151 Ok(FlowSuccess::Ok) }; { let events = events.clone(); pad.add_probe(crate::PadProbeType::EVENT_DOWNSTREAM, move |_, info| { if let Some(PadProbeData::Event(event)) = &info.data { let mut events = events.lock().unwrap(); events.push(event.clone()); } else { unreachable!(); } crate::PadProbeReturn::Ok }); } { let events = events.clone(); pad.add_probe(crate::PadProbeType::EVENT_UPSTREAM, move |_, info| { if let Some(event) = info.take_event() { let mut events = events.lock().unwrap(); events.push(event); } else { unreachable!(); } probe_return }); } { let buffers = buffers.clone(); pad.add_probe(crate::PadProbeType::BUFFER, move |_, info| { if let Some(buffer) = info.take_buffer() { let mut buffers = buffers.lock().unwrap(); info.flow_res = if buffers.is_empty() { Ok(FlowSuccess::Ok) } else { flow_override }; buffers.push(buffer); } else { unreachable!(); } probe_return }); } pad.set_active(true).unwrap(); assert!( pad.send_event(crate::event::Latency::new(crate::ClockTime::from_nseconds( 10 ))) ); assert!(pad.push_event(crate::event::StreamStart::new("test"))); let segment = crate::FormattedSegment::::new(); assert!(pad.push_event(crate::event::Segment::new(segment.as_ref()))); assert_eq!(pad.push(crate::Buffer::new()), Ok(FlowSuccess::Ok)); assert_eq!( pad.push(crate::Buffer::new()), // On Drop, we will get an Ok, not whatever value we returned if probe_return == crate::PadProbeReturn::Drop { Ok(FlowSuccess::Ok) } else { flow_override } ); let events = events.lock().unwrap(); let buffers = buffers.lock().unwrap(); assert_eq!(events.len(), 3); assert_eq!(buffers.len(), 2); assert_eq!(events[0].type_(), crate::EventType::Latency); assert_eq!(events[1].type_(), crate::EventType::StreamStart); assert_eq!(events[2].type_(), crate::EventType::Segment); assert!( buffers.iter().all(|b| b.is_writable()), "A buffer ref leaked!" ); drop(pad); // Need to drop the pad first to unref sticky events assert!( events.iter().all(|e| e.is_writable()), "An event ref leaked!" ); } #[test] fn test_probe() { crate::init().unwrap(); do_probe_with_return(crate::PadProbeReturn::Handled); } #[test] fn test_probe_drop() { crate::init().unwrap(); do_probe_with_return(crate::PadProbeReturn::Drop); } #[test] fn test_sticky_events() { crate::init().unwrap(); let pad = crate::Pad::builder(crate::PadDirection::Sink) .name("sink") .build(); pad.set_active(true).unwrap(); // Send some sticky events assert!(pad.send_event(crate::event::StreamStart::new("test"))); let caps = crate::Caps::builder("some/x-caps").build(); assert!(pad.send_event(crate::event::Caps::new(&caps))); let segment = crate::FormattedSegment::::new(); assert!(pad.send_event(crate::event::Segment::new(segment.as_ref()))); let stream_start = pad.sticky_event::(0).unwrap(); assert_eq!(stream_start.stream_id(), "test"); let caps2 = pad.sticky_event::(0).unwrap(); assert_eq!(&*caps, caps2.caps()); let segment = pad.sticky_event::(0).unwrap(); assert_eq!(segment.segment().format(), crate::Format::Time); } #[test] fn test_sticky_events_foreach() { crate::init().unwrap(); let pad = crate::Pad::builder(crate::PadDirection::Sink) .name("sink") .build(); pad.set_active(true).unwrap(); // Send some sticky events assert!(pad.send_event(crate::event::StreamStart::new("test"))); let caps = crate::Caps::builder("some/x-caps").build(); assert!(pad.send_event(crate::event::Caps::new(&caps))); let segment = crate::FormattedSegment::::new(); assert!(pad.send_event(crate::event::Segment::new(segment.as_ref()))); let mut sticky_events = Vec::new(); pad.sticky_events_foreach(|event| { sticky_events.push(event.clone()); ControlFlow::Continue(EventForeachAction::Keep) }); assert_eq!(sticky_events.len(), 3); // Test early exit from foreach loop let mut sticky_events2 = Vec::new(); pad.sticky_events_foreach(|event| { sticky_events2.push(event.clone()); if event.type_() == crate::EventType::Caps { ControlFlow::Break(EventForeachAction::Keep) } else { ControlFlow::Continue(EventForeachAction::Keep) } }); assert_eq!(sticky_events2.len(), 2); let mut sticky_events3 = Vec::new(); pad.sticky_events_foreach(|event| { sticky_events3.push(event.clone()); ControlFlow::Continue(EventForeachAction::Keep) }); assert_eq!(sticky_events3.len(), 3); for (e1, e2) in sticky_events.iter().zip(sticky_events3.iter()) { assert_eq!(e1.as_ref() as *const _, e2.as_ref() as *const _); } // Replace segment event pad.sticky_events_foreach(|event| { let action = if event.type_() == crate::EventType::Segment { let byte_segment = crate::FormattedSegment::::new(); EventForeachAction::Replace(crate::event::Segment::new(&byte_segment)) } else { EventForeachAction::Keep }; ControlFlow::Continue(action) }); // Check that segment event is different now let mut sticky_events4 = Vec::new(); pad.sticky_events_foreach(|event| { sticky_events4.push(event.clone()); ControlFlow::Continue(EventForeachAction::Keep) }); assert_eq!(sticky_events4.len(), 3); assert_eq!( sticky_events[0].as_ref() as *const _, sticky_events4[0].as_ref() as *const _ ); assert_eq!( sticky_events[1].as_ref() as *const _, sticky_events4[1].as_ref() as *const _ ); assert_ne!( sticky_events[2].as_ref() as *const _, sticky_events4[2].as_ref() as *const _ ); // Drop caps event pad.sticky_events_foreach(|event| { let action = if event.type_() == crate::EventType::Caps { EventForeachAction::Remove } else { EventForeachAction::Keep }; ControlFlow::Continue(action) }); // Check that caps event actually got removed let mut sticky_events5 = Vec::new(); pad.sticky_events_foreach(|event| { sticky_events5.push(event.clone()); ControlFlow::Continue(EventForeachAction::Keep) }); assert_eq!(sticky_events5.len(), 2); assert_eq!( sticky_events4[0].as_ref() as *const _, sticky_events5[0].as_ref() as *const _ ); assert_eq!( sticky_events4[2].as_ref() as *const _, sticky_events5[1].as_ref() as *const _ ); } #[test] #[allow(deprecated)] // maybe_name() is deprecated fn naming() { crate::init().unwrap(); let pad = crate::Pad::builder(crate::PadDirection::Sink).build(); assert!(pad.name().starts_with("pad")); let pad = crate::Pad::builder(crate::PadDirection::Src).build(); assert!(pad.name().starts_with("pad")); let pad = crate::Pad::builder(crate::PadDirection::Unknown).build(); assert!(pad.name().starts_with("pad")); let pad = crate::Pad::builder(crate::PadDirection::Unknown) .generated_name() .build(); assert!(pad.name().starts_with("pad")); let pad = crate::Pad::builder(crate::PadDirection::Unknown) .maybe_name(None::<&str>) .build(); assert!(pad.name().starts_with("pad")); let pad = crate::Pad::builder(crate::PadDirection::Unknown) .name_if_some(None::<&str>) .build(); assert!(pad.name().starts_with("pad")); let pad = crate::Pad::builder(crate::PadDirection::Sink) .name("sink_0") .build(); assert_eq!(pad.name(), "sink_0"); let pad = crate::Pad::builder(crate::PadDirection::Src) .name("src_0") .build(); assert_eq!(pad.name(), "src_0"); let pad = crate::Pad::builder(crate::PadDirection::Unknown) .name("test") .build(); assert_eq!(pad.name(), "test"); let pad = crate::Pad::builder(crate::PadDirection::Unknown) .maybe_name(Some("test")) .build(); assert_eq!(pad.name(), "test"); let pad = crate::Pad::builder(crate::PadDirection::Unknown) .name_if_some(Some("test")) .build(); assert_eq!(pad.name(), "test"); let caps = crate::Caps::new_any(); let templ = crate::PadTemplate::new( "sink", crate::PadDirection::Sink, crate::PadPresence::Always, &caps, ) .unwrap(); let pad = Pad::from_template(&templ); assert!(pad.name().starts_with("sink")); let pad = Pad::builder_from_template(&templ) .name("audio_sink") .build(); assert!(pad.name().starts_with("audio_sink")); let pad = Pad::builder_from_template(&templ).generated_name().build(); assert!(pad.name().starts_with("pad")); let templ = crate::PadTemplate::new( "audio_%u", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); let pad = Pad::builder_from_template(&templ).name("audio_0").build(); assert!(pad.name().starts_with("audio_0")); let pad = Pad::builder_from_template(&templ).generated_name().build(); assert!(pad.name().starts_with("pad")); } #[test] #[should_panic] fn missing_name() { crate::init().unwrap(); let caps = crate::Caps::new_any(); let templ = crate::PadTemplate::new( "audio_%u", crate::PadDirection::Sink, crate::PadPresence::Request, &caps, ) .unwrap(); // Panic: attempt to build from a wildcard-named template // without providing a name. let _pad = Pad::from_template(&templ); } } gstreamer-0.23.5/src/pad_template.rs000064400000000000000000000136371046102023000155120ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ffi::CStr; use glib::{prelude::*, translate::*}; use crate::{ffi, Caps, PadDirection, PadPresence, PadTemplate, StaticPadTemplate}; impl PadTemplate { #[doc(alias = "gst_pad_template_new_from_static_pad_template_with_gtype")] pub fn from_static_pad_template_with_gtype( pad_template: &StaticPadTemplate, pad_type: glib::types::Type, ) -> Result { skip_assert_initialized!(); unsafe { Option::<_>::from_glib_none( ffi::gst_pad_template_new_from_static_pad_template_with_gtype( mut_override(pad_template.to_glib_none().0), pad_type.into_glib(), ), ) .ok_or_else(|| glib::bool_error!("Failed to create PadTemplate")) } } #[doc(alias = "gst_pad_template_get_caps")] #[doc(alias = "get_caps")] pub fn caps(&self) -> &Caps { unsafe { let templ = &*(self.as_ptr() as *const ffi::GstPadTemplate); &*(&templ.caps as *const *mut ffi::GstCaps as *const Caps) } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] #[doc(alias = "gst_pad_template_get_documentation_caps")] #[doc(alias = "get_documentation_caps")] pub fn documentation_caps(&self) -> &Caps { unsafe { let templ = &*(self.as_ptr() as *const ffi::GstPadTemplate); if !templ.ABI.abi.documentation_caps.is_null() { &*(&templ.ABI.abi.documentation_caps as *const *mut ffi::GstCaps as *const Caps) } else { &*(&templ.caps as *const *mut ffi::GstCaps as *const Caps) } } } pub fn direction(&self) -> PadDirection { unsafe { let templ = &*(self.as_ptr() as *const ffi::GstPadTemplate); from_glib(templ.direction) } } pub fn gtype(&self) -> glib::types::Type { unsafe { let templ = &*(self.as_ptr() as *const ffi::GstPadTemplate); from_glib(templ.ABI.abi.gtype) } } #[doc(alias = "name-template")] pub fn name_template(&self) -> &str { unsafe { let templ = &*(self.as_ptr() as *const ffi::GstPadTemplate); CStr::from_ptr(templ.name_template).to_str().unwrap() } } pub fn presence(&self) -> PadPresence { unsafe { let templ = &*(self.as_ptr() as *const ffi::GstPadTemplate); from_glib(templ.presence) } } pub fn builder<'a>( name_template: &'a str, direction: PadDirection, presence: PadPresence, caps: &'a Caps, ) -> PadTemplateBuilder<'a> { skip_assert_initialized!(); PadTemplateBuilder { name_template, direction, presence, caps, gtype: None, #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] documentation_caps: None, } } } #[must_use = "The builder must be built to be used"] #[derive(Debug)] pub struct PadTemplateBuilder<'a> { name_template: &'a str, direction: PadDirection, presence: PadPresence, caps: &'a Caps, gtype: Option, #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] documentation_caps: Option<&'a Caps>, } #[allow(clippy::needless_lifetimes)] impl<'a> PadTemplateBuilder<'a> { pub fn gtype(self, gtype: glib::Type) -> Self { PadTemplateBuilder { gtype: Some(gtype), ..self } } pub fn gtype_if(self, gtype: glib::Type, predicate: bool) -> Self { if predicate { PadTemplateBuilder { gtype: Some(gtype), ..self } } else { self } } pub fn gtype_if_some(self, gtype: Option) -> Self { if let Some(gtype) = gtype { self.gtype(gtype) } else { self } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] pub fn documentation_caps(self, documentation_caps: &'a Caps) -> Self { PadTemplateBuilder { documentation_caps: Some(documentation_caps), ..self } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] pub fn documentation_caps_if(self, documentation_caps: &'a Caps, predicate: bool) -> Self { if predicate { PadTemplateBuilder { documentation_caps: Some(documentation_caps), ..self } } else { self } } #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] pub fn documentation_caps_if_some(self, documentation_caps: Option<&'a Caps>) -> Self { if let Some(documentation_caps) = documentation_caps { self.documentation_caps(documentation_caps) } else { self } } pub fn build(self) -> Result { let templ = if let Some(gtype) = self.gtype { PadTemplate::with_gtype( self.name_template, self.direction, self.presence, self.caps, gtype, )? } else { PadTemplate::new(self.name_template, self.direction, self.presence, self.caps)? }; #[cfg(feature = "v1_18")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))] if let Some(documentation_caps) = self.documentation_caps { unsafe { ffi::gst_pad_template_set_documentation_caps( templ.to_glib_none().0, documentation_caps.to_glib_none().0, ); } } Ok(templ) } } gstreamer-0.23.5/src/param_spec.rs000064400000000000000000000272301046102023000151570ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::ffi; use glib::{gobject_ffi, prelude::*, translate::*, ParamSpec}; glib::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GstParamSpecFraction")] pub struct ParamSpecFraction(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec), unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), type_ => || ffi::gst_param_spec_fraction_get_type(), } } unsafe impl Send for ParamSpecFraction {} unsafe impl Sync for ParamSpecFraction {} impl std::ops::Deref for ParamSpecFraction { type Target = ParamSpec; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self as *const ParamSpecFraction as *const ParamSpec) } } } unsafe impl ParamSpecType for ParamSpecFraction {} impl HasParamSpec for crate::Fraction { type ParamSpec = ParamSpecFraction; type SetValue = crate::Fraction; type BuilderFn = for<'a> fn(&'a str) -> ParamSpecFractionBuilder<'a>; fn param_spec_builder() -> Self::BuilderFn { ParamSpecFraction::builder } } #[doc(hidden)] impl FromGlibPtrFull<*mut gobject_ffi::GParamSpec> for ParamSpecFraction { #[inline] unsafe fn from_glib_full(ptr: *mut gobject_ffi::GParamSpec) -> Self { from_glib_full(ptr as *mut ffi::GstParamSpecFraction) } } impl ParamSpecFraction { #[doc(alias = "gst_param_spec_fraction")] pub fn builder(name: &str) -> ParamSpecFractionBuilder { assert_initialized_main_thread!(); ParamSpecFractionBuilder::new(name) } unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, min: crate::Fraction, max: crate::Fraction, default: crate::Fraction, flags: glib::ParamFlags, ) -> glib::ParamSpec { unsafe { from_glib_none(ffi::gst_param_spec_fraction( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, min.numer(), min.denom(), max.numer(), max.denom(), default.numer(), default.denom(), flags.into_glib(), )) } } #[inline] pub fn minimum(&self) -> crate::Fraction { unsafe { let ptr = self.as_ptr(); crate::Fraction::new((*ptr).min_num, (*ptr).min_den) } } #[inline] pub fn maximum(&self) -> crate::Fraction { unsafe { let ptr = self.as_ptr(); crate::Fraction::new((*ptr).max_num, (*ptr).max_den) } } #[inline] pub fn default_value(&self) -> crate::Fraction { unsafe { let ptr = self.as_ptr(); crate::Fraction::new((*ptr).def_num, (*ptr).def_den) } } #[inline] pub fn upcast(self) -> ParamSpec { unsafe { from_glib_full( IntoGlibPtr::<*mut ffi::GstParamSpecFraction>::into_glib_ptr(self) as *mut gobject_ffi::GParamSpec, ) } } #[inline] pub fn upcast_ref(&self) -> &ParamSpec { self } } #[derive(Default)] #[must_use] pub struct ParamSpecFractionBuilder<'a> { name: &'a str, nick: Option<&'a str>, blurb: Option<&'a str>, flags: glib::ParamFlags, minimum: Option, maximum: Option, default_value: Option, } impl<'a> ParamSpecFractionBuilder<'a> { fn new(name: &'a str) -> Self { assert_initialized_main_thread!(); Self { name, ..Default::default() } } // rustdoc-stripper-ignore-next /// Default: `-i32::MAX/1` pub fn minimum(mut self, minimum: crate::Fraction) -> Self { self.minimum = Some(minimum); self } // rustdoc-stripper-ignore-next /// Default: `i32::MAX/1` pub fn maximum(mut self, maximum: crate::Fraction) -> Self { self.maximum = Some(maximum); self } // rustdoc-stripper-ignore-next /// Default: `0/1` pub fn default_value(mut self, default_value: crate::Fraction) -> Self { self.default_value = Some(default_value); self } #[must_use] pub fn build(self) -> ParamSpec { unsafe { ParamSpecFraction::new_unchecked( self.name, self.nick.unwrap_or(self.name), self.blurb.unwrap_or(self.name), self.minimum .unwrap_or_else(|| crate::Fraction::new(-i32::MAX, 1)), self.maximum .unwrap_or_else(|| crate::Fraction::new(i32::MAX, 1)), self.default_value .unwrap_or_else(|| crate::Fraction::new(0, 1)), self.flags, ) } } } impl<'a> glib::prelude::ParamSpecBuilderExt<'a> for ParamSpecFractionBuilder<'a> { fn set_nick(&mut self, nick: Option<&'a str>) { self.nick = nick; } fn set_blurb(&mut self, blurb: Option<&'a str>) { self.blurb = blurb; } fn set_flags(&mut self, flags: glib::ParamFlags) { self.flags = flags; } fn current_flags(&self) -> glib::ParamFlags { self.flags } } glib::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GstParamSpecArray")] pub struct ParamSpecArray(Shared); match fn { ref => |ptr| gobject_ffi::g_param_spec_ref_sink(ptr as *mut gobject_ffi::GParamSpec), unref => |ptr| gobject_ffi::g_param_spec_unref(ptr as *mut gobject_ffi::GParamSpec), type_ => || ffi::gst_param_spec_array_get_type(), } } unsafe impl Send for ParamSpecArray {} unsafe impl Sync for ParamSpecArray {} impl std::ops::Deref for ParamSpecArray { type Target = ParamSpec; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self as *const ParamSpecArray as *const ParamSpec) } } } unsafe impl ParamSpecType for ParamSpecArray {} impl HasParamSpec for crate::Array { type ParamSpec = ParamSpecArray; type SetValue = crate::Array; type BuilderFn = for<'a> fn(&'a str) -> ParamSpecArrayBuilder<'a>; fn param_spec_builder() -> Self::BuilderFn { ParamSpecArray::builder } } #[doc(hidden)] impl FromGlibPtrFull<*mut gobject_ffi::GParamSpec> for ParamSpecArray { #[inline] unsafe fn from_glib_full(ptr: *mut gobject_ffi::GParamSpec) -> Self { from_glib_full(ptr as *mut ffi::GstParamSpecArray) } } impl ParamSpecArray { #[doc(alias = "gst_param_spec_array")] pub fn builder(name: &str) -> ParamSpecArrayBuilder { assert_initialized_main_thread!(); ParamSpecArrayBuilder::new(name) } unsafe fn new_unchecked<'a>( name: &str, nick: impl Into>, blurb: impl Into>, element_spec: Option<&glib::ParamSpec>, flags: glib::ParamFlags, ) -> glib::ParamSpec { unsafe { from_glib_none(ffi::gst_param_spec_array( name.to_glib_none().0, nick.into().to_glib_none().0, blurb.into().to_glib_none().0, element_spec.to_glib_none().0, flags.into_glib(), )) } } #[inline] pub fn element_spec(&self) -> Option<&ParamSpec> { unsafe { let ptr = self.as_ptr(); if (*ptr).element_spec.is_null() { None } else { Some( &*(&(*ptr).element_spec as *const *mut glib::gobject_ffi::GParamSpec as *const glib::ParamSpec), ) } } } #[inline] pub fn upcast(self) -> ParamSpec { unsafe { from_glib_full( IntoGlibPtr::<*mut ffi::GstParamSpecArray>::into_glib_ptr(self) as *mut gobject_ffi::GParamSpec, ) } } #[inline] pub fn upcast_ref(&self) -> &ParamSpec { self } } #[derive(Default)] #[must_use] pub struct ParamSpecArrayBuilder<'a> { name: &'a str, nick: Option<&'a str>, blurb: Option<&'a str>, flags: glib::ParamFlags, element_spec: Option<&'a glib::ParamSpec>, } impl<'a> ParamSpecArrayBuilder<'a> { fn new(name: &'a str) -> Self { assert_initialized_main_thread!(); Self { name, ..Default::default() } } // rustdoc-stripper-ignore-next /// Default: `None` pub fn element_spec(mut self, element_spec: impl Into>) -> Self { self.element_spec = element_spec.into(); self } #[must_use] pub fn build(self) -> ParamSpec { unsafe { ParamSpecArray::new_unchecked( self.name, self.nick.unwrap_or(self.name), self.blurb.unwrap_or(self.name), self.element_spec, self.flags, ) } } } impl<'a> glib::prelude::ParamSpecBuilderExt<'a> for ParamSpecArrayBuilder<'a> { fn set_nick(&mut self, nick: Option<&'a str>) { self.nick = nick; } fn set_blurb(&mut self, blurb: Option<&'a str>) { self.blurb = blurb; } fn set_flags(&mut self, flags: glib::ParamFlags) { self.flags = flags; } fn current_flags(&self) -> glib::ParamFlags { self.flags } } pub trait GstParamSpecBuilderExt<'a>: glib::prelude::ParamSpecBuilderExt<'a> { // rustdoc-stripper-ignore-next /// Mark the property as controllable fn controllable(self) -> Self { let flags = self.current_flags() | crate::PARAM_FLAG_CONTROLLABLE; self.flags(flags) } // rustdoc-stripper-ignore-next /// Mark the property as mutable in ready state fn mutable_ready(self) -> Self { let flags = self.current_flags() | crate::PARAM_FLAG_MUTABLE_READY; self.flags(flags) } // rustdoc-stripper-ignore-next /// Mark the property as mutable in paused state fn mutable_paused(self) -> Self { let flags = self.current_flags() | crate::PARAM_FLAG_MUTABLE_PAUSED; self.flags(flags) } // rustdoc-stripper-ignore-next /// Mark the property as mutable in playing state fn mutable_playing(self) -> Self { let flags = self.current_flags() | crate::PARAM_FLAG_MUTABLE_PLAYING; self.flags(flags) } #[cfg(feature = "v1_18")] // rustdoc-stripper-ignore-next /// Mark the property for showing the default value in the docs fn doc_show_default(self) -> Self { let flags = self.current_flags() | crate::PARAM_FLAG_DOC_SHOW_DEFAULT; self.flags(flags) } #[cfg(feature = "v1_18")] // rustdoc-stripper-ignore-next /// Mark the property for being only conditionally available fn conditionally_available(self) -> Self { let flags = self.current_flags() | crate::PARAM_FLAG_CONDITIONALLY_AVAILABLE; self.flags(flags) } } impl<'a, T: glib::prelude::ParamSpecBuilderExt<'a>> GstParamSpecBuilderExt<'a> for T {} #[cfg(test)] mod tests { use glib::prelude::*; use super::*; #[test] fn test_trait() { crate::init().unwrap(); let _pspec = ParamSpecFraction::builder("foo") .nick("Foo") .blurb("Foo Bar") .minimum((0, 1).into()) .maximum((100, 1).into()) .default_value((1, 1).into()) .readwrite() .mutable_playing() .build(); } } gstreamer-0.23.5/src/parse.rs000064400000000000000000000076621046102023000141660ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ptr; use glib::{prelude::*, translate::*}; use crate::{ffi, Bin, Element, Object, ParseContext, ParseFlags}; pub use crate::auto::functions::parse_bin_from_description as bin_from_description; pub use crate::auto::functions::parse_launch as launch; pub use crate::auto::functions::parse_launchv as launchv; #[doc(alias = "gst_parse_bin_from_description_full")] pub fn bin_from_description_with_name( bin_description: &str, ghost_unlinked_pads: bool, bin_name: &str, ) -> Result { skip_assert_initialized!(); let bin = bin_from_description(bin_description, ghost_unlinked_pads)?; if !bin_name.is_empty() { let obj = bin.clone().upcast::(); unsafe { ffi::gst_object_set_name(obj.to_glib_none().0, bin_name.to_glib_none().0); } } Ok(bin) } #[doc(alias = "gst_parse_bin_from_description_full")] pub fn bin_from_description_full( bin_description: &str, ghost_unlinked_pads: bool, mut context: Option<&mut ParseContext>, flags: ParseFlags, ) -> Result { skip_assert_initialized!(); unsafe { let mut error = ptr::null_mut(); let ret = ffi::gst_parse_bin_from_description_full( bin_description.to_glib_none().0, ghost_unlinked_pads.into_glib(), context.to_glib_none_mut().0, flags.into_glib(), &mut error, ); if error.is_null() { Ok(from_glib_none(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "gst_parse_bin_from_description_full")] pub fn bin_from_description_with_name_full( bin_description: &str, ghost_unlinked_pads: bool, bin_name: &str, context: Option<&mut ParseContext>, flags: ParseFlags, ) -> Result { skip_assert_initialized!(); let bin = bin_from_description_full(bin_description, ghost_unlinked_pads, context, flags)?; if !bin_name.is_empty() { let obj = bin.clone().upcast::(); unsafe { ffi::gst_object_set_name(obj.to_glib_none().0, bin_name.to_glib_none().0); } } Ok(bin) } #[doc(alias = "gst_parse_launch_full")] pub fn launch_full( pipeline_description: &str, mut context: Option<&mut ParseContext>, flags: ParseFlags, ) -> Result { assert_initialized_main_thread!(); unsafe { let mut error = ptr::null_mut(); let ret = ffi::gst_parse_launch_full( pipeline_description.to_glib_none().0, context.to_glib_none_mut().0, flags.into_glib(), &mut error, ); if error.is_null() { Ok(from_glib_none(ret)) } else { Err(from_glib_full(error)) } } } #[doc(alias = "gst_parse_launchv_full")] pub fn launchv_full( argv: &[&str], mut context: Option<&mut ParseContext>, flags: ParseFlags, ) -> Result { assert_initialized_main_thread!(); unsafe { let mut error = ptr::null_mut(); let ret = ffi::gst_parse_launchv_full( argv.to_glib_none().0, context.to_glib_none_mut().0, flags.into_glib(), &mut error, ); if error.is_null() { Ok(from_glib_none(ret)) } else { Err(from_glib_full(error)) } } } #[cfg(test)] mod tests { use super::*; use crate::prelude::*; #[test] fn test_parse_bin_from_description_with_name() { crate::init().unwrap(); let bin = bin_from_description_with_name("fakesrc ! fakesink", false, "all_fake").unwrap(); let name = bin.name(); assert_eq!(name, "all_fake"); let bin = bin_from_description_with_name("fakesrc ! fakesink", false, "").unwrap(); let name = bin.name(); assert_ne!(name, ""); } } gstreamer-0.23.5/src/parse_context.rs000064400000000000000000000022141046102023000157160ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::ffi; use glib::translate::*; glib::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GstParseContext")] pub struct ParseContext(Boxed); match fn { copy => |ptr| ffi::gst_parse_context_copy(ptr), free => |ptr| ffi::gst_parse_context_free(ptr), type_ => || ffi::gst_parse_context_get_type(), } } unsafe impl Send for ParseContext {} unsafe impl Sync for ParseContext {} impl ParseContext { #[doc(alias = "gst_parse_context_new")] pub fn new() -> Self { unsafe { from_glib_full(ffi::gst_parse_context_new()) } } #[doc(alias = "get_missing_elements")] #[doc(alias = "gst_parse_context_get_missing_elements")] pub fn missing_elements(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_parse_context_get_missing_elements( mut_override(self.to_glib_none().0), )) } } } impl Default for ParseContext { fn default() -> Self { Self::new() } } gstreamer-0.23.5/src/pipeline.rs000064400000000000000000000142551046102023000146550ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::{prelude::*, translate::*}; use crate::{ffi, prelude::*, Pipeline, PipelineFlags}; impl Pipeline { // rustdoc-stripper-ignore-next /// Creates a new [`Pipeline`] object with a default name. /// /// Use [`Pipeline::with_name()`] to create a [`Pipeline`] with a specific name. /// Use [`Pipeline::builder()`] to get a [`PipelineBuilder`] and then define a specific name. #[doc(alias = "gst_pipeline_new")] pub fn new() -> Pipeline { assert_initialized_main_thread!(); unsafe { crate::Element::from_glib_none(ffi::gst_pipeline_new(std::ptr::null())).unsafe_cast() } } // rustdoc-stripper-ignore-next /// Creates a new [`Pipeline`] object with the specified name. /// /// Use [`Pipeline::builder()`] for additional configuration. #[doc(alias = "gst_pipeline_new")] pub fn with_name(name: &str) -> Pipeline { assert_initialized_main_thread!(); unsafe { crate::Element::from_glib_none(ffi::gst_pipeline_new(name.to_glib_none().0)) .unsafe_cast() } } // rustdoc-stripper-ignore-next /// Creates a new builder-pattern struct instance to construct [`Pipeline`] objects. /// /// This method returns an instance of [`PipelineBuilder`] which can be used to create [`Pipeline`] objects. pub fn builder() -> PipelineBuilder { PipelineBuilder::new() } } mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait GstPipelineExtManual: sealed::Sealed + IsA + 'static { fn set_pipeline_flags(&self, flags: PipelineFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags |= flags.into_glib(); } } fn unset_pipeline_flags(&self, flags: PipelineFlags) { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); (*ptr).flags &= !flags.into_glib(); } } #[doc(alias = "get_pipeline_flags")] fn pipeline_flags(&self) -> PipelineFlags { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.as_ref().object_lock(); from_glib((*ptr).flags) } } } impl> GstPipelineExtManual for O {} impl Default for Pipeline { fn default() -> Self { glib::object::Object::new() } } // rustdoc-stripper-ignore-next /// A [builder-pattern] type to construct [`Pipeline`] objects. /// /// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html #[must_use = "The builder must be built to be used"] pub struct PipelineBuilder { builder: glib::object::ObjectBuilder<'static, Pipeline>, } impl PipelineBuilder { fn new() -> Self { Self { builder: glib::Object::builder(), } } // rustdoc-stripper-ignore-next /// Build the [`Pipeline`]. #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"] pub fn build(self) -> Pipeline { self.builder.build() } pub fn auto_flush_bus(self, auto_flush_bus: bool) -> Self { Self { builder: self.builder.property("auto-flush-bus", auto_flush_bus), } } pub fn auto_flush_bus_if_some(self, auto_flush_bus: Option) -> Self { if let Some(auto_flush_bus) = auto_flush_bus { self.auto_flush_bus(auto_flush_bus) } else { self } } pub fn delay(self, delay: u64) -> Self { Self { builder: self.builder.property("delay", delay), } } pub fn delay_if(self, delay: u64, predicate: bool) -> Self { if predicate { self.delay(delay) } else { self } } pub fn delay_if_some(self, delay: Option) -> Self { if let Some(delay) = delay { self.delay(delay) } else { self } } pub fn latency(self, latency: impl Into>) -> Self { if let Some(latency) = latency.into() { Self { builder: self.builder.property("latency", latency), } } else { self } } pub fn latency_if(self, latency: impl Into>, predicate: bool) -> Self { if predicate { self.latency(latency) } else { self } } pub fn latency_if_some(self, latency: Option) -> Self { if let Some(latency) = latency { self.latency(latency) } else { self } } pub fn async_handling(self, async_handling: bool) -> Self { Self { builder: self.builder.property("async-handling", async_handling), } } pub fn async_handling_if_some(self, async_handling: Option) -> Self { if let Some(async_handling) = async_handling { self.async_handling(async_handling) } else { self } } pub fn message_forward(self, message_forward: bool) -> Self { Self { builder: self.builder.property("message-forward", message_forward), } } pub fn message_forward_if_some(self, message_forward: Option) -> Self { if let Some(message_forward) = message_forward { self.message_forward(message_forward) } else { self } } pub fn name(self, name: impl Into) -> Self { Self { builder: self.builder.property("name", name.into()), } } pub fn name_if(self, name: impl Into, predicate: bool) -> Self { if predicate { self.name(name) } else { self } } pub fn name_if_some(self, name: Option>) -> Self { if let Some(name) = name { self.name(name) } else { self } } } gstreamer-0.23.5/src/plugin.rs000064400000000000000000000015711046102023000143430ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::{prelude::*, translate::*}; use crate::{ffi, prelude::*, Plugin, PluginFlags, StructureRef}; impl Plugin { #[doc(alias = "get_cache_data")] #[doc(alias = "gst_plugin_get_cache_data")] pub fn cache_data(&self) -> Option<&StructureRef> { unsafe { let cache_data = ffi::gst_plugin_get_cache_data(self.to_glib_none().0); if cache_data.is_null() { None } else { Some(StructureRef::from_glib_borrow(cache_data)) } } } #[doc(alias = "get_plugin_flags")] pub fn plugin_flags(&self) -> PluginFlags { unsafe { let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _; let _guard = self.object_lock(); from_glib((*ptr).flags) } } } gstreamer-0.23.5/src/plugin_feature.rs000064400000000000000000000033511046102023000160540ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::{ prelude::*, translate::{from_glib, FromGlibPtrFull, IntoGlib, ToGlibPtr}, }; use crate::{ffi, PluginFeature, Rank}; mod sealed { pub trait Sealed {} impl> Sealed for T {} } pub trait PluginFeatureExtManual: sealed::Sealed + IsA + Sized + 'static { #[doc(alias = "get_rank")] #[doc(alias = "gst_plugin_feature_get_rank")] fn rank(&self) -> Rank { unsafe { let rank = ffi::gst_plugin_feature_get_rank(self.as_ref().to_glib_none().0); from_glib(rank as i32) } } #[doc(alias = "gst_plugin_feature_set_rank")] fn set_rank(&self, rank: Rank) { unsafe { ffi::gst_plugin_feature_set_rank( self.as_ref().to_glib_none().0, rank.into_glib() as u32, ); } } #[doc(alias = "gst_plugin_feature_load")] fn load(&self) -> Result { unsafe { let loaded = Option::::from_glib_full(ffi::gst_plugin_feature_load( self.as_ref().to_glib_none().0, )) .ok_or_else(|| glib::bool_error!("Failed to load plugin feature"))?; Ok(loaded.unsafe_cast()) } } } impl> PluginFeatureExtManual for O {} #[cfg(test)] mod tests { use super::*; #[test] fn test_load() { crate::init().unwrap(); let factory = crate::ElementFactory::find("identity").unwrap(); let loaded = factory.load().unwrap(); assert_eq!(factory.type_(), loaded.type_()); let _element = loaded.create().build().unwrap(); } } gstreamer-0.23.5/src/promise.rs000064400000000000000000000155301046102023000145230ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ ops::Deref, pin::Pin, ptr, task::{Context, Poll}, }; use glib::translate::*; use crate::{ffi, PromiseResult, Structure, StructureRef}; glib::wrapper! { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[doc(alias = "GstPromise")] pub struct Promise(Shared); match fn { ref => |ptr| ffi::gst_mini_object_ref(ptr as *mut _), unref => |ptr| ffi::gst_mini_object_unref(ptr as *mut _), type_ => || ffi::gst_promise_get_type(), } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum PromiseError { Interrupted, Expired, Other(PromiseResult), } impl Promise { #[doc(alias = "gst_promise_new")] pub fn new() -> Promise { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_promise_new()) } } #[doc(alias = "gst_promise_new_with_change_func")] pub fn with_change_func(func: F) -> Promise where F: FnOnce(Result, PromiseError>) + Send + 'static, { assert_initialized_main_thread!(); let user_data: Box> = Box::new(Some(func)); unsafe extern "C" fn trampoline< F: FnOnce(Result, PromiseError>) + Send + 'static, >( promise: *mut ffi::GstPromise, user_data: glib::ffi::gpointer, ) { let user_data: &mut Option = &mut *(user_data as *mut _); let callback = user_data.take().unwrap(); let promise: Borrowed = from_glib_borrow(promise); let res = match promise.wait() { PromiseResult::Replied => Ok(promise.get_reply()), PromiseResult::Interrupted => Err(PromiseError::Interrupted), PromiseResult::Expired => Err(PromiseError::Expired), PromiseResult::Pending => { panic!("Promise resolved but returned Pending"); } err => Err(PromiseError::Other(err)), }; callback(res); } unsafe extern "C" fn free_user_data< F: FnOnce(Result, PromiseError>) + Send + 'static, >( user_data: glib::ffi::gpointer, ) { let _: Box> = Box::from_raw(user_data as *mut _); } unsafe { from_glib_full(ffi::gst_promise_new_with_change_func( Some(trampoline::), Box::into_raw(user_data) as *mut _, Some(free_user_data::), )) } } pub fn new_future() -> (Self, PromiseFuture) { use futures_channel::oneshot; // We only use the channel as a convenient waker let (sender, receiver) = oneshot::channel(); let promise = Self::with_change_func(move |_res| { let _ = sender.send(()); }); (promise.clone(), PromiseFuture(promise, receiver)) } #[doc(alias = "gst_promise_expire")] pub fn expire(&self) { unsafe { ffi::gst_promise_expire(self.to_glib_none().0); } } #[doc(alias = "gst_promise_get_reply")] pub fn get_reply(&self) -> Option<&StructureRef> { unsafe { let s = ffi::gst_promise_get_reply(self.to_glib_none().0); if s.is_null() { None } else { Some(StructureRef::from_glib_borrow(s)) } } } #[doc(alias = "gst_promise_interrupt")] pub fn interrupt(&self) { unsafe { ffi::gst_promise_interrupt(self.to_glib_none().0); } } #[doc(alias = "gst_promise_reply")] pub fn reply(&self, s: Option) { unsafe { ffi::gst_promise_reply( self.to_glib_none().0, s.map(|s| s.into_glib_ptr()).unwrap_or(ptr::null_mut()), ); } } #[doc(alias = "gst_promise_wait")] pub fn wait(&self) -> PromiseResult { unsafe { from_glib(ffi::gst_promise_wait(self.to_glib_none().0)) } } } impl Default for Promise { fn default() -> Self { Self::new() } } unsafe impl Send for Promise {} unsafe impl Sync for Promise {} #[derive(Debug)] pub struct PromiseFuture(Promise, futures_channel::oneshot::Receiver<()>); pub struct PromiseReply(Promise); impl std::future::Future for PromiseFuture { type Output = Result, PromiseError>; fn poll(mut self: Pin<&mut Self>, context: &mut Context) -> Poll { match Pin::new(&mut self.1).poll(context) { Poll::Ready(Err(_)) => panic!("Sender dropped before callback was called"), Poll::Ready(Ok(())) => { let res = match self.0.wait() { PromiseResult::Replied => { if self.0.get_reply().is_none() { Ok(None) } else { Ok(Some(PromiseReply(self.0.clone()))) } } PromiseResult::Interrupted => Err(PromiseError::Interrupted), PromiseResult::Expired => Err(PromiseError::Expired), PromiseResult::Pending => { panic!("Promise resolved but returned Pending"); } err => Err(PromiseError::Other(err)), }; Poll::Ready(res) } Poll::Pending => Poll::Pending, } } } impl futures_core::future::FusedFuture for PromiseFuture { fn is_terminated(&self) -> bool { self.1.is_terminated() } } impl Deref for PromiseReply { type Target = StructureRef; #[inline] fn deref(&self) -> &StructureRef { self.0.get_reply().expect("Promise without reply") } } impl std::fmt::Debug for PromiseReply { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut debug = f.debug_tuple("PromiseReply"); match self.0.get_reply() { Some(reply) => debug.field(reply), None => debug.field(&""), } .finish() } } #[cfg(test)] mod tests { use std::{sync::mpsc::channel, thread}; use super::*; #[test] fn test_change_func() { crate::init().unwrap(); let (sender, receiver) = channel(); let promise = Promise::with_change_func(move |res| { sender.send(res.map(|s| s.map(ToOwned::to_owned))).unwrap(); }); thread::spawn(move || { promise.reply(Some(crate::Structure::new_empty("foo/bar"))); }); let res = receiver.recv().unwrap(); let res = res.expect("promise failed").expect("promise returned None"); assert_eq!(res.name(), "foo/bar"); } } gstreamer-0.23.5/src/proxy_pad.rs000064400000000000000000000046621046102023000150560ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::ptr; use glib::{prelude::*, translate::*}; use crate::{ffi, Buffer, BufferList, FlowError, FlowSuccess, Pad, ProxyPad}; impl ProxyPad { #[doc(alias = "gst_proxy_pad_chain_default")] pub fn chain_default>( pad: &O, parent: Option<&impl IsA>, buffer: Buffer, ) -> Result { skip_assert_initialized!(); unsafe { try_from_glib(ffi::gst_proxy_pad_chain_default( pad.as_ptr() as *mut ffi::GstPad, parent.map(|p| p.as_ref()).to_glib_none().0, buffer.into_glib_ptr(), )) } } #[doc(alias = "gst_proxy_pad_chain_list_default")] pub fn chain_list_default>( pad: &O, parent: Option<&impl IsA>, list: BufferList, ) -> Result { skip_assert_initialized!(); unsafe { try_from_glib(ffi::gst_proxy_pad_chain_list_default( pad.as_ptr() as *mut ffi::GstPad, parent.map(|p| p.as_ref()).to_glib_none().0, list.into_glib_ptr(), )) } } #[doc(alias = "gst_proxy_pad_getrange_default")] pub fn getrange_default>( pad: &O, parent: Option<&impl IsA>, offset: u64, size: u32, ) -> Result { skip_assert_initialized!(); unsafe { let mut buffer = ptr::null_mut(); FlowSuccess::try_from_glib(ffi::gst_proxy_pad_getrange_default( pad.as_ptr() as *mut ffi::GstPad, parent.map(|p| p.as_ref()).to_glib_none().0, offset, size, &mut buffer, )) .map(|_| from_glib_full(buffer)) } } #[doc(alias = "gst_proxy_pad_iterate_internal_links_default")] pub fn iterate_internal_links_default>( pad: &O, parent: Option<&impl IsA>, ) -> Option> { skip_assert_initialized!(); unsafe { from_glib_full(ffi::gst_proxy_pad_iterate_internal_links_default( pad.as_ptr() as *mut ffi::GstPad, parent.map(|p| p.as_ref()).to_glib_none().0, )) } } } gstreamer-0.23.5/src/query.rs000064400000000000000000001770231046102023000142200ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{ borrow::{Borrow, BorrowMut}, ffi::CStr, fmt, mem, ops::{Deref, DerefMut}, ptr, }; use glib::{object::IsA, translate::*}; use crate::{ ffi, format::{CompatibleFormattedValue, FormattedValue, GenericFormattedValue}, structure::*, }; mini_object_wrapper!(Query, QueryRef, ffi::GstQuery, || { ffi::gst_query_get_type() }); impl QueryRef { #[doc(alias = "get_structure")] #[doc(alias = "gst_query_get_structure")] #[inline] pub fn structure(&self) -> Option<&StructureRef> { unsafe { let structure = ffi::gst_query_get_structure(self.as_mut_ptr()); if structure.is_null() { None } else { Some(StructureRef::from_glib_borrow(structure)) } } } #[doc(alias = "get_mut_structure")] #[doc(alias = "gst_query_writable_structure")] #[inline] pub fn structure_mut(&mut self) -> &mut StructureRef { unsafe { let structure = ffi::gst_query_writable_structure(self.as_mut_ptr()); StructureRef::from_glib_borrow_mut(structure) } } #[doc(alias = "GST_QUERY_IS_DOWNSTREAM")] #[inline] pub fn is_downstream(&self) -> bool { unsafe { ((*self.as_ptr()).type_ as u32) & ffi::GST_QUERY_TYPE_DOWNSTREAM != 0 } } #[doc(alias = "GST_QUERY_IS_UPSTREAM")] #[inline] pub fn is_upstream(&self) -> bool { unsafe { ((*self.as_ptr()).type_ as u32) & ffi::GST_QUERY_TYPE_UPSTREAM != 0 } } #[doc(alias = "GST_QUERY_IS_SERIALIZED")] #[inline] pub fn is_serialized(&self) -> bool { unsafe { ((*self.as_ptr()).type_ as u32) & ffi::GST_QUERY_TYPE_SERIALIZED != 0 } } pub fn view(&self) -> QueryView { unsafe { let type_ = (*self.as_ptr()).type_; match type_ { ffi::GST_QUERY_POSITION => Position::view(self), ffi::GST_QUERY_DURATION => Duration::view(self), ffi::GST_QUERY_LATENCY => Latency::view(self), ffi::GST_QUERY_SEEKING => Seeking::view(self), ffi::GST_QUERY_SEGMENT => Segment::view(self), ffi::GST_QUERY_CONVERT => Convert::view(self), ffi::GST_QUERY_FORMATS => Formats::view(self), ffi::GST_QUERY_BUFFERING => Buffering::view(self), ffi::GST_QUERY_CUSTOM => Custom::view(self), ffi::GST_QUERY_URI => Uri::view(self), ffi::GST_QUERY_ALLOCATION => Allocation::view(self), ffi::GST_QUERY_SCHEDULING => Scheduling::view(self), ffi::GST_QUERY_ACCEPT_CAPS => AcceptCaps::view(self), ffi::GST_QUERY_CAPS => Caps::view(self), ffi::GST_QUERY_DRAIN => Drain::view(self), ffi::GST_QUERY_CONTEXT => Context::view(self), #[cfg(feature = "v1_16")] ffi::GST_QUERY_BITRATE => Bitrate::view(self), #[cfg(feature = "v1_22")] ffi::GST_QUERY_SELECTABLE => Selectable::view(self), _ => Other::view(self), } } } pub fn view_mut(&mut self) -> QueryViewMut { unsafe { let type_ = (*self.as_ptr()).type_; match type_ { ffi::GST_QUERY_POSITION => Position::view_mut(self), ffi::GST_QUERY_DURATION => Duration::view_mut(self), ffi::GST_QUERY_LATENCY => Latency::view_mut(self), ffi::GST_QUERY_SEEKING => Seeking::view_mut(self), ffi::GST_QUERY_SEGMENT => Segment::view_mut(self), ffi::GST_QUERY_CONVERT => Convert::view_mut(self), ffi::GST_QUERY_FORMATS => Formats::view_mut(self), ffi::GST_QUERY_BUFFERING => Buffering::view_mut(self), ffi::GST_QUERY_CUSTOM => Custom::view_mut(self), ffi::GST_QUERY_URI => Uri::view_mut(self), ffi::GST_QUERY_ALLOCATION => Allocation::view_mut(self), ffi::GST_QUERY_SCHEDULING => Scheduling::view_mut(self), ffi::GST_QUERY_ACCEPT_CAPS => AcceptCaps::view_mut(self), ffi::GST_QUERY_CAPS => Caps::view_mut(self), ffi::GST_QUERY_DRAIN => Drain::view_mut(self), ffi::GST_QUERY_CONTEXT => Context::view_mut(self), #[cfg(feature = "v1_16")] ffi::GST_QUERY_BITRATE => Bitrate::view_mut(self), #[cfg(feature = "v1_22")] ffi::GST_QUERY_SELECTABLE => Selectable::view_mut(self), _ => Other::view_mut(self), } } } } impl fmt::Debug for Query { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { QueryRef::fmt(self, f) } } impl fmt::Debug for QueryRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Query") .field("ptr", &self.as_ptr()) .field("type", &unsafe { let type_ = ffi::gst_query_type_get_name((*self.as_ptr()).type_); CStr::from_ptr(type_).to_str().unwrap() }) .field("structure", &self.structure()) .finish() } } #[derive(Debug)] #[non_exhaustive] pub enum QueryView<'a> { Position(&'a Position), Duration(&'a Duration), Latency(&'a Latency), Seeking(&'a Seeking), Segment(&'a Segment), Convert(&'a Convert), Formats(&'a Formats), Buffering(&'a Buffering), Custom(&'a Custom), Uri(&'a Uri), Allocation(&'a Allocation), Scheduling(&'a Scheduling), AcceptCaps(&'a AcceptCaps), Caps(&'a Caps), Drain(&'a Drain), Context(&'a Context), #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] Bitrate(&'a Bitrate), #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] Selectable(&'a Selectable), Other(&'a Other), } #[derive(Debug)] #[non_exhaustive] pub enum QueryViewMut<'a> { Position(&'a mut Position), Duration(&'a mut Duration), Latency(&'a mut Latency), Seeking(&'a mut Seeking), Segment(&'a mut Segment), Convert(&'a mut Convert), Formats(&'a mut Formats), Buffering(&'a mut Buffering), Custom(&'a mut Custom), Uri(&'a mut Uri), Allocation(&'a mut Allocation), Scheduling(&'a mut Scheduling), AcceptCaps(&'a mut AcceptCaps), Caps(&'a mut Caps), Drain(&'a mut Drain), Context(&'a mut Context), #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] Bitrate(&'a mut Bitrate), #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] Selectable(&'a mut Selectable), Other(&'a mut Other), } macro_rules! declare_concrete_query( ($name:ident, $param:ident) => { #[repr(transparent)] pub struct $name<$param = QueryRef>($param); impl $name { #[inline] pub fn query(&self) -> &QueryRef { unsafe { &*(self as *const Self as *const QueryRef) } } #[inline] pub fn query_mut(&mut self) -> &mut QueryRef { unsafe { &mut *(self as *mut Self as *mut QueryRef) } } #[inline] unsafe fn view(query: &QueryRef) -> QueryView<'_> { let query = &*(query as *const QueryRef as *const Self); QueryView::$name(query) } #[inline] unsafe fn view_mut(query: &mut QueryRef) -> QueryViewMut<'_> { let query = &mut *(query as *mut QueryRef as *mut Self); QueryViewMut::$name(query) } } impl Deref for $name { type Target = QueryRef; #[inline] fn deref(&self) -> &Self::Target { self.query() } } impl DerefMut for $name { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { self.query_mut() } } impl ToOwned for $name { type Owned = $name; #[inline] fn to_owned(&self) -> Self::Owned { $name::(self.copy()) } } impl $name { #[inline] pub fn get_mut(&mut self) -> Option<&mut $name> { self.0 .get_mut() .map(|query| unsafe { &mut *(query as *mut QueryRef as *mut $name) }) } } impl Deref for $name { type Target = $name; #[inline] fn deref(&self) -> &Self::Target { unsafe { &*(self.0.as_ptr() as *const Self::Target) } } } impl DerefMut for $name { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { debug_assert!(self.0.is_writable()); unsafe { &mut *(self.0.as_mut_ptr() as *mut Self::Target) } } } impl Borrow<$name> for $name { #[inline] fn borrow(&self) -> &$name { &*self } } impl BorrowMut<$name> for $name { #[inline] fn borrow_mut(&mut self) -> &mut $name { &mut *self } } impl From<$name> for Query { #[inline] fn from(concrete: $name) -> Self { skip_assert_initialized!(); concrete.0 } } } ); declare_concrete_query!(Position, T); impl Position { #[doc(alias = "gst_query_new_position")] pub fn new(fmt: crate::Format) -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_position(fmt.into_glib()))) } } } impl Position { #[doc(alias = "get_result")] #[doc(alias = "gst_query_parse_position")] pub fn result(&self) -> GenericFormattedValue { unsafe { let mut fmt = mem::MaybeUninit::uninit(); let mut pos = mem::MaybeUninit::uninit(); ffi::gst_query_parse_position(self.as_mut_ptr(), fmt.as_mut_ptr(), pos.as_mut_ptr()); GenericFormattedValue::new(from_glib(fmt.assume_init()), pos.assume_init()) } } #[doc(alias = "get_format")] #[doc(alias = "gst_query_parse_position")] pub fn format(&self) -> crate::Format { unsafe { let mut fmt = mem::MaybeUninit::uninit(); ffi::gst_query_parse_position(self.as_mut_ptr(), fmt.as_mut_ptr(), ptr::null_mut()); from_glib(fmt.assume_init()) } } #[doc(alias = "gst_query_set_position")] pub fn set(&mut self, pos: impl FormattedValue) { assert_eq!(pos.format(), self.format()); unsafe { ffi::gst_query_set_position( self.as_mut_ptr(), pos.format().into_glib(), pos.into_raw_value(), ); } } } impl std::fmt::Debug for Position { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Position") .field("structure", &self.query().structure()) .field("result", &self.result()) .field("format", &self.format()) .finish() } } impl std::fmt::Debug for Position { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Position::::fmt(self, f) } } declare_concrete_query!(Duration, T); impl Duration { #[doc(alias = "gst_query_new_duration")] pub fn new(fmt: crate::Format) -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_duration(fmt.into_glib()))) } } } impl Duration { #[doc(alias = "get_result")] #[doc(alias = "gst_query_parse_duration")] pub fn result(&self) -> GenericFormattedValue { unsafe { let mut fmt = mem::MaybeUninit::uninit(); let mut pos = mem::MaybeUninit::uninit(); ffi::gst_query_parse_duration(self.as_mut_ptr(), fmt.as_mut_ptr(), pos.as_mut_ptr()); GenericFormattedValue::new(from_glib(fmt.assume_init()), pos.assume_init()) } } #[doc(alias = "get_format")] #[doc(alias = "gst_query_parse_duration")] pub fn format(&self) -> crate::Format { unsafe { let mut fmt = mem::MaybeUninit::uninit(); ffi::gst_query_parse_duration(self.as_mut_ptr(), fmt.as_mut_ptr(), ptr::null_mut()); from_glib(fmt.assume_init()) } } #[doc(alias = "gst_query_set_duration")] pub fn set(&mut self, dur: impl FormattedValue) { assert_eq!(dur.format(), self.format()); unsafe { ffi::gst_query_set_duration( self.as_mut_ptr(), dur.format().into_glib(), dur.into_raw_value(), ); } } } impl std::fmt::Debug for Duration { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Duration") .field("structure", &self.query().structure()) .field("result", &self.result()) .field("format", &self.format()) .finish() } } impl std::fmt::Debug for Duration { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Duration::::fmt(self, f) } } declare_concrete_query!(Latency, T); impl Latency { #[doc(alias = "gst_query_new_latency")] pub fn new() -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_latency())) } } } impl Default for Latency { fn default() -> Self { Self::new() } } impl Latency { #[doc(alias = "get_result")] #[doc(alias = "gst_query_parse_latency")] pub fn result(&self) -> (bool, crate::ClockTime, Option) { unsafe { let mut live = mem::MaybeUninit::uninit(); let mut min = mem::MaybeUninit::uninit(); let mut max = mem::MaybeUninit::uninit(); ffi::gst_query_parse_latency( self.as_mut_ptr(), live.as_mut_ptr(), min.as_mut_ptr(), max.as_mut_ptr(), ); ( from_glib(live.assume_init()), try_from_glib(min.assume_init()).expect("undefined min latency"), from_glib(max.assume_init()), ) } } #[doc(alias = "gst_query_set_latency")] pub fn set( &mut self, live: bool, min: crate::ClockTime, max: impl Into>, ) { unsafe { ffi::gst_query_set_latency( self.as_mut_ptr(), live.into_glib(), min.into_glib(), max.into().into_glib(), ); } } } impl std::fmt::Debug for Latency { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Latency") .field("structure", &self.query().structure()) .field("result", &self.result()) .finish() } } impl std::fmt::Debug for Latency { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Latency::::fmt(self, f) } } declare_concrete_query!(Seeking, T); impl Seeking { #[doc(alias = "gst_query_new_seeking")] pub fn new(fmt: crate::Format) -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_seeking(fmt.into_glib()))) } } } impl Seeking { #[doc(alias = "get_result")] #[doc(alias = "gst_query_parse_seeking")] pub fn result(&self) -> (bool, GenericFormattedValue, GenericFormattedValue) { unsafe { let mut fmt = mem::MaybeUninit::uninit(); let mut seekable = mem::MaybeUninit::uninit(); let mut start = mem::MaybeUninit::uninit(); let mut end = mem::MaybeUninit::uninit(); ffi::gst_query_parse_seeking( self.as_mut_ptr(), fmt.as_mut_ptr(), seekable.as_mut_ptr(), start.as_mut_ptr(), end.as_mut_ptr(), ); ( from_glib(seekable.assume_init()), GenericFormattedValue::new(from_glib(fmt.assume_init()), start.assume_init()), GenericFormattedValue::new(from_glib(fmt.assume_init()), end.assume_init()), ) } } #[doc(alias = "get_format")] #[doc(alias = "gst_query_parse_seeking")] pub fn format(&self) -> crate::Format { unsafe { let mut fmt = mem::MaybeUninit::uninit(); ffi::gst_query_parse_seeking( self.as_mut_ptr(), fmt.as_mut_ptr(), ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ); from_glib(fmt.assume_init()) } } #[doc(alias = "gst_query_set_seeking")] pub fn set( &mut self, seekable: bool, start: V, end: impl CompatibleFormattedValue, ) { assert_eq!(self.format(), start.format()); let end = end.try_into_checked(start).unwrap(); unsafe { ffi::gst_query_set_seeking( self.as_mut_ptr(), start.format().into_glib(), seekable.into_glib(), start.into_raw_value(), end.into_raw_value(), ); } } } impl std::fmt::Debug for Seeking { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Seeking") .field("structure", &self.query().structure()) .field("result", &self.result()) .field("format", &self.format()) .finish() } } impl std::fmt::Debug for Seeking { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Seeking::::fmt(self, f) } } declare_concrete_query!(Segment, T); impl Segment { #[doc(alias = "gst_query_new_segment")] pub fn new(fmt: crate::Format) -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_segment(fmt.into_glib()))) } } } impl Segment { #[doc(alias = "get_result")] #[doc(alias = "gst_query_parse_segment")] pub fn result(&self) -> (f64, GenericFormattedValue, GenericFormattedValue) { unsafe { let mut rate = mem::MaybeUninit::uninit(); let mut fmt = mem::MaybeUninit::uninit(); let mut start = mem::MaybeUninit::uninit(); let mut stop = mem::MaybeUninit::uninit(); ffi::gst_query_parse_segment( self.as_mut_ptr(), rate.as_mut_ptr(), fmt.as_mut_ptr(), start.as_mut_ptr(), stop.as_mut_ptr(), ); ( rate.assume_init(), GenericFormattedValue::new(from_glib(fmt.assume_init()), start.assume_init()), GenericFormattedValue::new(from_glib(fmt.assume_init()), stop.assume_init()), ) } } #[doc(alias = "get_format")] #[doc(alias = "gst_query_parse_segment")] pub fn format(&self) -> crate::Format { unsafe { let mut fmt = mem::MaybeUninit::uninit(); ffi::gst_query_parse_segment( self.as_mut_ptr(), ptr::null_mut(), fmt.as_mut_ptr(), ptr::null_mut(), ptr::null_mut(), ); from_glib(fmt.assume_init()) } } #[doc(alias = "gst_query_set_segment")] pub fn set( &mut self, rate: f64, start: V, stop: impl CompatibleFormattedValue, ) { let stop = stop.try_into_checked(start).unwrap(); unsafe { ffi::gst_query_set_segment( self.as_mut_ptr(), rate, start.format().into_glib(), start.into_raw_value(), stop.into_raw_value(), ); } } } impl std::fmt::Debug for Segment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Segment") .field("structure", &self.query().structure()) .field("result", &self.result()) .field("format", &self.format()) .finish() } } impl std::fmt::Debug for Segment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Segment::::fmt(self, f) } } declare_concrete_query!(Convert, T); impl Convert { #[doc(alias = "gst_query_new_convert")] pub fn new(value: impl FormattedValue, dest_fmt: crate::Format) -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_convert( value.format().into_glib(), value.into_raw_value(), dest_fmt.into_glib(), ))) } } } impl Convert { #[doc(alias = "get_result")] #[doc(alias = "gst_query_parse_convert")] pub fn result(&self) -> (GenericFormattedValue, GenericFormattedValue) { unsafe { let mut src_fmt = mem::MaybeUninit::uninit(); let mut src = mem::MaybeUninit::uninit(); let mut dest_fmt = mem::MaybeUninit::uninit(); let mut dest = mem::MaybeUninit::uninit(); ffi::gst_query_parse_convert( self.as_mut_ptr(), src_fmt.as_mut_ptr(), src.as_mut_ptr(), dest_fmt.as_mut_ptr(), dest.as_mut_ptr(), ); ( GenericFormattedValue::new(from_glib(src_fmt.assume_init()), src.assume_init()), GenericFormattedValue::new(from_glib(dest_fmt.assume_init()), dest.assume_init()), ) } } #[doc(alias = "gst_query_parse_convert")] pub fn get(&self) -> (GenericFormattedValue, crate::Format) { unsafe { let mut src_fmt = mem::MaybeUninit::uninit(); let mut src = mem::MaybeUninit::uninit(); let mut dest_fmt = mem::MaybeUninit::uninit(); ffi::gst_query_parse_convert( self.as_mut_ptr(), src_fmt.as_mut_ptr(), src.as_mut_ptr(), dest_fmt.as_mut_ptr(), ptr::null_mut(), ); ( GenericFormattedValue::new(from_glib(src_fmt.assume_init()), src.assume_init()), from_glib(dest_fmt.assume_init()), ) } } #[doc(alias = "gst_query_set_convert")] pub fn set(&mut self, src: impl FormattedValue, dest: impl FormattedValue) { unsafe { ffi::gst_query_set_convert( self.as_mut_ptr(), src.format().into_glib(), src.into_raw_value(), dest.format().into_glib(), dest.into_raw_value(), ); } } } impl std::fmt::Debug for Convert { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (source, dest) = self.result(); f.debug_struct("Convert") .field("structure", &self.query().structure()) .field("source", &source) .field("dest", &dest) .finish() } } impl std::fmt::Debug for Convert { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Convert::::fmt(self, f) } } declare_concrete_query!(Formats, T); impl Formats { #[doc(alias = "gst_query_new_formats")] pub fn new() -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_formats())) } } } impl Default for Formats { fn default() -> Self { Self::new() } } impl Formats { #[doc(alias = "get_result")] #[doc(alias = "gst_query_parse_n_formats")] #[doc(alias = "gst_query_parse_nth_format")] pub fn result(&self) -> Vec { unsafe { let mut n = mem::MaybeUninit::uninit(); ffi::gst_query_parse_n_formats(self.as_mut_ptr(), n.as_mut_ptr()); let n = n.assume_init(); let mut res = Vec::with_capacity(n as usize); for i in 0..n { let mut fmt = mem::MaybeUninit::uninit(); ffi::gst_query_parse_nth_format(self.as_mut_ptr(), i, fmt.as_mut_ptr()); res.push(from_glib(fmt.assume_init())); } res } } #[doc(alias = "gst_query_set_formats")] #[doc(alias = "gst_query_set_formatsv")] pub fn set(&mut self, formats: &[crate::Format]) { unsafe { let v: Vec<_> = formats.iter().map(|f| f.into_glib()).collect(); ffi::gst_query_set_formatsv(self.as_mut_ptr(), v.len() as i32, v.as_ptr() as *mut _); } } } impl std::fmt::Debug for Formats { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Formats") .field("structure", &self.query().structure()) .field("result", &self.result()) .finish() } } impl std::fmt::Debug for Formats { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Formats::::fmt(self, f) } } declare_concrete_query!(Buffering, T); impl Buffering { #[doc(alias = "gst_query_new_buffering")] pub fn new(fmt: crate::Format) -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_buffering( fmt.into_glib(), ))) } } } impl Buffering { #[doc(alias = "get_format")] #[doc(alias = "gst_query_parse_buffering_range")] pub fn format(&self) -> crate::Format { unsafe { let mut fmt = mem::MaybeUninit::uninit(); ffi::gst_query_parse_buffering_range( self.as_mut_ptr(), fmt.as_mut_ptr(), ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ); from_glib(fmt.assume_init()) } } #[doc(alias = "get_percent")] #[doc(alias = "gst_query_parse_buffering_percent")] pub fn percent(&self) -> (bool, i32) { unsafe { let mut busy = mem::MaybeUninit::uninit(); let mut percent = mem::MaybeUninit::uninit(); ffi::gst_query_parse_buffering_percent( self.as_mut_ptr(), busy.as_mut_ptr(), percent.as_mut_ptr(), ); (from_glib(busy.assume_init()), percent.assume_init()) } } #[doc(alias = "get_range")] #[doc(alias = "gst_query_parse_buffering_range")] pub fn range(&self) -> (GenericFormattedValue, GenericFormattedValue, i64) { unsafe { let mut fmt = mem::MaybeUninit::uninit(); let mut start = mem::MaybeUninit::uninit(); let mut stop = mem::MaybeUninit::uninit(); let mut estimated_total = mem::MaybeUninit::uninit(); ffi::gst_query_parse_buffering_range( self.as_mut_ptr(), fmt.as_mut_ptr(), start.as_mut_ptr(), stop.as_mut_ptr(), estimated_total.as_mut_ptr(), ); ( GenericFormattedValue::new(from_glib(fmt.assume_init()), start.assume_init()), GenericFormattedValue::new(from_glib(fmt.assume_init()), stop.assume_init()), estimated_total.assume_init(), ) } } #[doc(alias = "get_stats")] #[doc(alias = "gst_query_parse_buffering_stats")] pub fn stats(&self) -> (crate::BufferingMode, i32, i32, i64) { unsafe { let mut mode = mem::MaybeUninit::uninit(); let mut avg_in = mem::MaybeUninit::uninit(); let mut avg_out = mem::MaybeUninit::uninit(); let mut buffering_left = mem::MaybeUninit::uninit(); ffi::gst_query_parse_buffering_stats( self.as_mut_ptr(), mode.as_mut_ptr(), avg_in.as_mut_ptr(), avg_out.as_mut_ptr(), buffering_left.as_mut_ptr(), ); ( from_glib(mode.assume_init()), avg_in.assume_init(), avg_out.assume_init(), buffering_left.assume_init(), ) } } #[doc(alias = "get_ranges")] #[doc(alias = "gst_query_get_n_buffering_ranges")] #[doc(alias = "gst_query_parse_nth_buffering_range")] pub fn ranges(&self) -> Vec<(GenericFormattedValue, GenericFormattedValue)> { unsafe { let mut fmt = mem::MaybeUninit::uninit(); ffi::gst_query_parse_buffering_range( self.as_mut_ptr(), fmt.as_mut_ptr(), ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ); let fmt = from_glib(fmt.assume_init()); let n = ffi::gst_query_get_n_buffering_ranges(self.as_mut_ptr()); let mut res = Vec::with_capacity(n as usize); for i in 0..n { let mut start = mem::MaybeUninit::uninit(); let mut stop = mem::MaybeUninit::uninit(); let s: bool = from_glib(ffi::gst_query_parse_nth_buffering_range( self.as_mut_ptr(), i, start.as_mut_ptr(), stop.as_mut_ptr(), )); if s { res.push(( GenericFormattedValue::new(fmt, start.assume_init()), GenericFormattedValue::new(fmt, stop.assume_init()), )); } } res } } #[doc(alias = "gst_query_set_buffering_percent")] pub fn set_percent(&mut self, busy: bool, percent: i32) { unsafe { ffi::gst_query_set_buffering_percent(self.as_mut_ptr(), busy.into_glib(), percent); } } #[doc(alias = "gst_query_set_buffering_range")] pub fn set_range( &mut self, start: V, stop: impl CompatibleFormattedValue, estimated_total: i64, ) { assert_eq!(self.format(), start.format()); let stop = stop.try_into_checked(start).unwrap(); unsafe { ffi::gst_query_set_buffering_range( self.as_mut_ptr(), start.format().into_glib(), start.into_raw_value(), stop.into_raw_value(), estimated_total, ); } } #[doc(alias = "gst_query_set_buffering_stats")] pub fn set_stats( &mut self, mode: crate::BufferingMode, avg_in: i32, avg_out: i32, buffering_left: i64, ) { skip_assert_initialized!(); unsafe { ffi::gst_query_set_buffering_stats( self.as_mut_ptr(), mode.into_glib(), avg_in, avg_out, buffering_left, ); } } #[doc(alias = "gst_query_add_buffering_range")] pub fn add_buffering_ranges + Copy>( &mut self, ranges: &[(V, U)], ) { unsafe { let fmt = self.format(); for &(start, stop) in ranges { assert_eq!(start.format(), fmt); let stop = stop.try_into_checked(start).unwrap(); ffi::gst_query_add_buffering_range( self.as_mut_ptr(), start.into_raw_value(), stop.into_raw_value(), ); } } } } impl std::fmt::Debug for Buffering { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Buffering") .field("structure", &self.query().structure()) .field("format", &self.format()) .field("percent", &self.percent()) .field("range", &self.range()) .finish() } } impl std::fmt::Debug for Buffering { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Buffering::::fmt(self, f) } } declare_concrete_query!(Custom, T); impl Custom { #[doc(alias = "gst_query_new_custom")] pub fn new(structure: crate::Structure) -> Self { skip_assert_initialized!(); unsafe { Self(from_glib_full(ffi::gst_query_new_custom( ffi::GST_QUERY_CUSTOM, structure.into_glib_ptr(), ))) } } } impl std::fmt::Debug for Custom { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Custom") .field("structure", &self.query().structure()) .finish() } } impl std::fmt::Debug for Custom { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Custom::::fmt(self, f) } } declare_concrete_query!(Uri, T); impl Uri { #[doc(alias = "gst_query_new_uri")] pub fn new() -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_uri())) } } } impl Default for Uri { fn default() -> Self { Self::new() } } impl Uri { #[doc(alias = "get_uri")] #[doc(alias = "gst_query_parse_uri")] pub fn uri(&self) -> Option { unsafe { let mut uri = ptr::null_mut(); ffi::gst_query_parse_uri(self.as_mut_ptr(), &mut uri); from_glib_full(uri) } } #[doc(alias = "get_redirection")] #[doc(alias = "gst_query_parse_uri_redirection")] #[doc(alias = "gst_query_parse_uri_redirection_permanent")] pub fn redirection(&self) -> (Option, bool) { unsafe { let mut uri = ptr::null_mut(); ffi::gst_query_parse_uri_redirection(self.as_mut_ptr(), &mut uri); let mut permanent = mem::MaybeUninit::uninit(); ffi::gst_query_parse_uri_redirection_permanent( self.as_mut_ptr(), permanent.as_mut_ptr(), ); (from_glib_full(uri), from_glib(permanent.assume_init())) } } #[doc(alias = "gst_query_set_uri")] pub fn set_uri<'a, T>(&mut self, uri: impl Into>) where T: 'a + AsRef + ?Sized, { unsafe { ffi::gst_query_set_uri( self.as_mut_ptr(), uri.into().map(AsRef::as_ref).to_glib_none().0, ); } } #[doc(alias = "gst_query_set_uri_redirection")] #[doc(alias = "gst_query_set_uri_redirection_permanent")] pub fn set_redirection<'a, T>(&mut self, uri: impl Into>, permanent: bool) where T: 'a + AsRef + ?Sized, { unsafe { ffi::gst_query_set_uri_redirection( self.as_mut_ptr(), uri.into().map(AsRef::as_ref).to_glib_none().0, ); ffi::gst_query_set_uri_redirection_permanent( self.0.as_mut_ptr(), permanent.into_glib(), ); } } } impl std::fmt::Debug for Uri { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (redirection, permanent) = self.redirection(); f.debug_struct("Uri") .field("structure", &self.query().structure()) .field("uri", &self.uri()) .field("redirection", &redirection) .field("redirection-permanent", &permanent) .finish() } } impl std::fmt::Debug for Uri { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Uri::::fmt(self, f) } } declare_concrete_query!(Allocation, T); impl Allocation { #[doc(alias = "gst_query_new_allocation")] pub fn new(caps: Option<&crate::Caps>, need_pool: bool) -> Self { skip_assert_initialized!(); unsafe { Self(from_glib_full(ffi::gst_query_new_allocation( caps.map(|caps| caps.as_mut_ptr()) .unwrap_or(ptr::null_mut()), need_pool.into_glib(), ))) } } } impl Allocation { #[doc(alias = "gst_query_parse_allocation")] pub fn get(&self) -> (Option<&crate::CapsRef>, bool) { unsafe { let mut caps = ptr::null_mut(); let mut need_pool = mem::MaybeUninit::uninit(); ffi::gst_query_parse_allocation(self.as_mut_ptr(), &mut caps, need_pool.as_mut_ptr()); ( if caps.is_null() { None } else { Some(crate::CapsRef::from_ptr(caps)) }, from_glib(need_pool.assume_init()), ) } } #[doc(alias = "gst_query_parse_allocation")] pub fn get_owned(&self) -> (Option, bool) { unsafe { let (caps, need_pool) = self.get(); (caps.map(|caps| from_glib_none(caps.as_ptr())), need_pool) } } #[doc(alias = "gst_allocation_params")] #[doc(alias = "gst_query_get_n_allocation_params")] #[doc(alias = "gst_query_parse_nth_allocation_param")] pub fn allocation_params(&self) -> Vec<(Option, crate::AllocationParams)> { unsafe { let n = ffi::gst_query_get_n_allocation_params(self.as_mut_ptr()); let mut params = Vec::with_capacity(n as usize); for i in 0..n { let mut allocator = ptr::null_mut(); let mut p = mem::MaybeUninit::uninit(); ffi::gst_query_parse_nth_allocation_param( self.as_mut_ptr(), i, &mut allocator, p.as_mut_ptr(), ); params.push((from_glib_full(allocator), from_glib(p.assume_init()))); } params } } #[doc(alias = "get_allocation_pools")] #[doc(alias = "gst_query_get_n_allocation_pools")] #[doc(alias = "gst_query_parse_nth_allocation_pool")] pub fn allocation_pools(&self) -> Vec<(Option, u32, u32, u32)> { unsafe { let n = ffi::gst_query_get_n_allocation_pools(self.as_mut_ptr()); let mut pools = Vec::with_capacity(n as usize); for i in 0..n { let mut pool = ptr::null_mut(); let mut size = mem::MaybeUninit::uninit(); let mut min_buffers = mem::MaybeUninit::uninit(); let mut max_buffers = mem::MaybeUninit::uninit(); ffi::gst_query_parse_nth_allocation_pool( self.0.as_mut_ptr(), i, &mut pool, size.as_mut_ptr(), min_buffers.as_mut_ptr(), max_buffers.as_mut_ptr(), ); pools.push(( from_glib_full(pool), size.assume_init(), min_buffers.assume_init(), max_buffers.assume_init(), )); } pools } } #[doc(alias = "get_allocation_metas")] #[doc(alias = "gst_query_get_n_allocation_metas")] #[doc(alias = "gst_query_parse_nth_allocation_meta")] pub fn allocation_metas(&self) -> Vec<(glib::Type, Option<&crate::StructureRef>)> { unsafe { let n = ffi::gst_query_get_n_allocation_metas(self.0.as_mut_ptr()); let mut metas = Vec::with_capacity(n as usize); for i in 0..n { let mut structure = ptr::null(); let api = ffi::gst_query_parse_nth_allocation_meta(self.as_mut_ptr(), i, &mut structure); metas.push(( from_glib(api), if structure.is_null() { None } else { Some(crate::StructureRef::from_glib_borrow(structure)) }, )); } metas } } #[doc(alias = "gst_query_find_allocation_meta")] pub fn find_allocation_meta(&self) -> Option { unsafe { let mut idx = mem::MaybeUninit::uninit(); if ffi::gst_query_find_allocation_meta( self.as_mut_ptr(), U::meta_api().into_glib(), idx.as_mut_ptr(), ) != glib::ffi::GFALSE { Some(idx.assume_init()) } else { None } } } #[doc(alias = "gst_query_add_allocation_pool")] pub fn add_allocation_pool( &mut self, pool: Option<&impl IsA>, size: u32, min_buffers: u32, max_buffers: u32, ) { unsafe { ffi::gst_query_add_allocation_pool( self.as_mut_ptr(), pool.to_glib_none().0 as *mut ffi::GstBufferPool, size, min_buffers, max_buffers, ); } } #[doc(alias = "gst_query_set_nth_allocation_pool")] pub fn set_nth_allocation_pool( &mut self, idx: u32, pool: Option<&impl IsA>, size: u32, min_buffers: u32, max_buffers: u32, ) { unsafe { let n = ffi::gst_query_get_n_allocation_pools(self.as_mut_ptr()); assert!(idx < n); ffi::gst_query_set_nth_allocation_pool( self.as_mut_ptr(), idx, pool.to_glib_none().0 as *mut ffi::GstBufferPool, size, min_buffers, max_buffers, ); } } #[doc(alias = "gst_query_remove_nth_allocation_pool")] pub fn remove_nth_allocation_pool(&mut self, idx: u32) { unsafe { let n = ffi::gst_query_get_n_allocation_pools(self.as_mut_ptr()); assert!(idx < n); ffi::gst_query_remove_nth_allocation_pool(self.as_mut_ptr(), idx); } } #[doc(alias = "gst_query_add_allocation_param")] pub fn add_allocation_param( &mut self, allocator: Option<&impl IsA>, params: crate::AllocationParams, ) { unsafe { ffi::gst_query_add_allocation_param( self.as_mut_ptr(), allocator.to_glib_none().0 as *mut ffi::GstAllocator, params.as_ptr(), ); } } #[doc(alias = "gst_query_set_nth_allocation_param")] pub fn set_nth_allocation_param( &mut self, idx: u32, allocator: Option<&impl IsA>, params: crate::AllocationParams, ) { unsafe { let n = ffi::gst_query_get_n_allocation_params(self.as_mut_ptr()); assert!(idx < n); ffi::gst_query_set_nth_allocation_param( self.as_mut_ptr(), idx, allocator.to_glib_none().0 as *mut ffi::GstAllocator, params.as_ptr(), ); } } #[doc(alias = "gst_query_remove_nth_allocation_param")] pub fn remove_nth_allocation_param(&mut self, idx: u32) { unsafe { let n = ffi::gst_query_get_n_allocation_params(self.as_mut_ptr()); assert!(idx < n); ffi::gst_query_remove_nth_allocation_param(self.as_mut_ptr(), idx); } } #[doc(alias = "gst_query_add_allocation_meta")] pub fn add_allocation_meta( &mut self, structure: Option<&crate::StructureRef>, ) { unsafe { ffi::gst_query_add_allocation_meta( self.as_mut_ptr(), U::meta_api().into_glib(), if let Some(structure) = structure { structure.as_ptr() } else { ptr::null() }, ); } } #[doc(alias = "gst_query_remove_nth_allocation_meta")] pub fn remove_nth_allocation_meta(&mut self, idx: u32) { unsafe { let n = ffi::gst_query_get_n_allocation_metas(self.as_mut_ptr()); assert!(idx < n); ffi::gst_query_remove_nth_allocation_meta(self.as_mut_ptr(), idx); } } } impl std::fmt::Debug for Allocation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (caps, need_pool) = self.get(); f.debug_struct("Allocation") .field("structure", &self.query().structure()) .field("caps", &caps) .field("need-pool", &need_pool) .field("allocation-params", &self.allocation_params()) .field("allocation-pools", &self.allocation_pools()) .field("allocation-metas", &self.allocation_metas()) .finish() } } impl std::fmt::Debug for Allocation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Allocation::::fmt(self, f) } } declare_concrete_query!(Scheduling, T); impl Scheduling { #[doc(alias = "gst_query_new_scheduling")] pub fn new() -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_scheduling())) } } } impl Default for Scheduling { fn default() -> Self { Self::new() } } impl Scheduling { #[doc(alias = "gst_query_has_scheduling_mode")] pub fn has_scheduling_mode(&self, mode: crate::PadMode) -> bool { unsafe { from_glib(ffi::gst_query_has_scheduling_mode( self.as_mut_ptr(), mode.into_glib(), )) } } #[doc(alias = "gst_query_has_scheduling_mode_with_flags")] pub fn has_scheduling_mode_with_flags( &self, mode: crate::PadMode, flags: crate::SchedulingFlags, ) -> bool { skip_assert_initialized!(); unsafe { from_glib(ffi::gst_query_has_scheduling_mode_with_flags( self.as_mut_ptr(), mode.into_glib(), flags.into_glib(), )) } } #[doc(alias = "get_scheduling_modes")] #[doc(alias = "gst_query_get_n_scheduling_modes")] pub fn scheduling_modes(&self) -> Vec { unsafe { let n = ffi::gst_query_get_n_scheduling_modes(self.as_mut_ptr()); let mut res = Vec::with_capacity(n as usize); for i in 0..n { res.push(from_glib(ffi::gst_query_parse_nth_scheduling_mode( self.as_mut_ptr(), i, ))); } res } } #[doc(alias = "get_result")] #[doc(alias = "gst_query_parse_scheduling")] pub fn result(&self) -> (crate::SchedulingFlags, i32, i32, i32) { unsafe { let mut flags = mem::MaybeUninit::uninit(); let mut minsize = mem::MaybeUninit::uninit(); let mut maxsize = mem::MaybeUninit::uninit(); let mut align = mem::MaybeUninit::uninit(); ffi::gst_query_parse_scheduling( self.as_mut_ptr(), flags.as_mut_ptr(), minsize.as_mut_ptr(), maxsize.as_mut_ptr(), align.as_mut_ptr(), ); ( from_glib(flags.assume_init()), minsize.assume_init(), maxsize.assume_init(), align.assume_init(), ) } } #[doc(alias = "gst_query_add_scheduling_mode")] pub fn add_scheduling_modes(&mut self, modes: &[crate::PadMode]) { unsafe { for mode in modes { ffi::gst_query_add_scheduling_mode(self.as_mut_ptr(), mode.into_glib()); } } } #[doc(alias = "gst_query_set_scheduling")] pub fn set(&mut self, flags: crate::SchedulingFlags, minsize: i32, maxsize: i32, align: i32) { unsafe { ffi::gst_query_set_scheduling( self.as_mut_ptr(), flags.into_glib(), minsize, maxsize, align, ); } } } impl std::fmt::Debug for Scheduling { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Scheduling") .field("structure", &self.query().structure()) .field("result", &self.result()) .field("scheduling-modes", &self.scheduling_modes()) .finish() } } impl std::fmt::Debug for Scheduling { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Scheduling::::fmt(self, f) } } declare_concrete_query!(AcceptCaps, T); impl AcceptCaps { #[doc(alias = "gst_query_new_accept_caps")] pub fn new(caps: &crate::Caps) -> Self { skip_assert_initialized!(); unsafe { Self(from_glib_full(ffi::gst_query_new_accept_caps( caps.as_mut_ptr(), ))) } } } impl AcceptCaps { #[doc(alias = "get_caps")] #[doc(alias = "gst_query_parse_accept_caps")] pub fn caps(&self) -> &crate::CapsRef { unsafe { let mut caps = ptr::null_mut(); ffi::gst_query_parse_accept_caps(self.as_mut_ptr(), &mut caps); crate::CapsRef::from_ptr(caps) } } #[doc(alias = "get_caps_owned")] #[doc(alias = "gst_query_parse_accept_caps")] pub fn caps_owned(&self) -> crate::Caps { unsafe { from_glib_none(self.caps().as_ptr()) } } #[doc(alias = "get_result")] #[doc(alias = "gst_query_parse_accept_caps_result")] pub fn result(&self) -> bool { unsafe { let mut accepted = mem::MaybeUninit::uninit(); ffi::gst_query_parse_accept_caps_result(self.as_mut_ptr(), accepted.as_mut_ptr()); from_glib(accepted.assume_init()) } } #[doc(alias = "gst_query_set_accept_caps_result")] pub fn set_result(&mut self, accepted: bool) { unsafe { ffi::gst_query_set_accept_caps_result(self.as_mut_ptr(), accepted.into_glib()); } } } impl std::fmt::Debug for AcceptCaps { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AcceptCaps") .field("structure", &self.query().structure()) .field("result", &self.result()) .field("caps", &self.caps()) .finish() } } impl std::fmt::Debug for AcceptCaps { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { AcceptCaps::::fmt(self, f) } } declare_concrete_query!(Caps, T); impl Caps { #[doc(alias = "gst_query_new_caps")] pub fn new(filter: Option<&crate::Caps>) -> Self { skip_assert_initialized!(); unsafe { Self(from_glib_full(ffi::gst_query_new_caps( filter.to_glib_none().0, ))) } } } impl Caps { #[doc(alias = "get_filter")] #[doc(alias = "gst_query_parse_caps")] pub fn filter(&self) -> Option<&crate::CapsRef> { unsafe { let mut caps = ptr::null_mut(); ffi::gst_query_parse_caps(self.as_mut_ptr(), &mut caps); if caps.is_null() { None } else { Some(crate::CapsRef::from_ptr(caps)) } } } #[doc(alias = "get_filter_owned")] #[doc(alias = "gst_query_parse_caps")] pub fn filter_owned(&self) -> Option { unsafe { self.filter().map(|caps| from_glib_none(caps.as_ptr())) } } #[doc(alias = "get_result")] #[doc(alias = "gst_query_parse_caps_result")] pub fn result(&self) -> Option<&crate::CapsRef> { unsafe { let mut caps = ptr::null_mut(); ffi::gst_query_parse_caps_result(self.as_mut_ptr(), &mut caps); if caps.is_null() { None } else { Some(crate::CapsRef::from_ptr(caps)) } } } #[doc(alias = "get_result_owned")] #[doc(alias = "gst_query_parse_caps_result")] pub fn result_owned(&self) -> Option { unsafe { self.result().map(|caps| from_glib_none(caps.as_ptr())) } } #[doc(alias = "gst_query_set_caps_result")] pub fn set_result<'a>(&mut self, caps: impl Into>) { unsafe { ffi::gst_query_set_caps_result( self.as_mut_ptr(), caps.into() .map(|caps| caps.as_mut_ptr()) .unwrap_or(ptr::null_mut()), ); } } } impl std::fmt::Debug for Caps { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Caps") .field("structure", &self.query().structure()) .field("result", &self.result()) .field("filter", &self.filter()) .finish() } } impl std::fmt::Debug for Caps { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Caps::::fmt(self, f) } } declare_concrete_query!(Drain, T); impl Drain { #[doc(alias = "gst_query_new_drain")] pub fn new() -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_drain())) } } } impl Default for Drain { fn default() -> Self { Self::new() } } impl std::fmt::Debug for Drain { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Drain") .field("structure", &self.query().structure()) .finish() } } impl std::fmt::Debug for Drain { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Drain::::fmt(self, f) } } declare_concrete_query!(Context, T); impl Context { #[doc(alias = "gst_query_new_context")] pub fn new(context_type: &str) -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_context( context_type.to_glib_none().0, ))) } } } impl Context { #[doc(alias = "get_context")] #[doc(alias = "gst_query_parse_context")] pub fn context(&self) -> Option<&crate::ContextRef> { unsafe { let mut context = ptr::null_mut(); ffi::gst_query_parse_context(self.as_mut_ptr(), &mut context); if context.is_null() { None } else { Some(crate::ContextRef::from_ptr(context)) } } } #[doc(alias = "get_context_owned")] #[doc(alias = "gst_query_parse_context")] pub fn context_owned(&self) -> Option { unsafe { self.context() .map(|context| from_glib_none(context.as_ptr())) } } #[doc(alias = "get_context_type")] #[doc(alias = "gst_query_parse_context_type")] pub fn context_type(&self) -> &str { unsafe { let mut context_type = ptr::null(); ffi::gst_query_parse_context_type(self.as_mut_ptr(), &mut context_type); CStr::from_ptr(context_type).to_str().unwrap() } } #[doc(alias = "gst_query_set_context")] pub fn set_context<'a>(&mut self, context: impl Into>) { unsafe { ffi::gst_query_set_context( self.as_mut_ptr(), context .into() .map(|context| context.as_mut_ptr()) .unwrap_or(ptr::null_mut()), ); } } } impl std::fmt::Debug for Context { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Context") .field("structure", &self.query().structure()) .field("context", &self.context()) .field("context-type", &self.context_type()) .finish() } } impl std::fmt::Debug for Context { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Context::::fmt(self, f) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] declare_concrete_query!(Bitrate, T); #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] impl Bitrate { #[doc(alias = "gst_query_new_bitrate")] pub fn new() -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_bitrate())) } } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] impl Default for Bitrate { fn default() -> Self { Self::new() } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] impl Bitrate { #[doc(alias = "get_bitrate")] #[doc(alias = "gst_query_parse_bitrate")] pub fn bitrate(&self) -> u32 { unsafe { let mut bitrate = mem::MaybeUninit::uninit(); ffi::gst_query_parse_bitrate(self.as_mut_ptr(), bitrate.as_mut_ptr()); bitrate.assume_init() } } #[doc(alias = "gst_query_set_bitrate")] pub fn set_bitrate(&mut self, bitrate: u32) { unsafe { ffi::gst_query_set_bitrate(self.as_mut_ptr(), bitrate); } } } #[cfg(feature = "v1_16")] impl std::fmt::Debug for Bitrate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Bitrate") .field("structure", &self.query().structure()) .field("bitrate", &self.bitrate()) .finish() } } #[cfg(feature = "v1_16")] impl std::fmt::Debug for Bitrate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Bitrate::::fmt(self, f) } } #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] declare_concrete_query!(Selectable, T); #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] impl Selectable { #[doc(alias = "gst_query_new_selectable")] pub fn new() -> Self { assert_initialized_main_thread!(); unsafe { Self(from_glib_full(ffi::gst_query_new_selectable())) } } } #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] impl Default for Selectable { fn default() -> Self { Self::new() } } #[cfg(feature = "v1_22")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))] impl Selectable { #[doc(alias = "get_selectable")] #[doc(alias = "gst_query_parse_selectable")] pub fn selectable(&self) -> bool { unsafe { let mut selectable = mem::MaybeUninit::uninit(); ffi::gst_query_parse_selectable(self.as_mut_ptr(), selectable.as_mut_ptr()); from_glib(selectable.assume_init()) } } #[doc(alias = "gst_query_set_selectable")] pub fn set_selectable(&mut self, selectable: bool) { unsafe { ffi::gst_query_set_selectable(self.as_mut_ptr(), selectable.into_glib()); } } } #[cfg(feature = "v1_22")] impl std::fmt::Debug for Selectable { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Selectable") .field("structure", &self.query().structure()) .field("selectable", &self.selectable()) .finish() } } #[cfg(feature = "v1_22")] impl std::fmt::Debug for Selectable { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Selectable::::fmt(self, f) } } declare_concrete_query!(Other, T); impl std::fmt::Debug for Other { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Other") .field("structure", &self.query().structure()) .finish() } } impl std::fmt::Debug for Other { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { Other::::fmt(self, f) } } #[cfg(test)] mod tests { use super::*; use crate::ClockTime; #[test] fn test_writability() { crate::init().unwrap(); fn check_mut(query: &mut QueryRef) { skip_assert_initialized!(); match query.view_mut() { QueryViewMut::Position(p) => { let pos = p.result(); assert_eq!(pos.try_into(), Ok(ClockTime::NONE)); p.set(Some(3 * ClockTime::SECOND)); let pos = p.result(); assert_eq!(pos.try_into(), Ok(Some(3 * ClockTime::SECOND))); } _ => panic!("Wrong concrete Query in Query"), } } fn check_ref(query: &QueryRef) { skip_assert_initialized!(); match query.view() { QueryView::Position(p) => { let pos = p.result(); assert_eq!(pos.try_into(), Ok(Some(3 * ClockTime::SECOND))); assert!(!p.as_mut_ptr().is_null()); } _ => panic!("Wrong concrete Query in Query"), } } let mut p = Position::new(crate::Format::Time); let pos = p.result(); assert_eq!(pos.try_into(), Ok(ClockTime::NONE)); p.structure_mut().set("check_mut", true); // deref assert!(!p.is_serialized()); { check_mut(&mut p); let structure = p.structure(); structure.unwrap().has_field("check_mut"); // Expected: cannot borrow `p` as mutable because it is also borrowed as immutable //check_mut(&mut p); } check_ref(&p); } #[test] fn test_into_query() { crate::init().unwrap(); let d = Duration::new(crate::Format::Time); let mut query: Query = d.into(); assert!(query.is_writable()); let query = query.make_mut(); if let QueryViewMut::Duration(d) = query.view_mut() { d.set(Some(2 * ClockTime::SECOND)); } if let QueryView::Duration(d) = query.view() { let duration = d.result(); assert_eq!(duration.try_into(), Ok(Some(2 * ClockTime::SECOND))); } } #[test] fn test_concrete_to_sys() { crate::init().unwrap(); let p = Position::new(crate::Format::Time); assert!(!p.as_mut_ptr().is_null()); } #[test] fn allocation_need_pool() { crate::init().unwrap(); let mut a = Allocation::new(Some(&crate::Caps::new_empty_simple("foo/bar")), true); let pool = crate::BufferPool::new(); a.add_allocation_pool(Some(&pool), 1024, 1, 4); } #[test] fn allocation_do_not_need_pool() { crate::init().unwrap(); let mut a = Allocation::new(Some(&crate::Caps::new_empty_simple("foo/bar")), false); a.add_allocation_pool(crate::BufferPool::NONE, 1024, 1, 4); // cannot infer type of the type parameter `T` declared on the enum `Option` //a.add_allocation_pool(None, 1024, 1, 4); // This would be possible if we moved the `crate::BufferPool` // as a generic argument instead of using current arg type: // - `pool: Option<&impl IsA>` //a.add_allocation_pool::(None, 1024, 1, 4); } #[test] fn set_uri() { crate::init().unwrap(); let mut uri_q = Uri::new(); uri_q.set_uri("https://test.org"); uri_q.set_uri(&String::from("https://test.org")); uri_q.set_uri(Some("https://test.org")); uri_q.set_uri(Some(&String::from("https://test.org"))); // FIXME: this is commented out for now due to an inconsistent // assertion in `GStreamer` which results in critical logs. /* let none: Option<&str> = None; uri_q.set_uri(none); let none: Option = None; uri_q.set_uri(none.as_ref()); uri_q.set_uri::(None); */ } } gstreamer-0.23.5/src/rank.rs000064400000000000000000000105621046102023000140000ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use crate::ffi; use glib::{prelude::*, translate::*}; use std::fmt; use std::ops; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[doc(alias = "GstRank")] pub struct Rank(i32); impl Rank { #[doc(alias = "GST_RANK_NONE")] pub const NONE: Rank = Self(ffi::GST_RANK_NONE); #[doc(alias = "GST_RANK_MARGINAL")] pub const MARGINAL: Rank = Self(ffi::GST_RANK_MARGINAL); #[doc(alias = "GST_RANK_SECONDARY")] pub const SECONDARY: Rank = Self(ffi::GST_RANK_SECONDARY); #[doc(alias = "GST_RANK_PRIMARY")] pub const PRIMARY: Rank = Self(ffi::GST_RANK_PRIMARY); } impl IntoGlib for Rank { type GlibType = i32; #[inline] fn into_glib(self) -> i32 { self.0 } } #[doc(hidden)] impl FromGlib for Rank { #[inline] unsafe fn from_glib(value: i32) -> Self { Rank(value) } } impl StaticType for Rank { #[inline] fn static_type() -> glib::Type { unsafe { from_glib(ffi::gst_rank_get_type()) } } } impl HasParamSpec for Rank { type ParamSpec = glib::ParamSpecEnum; type SetValue = Self; type BuilderFn = fn(&str, Self) -> glib::ParamSpecEnumBuilder; fn param_spec_builder() -> Self::BuilderFn { Self::ParamSpec::builder_with_default } } impl glib::value::ValueType for Rank { type Type = Self; } unsafe impl<'a> glib::value::FromValue<'a> for Rank { type Checker = glib::value::GenericValueTypeChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) } } impl ToValue for Rank { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } impl From for glib::Value { #[inline] fn from(v: Rank) -> Self { skip_assert_initialized!(); ToValue::to_value(&v) } } impl From for Rank { #[inline] fn from(v: i32) -> Self { skip_assert_initialized!(); Rank(v) } } impl From for i32 { #[inline] fn from(v: Rank) -> Self { skip_assert_initialized!(); v.0 } } impl ops::Add for Rank { type Output = Rank; #[inline] fn add(self, rhs: i32) -> Rank { Rank(self.0 + rhs) } } impl ops::Add for i32 { type Output = Rank; #[inline] fn add(self, rhs: Rank) -> Rank { Rank(self + rhs.0) } } impl ops::AddAssign for Rank { #[inline] fn add_assign(&mut self, rhs: i32) { self.0 += rhs; } } impl ops::Sub for Rank { type Output = Rank; #[inline] fn sub(self, rhs: i32) -> Rank { Rank(self.0 - rhs) } } impl ops::Sub for i32 { type Output = Rank; #[inline] fn sub(self, rhs: Rank) -> Rank { Rank(self - rhs.0) } } impl ops::SubAssign for Rank { #[inline] fn sub_assign(&mut self, rhs: i32) { self.0 -= rhs } } impl std::cmp::PartialEq for Rank { #[inline] fn eq(&self, rhs: &i32) -> bool { self.0 == *rhs } } impl std::cmp::PartialEq for i32 { #[inline] fn eq(&self, rhs: &Rank) -> bool { *self == rhs.0 } } impl fmt::Display for Rank { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let rank = self.into_glib(); let names: [&str; 4] = ["none", "marginal", "secondary", "primary"]; let ranks: [Rank; 4] = [Rank::NONE, Rank::MARGINAL, Rank::SECONDARY, Rank::PRIMARY]; let mut best_i = 0; for i in 0..4 { if rank == ranks[i].into_glib() { return f.write_str(names[i]); } if (rank - ranks[i]).into_glib().abs() < (rank - ranks[best_i]).into_glib().abs() { best_i = i; } } let diff = (rank - ranks[best_i]).into_glib(); let op_str = if diff > 0 { '+' } else { '-' }; write!(f, "{} {} {}", names[best_i], op_str, diff.abs()) } } gstreamer-0.23.5/src/registry.rs000064400000000000000000000065671046102023000147270ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use glib::translate::*; use crate::{ffi, Plugin, PluginFeature, Registry}; impl Registry { #[doc(alias = "gst_registry_update")] pub fn update() -> Result<(), glib::BoolError> { crate::auto::functions::update_registry() } #[doc(alias = "gst_registry_feature_filter")] pub fn features_filtered bool>( &self, filter: P, first: bool, ) -> glib::List { let mut filter_data: P = filter; unsafe extern "C" fn filter_func bool>( feature: *mut ffi::GstPluginFeature, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let feature = from_glib_borrow(feature); let callback = user_data as *mut P; let res = (*callback)(&feature); res.into_glib() } let filter = Some(filter_func::

as _); let super_callback0: &mut P = &mut filter_data; unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_registry_feature_filter( self.to_glib_none().0, filter, first.into_glib(), super_callback0 as *mut _ as *mut _, )) } } #[doc(alias = "gst_registry_get_feature_list")] #[doc(alias = "get_feature_list")] pub fn features(&self, type_: glib::types::Type) -> glib::List { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_registry_get_feature_list( self.to_glib_none().0, type_.into_glib(), )) } } #[doc(alias = "gst_registry_get_feature_list_by_plugin")] #[doc(alias = "get_feature_list_by_plugin")] pub fn features_by_plugin(&self, name: &str) -> glib::List { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_registry_get_feature_list_by_plugin( self.to_glib_none().0, name.to_glib_none().0, )) } } #[doc(alias = "gst_registry_get_plugin_list")] #[doc(alias = "get_plugin_list")] pub fn plugins(&self) -> glib::List { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_registry_get_plugin_list( self.to_glib_none().0, )) } } #[doc(alias = "gst_registry_plugin_filter")] pub fn plugins_filtered bool>( &self, filter: P, first: bool, ) -> glib::List { let mut filter_data: P = filter; unsafe extern "C" fn filter_func bool>( plugin: *mut ffi::GstPlugin, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let plugin = from_glib_borrow(plugin); let callback = user_data as *mut P; let res = (*callback)(&plugin); res.into_glib() } let filter = Some(filter_func::

as _); let super_callback0: &mut P = &mut filter_data; unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_registry_plugin_filter( self.to_glib_none().0, filter, first.into_glib(), super_callback0 as *mut _ as *mut _, )) } } } gstreamer-0.23.5/src/sample.rs000064400000000000000000000203751046102023000143310ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{fmt, ptr}; use glib::translate::{from_glib_full, from_glib_none, IntoGlibPtr, ToGlibPtr}; use crate::{ ffi, format::FormattedValueIntrinsic, Buffer, BufferList, BufferListRef, BufferRef, Caps, CapsRef, FormattedSegment, Segment, Structure, StructureRef, }; mini_object_wrapper!(Sample, SampleRef, ffi::GstSample, || { ffi::gst_sample_get_type() }); #[derive(Debug, Clone)] #[must_use = "The builder must be built to be used"] pub struct SampleBuilder<'a> { buffer: Option<&'a Buffer>, buffer_list: Option<&'a BufferList>, caps: Option<&'a Caps>, segment: Option<&'a Segment>, info: Option, } impl<'a> SampleBuilder<'a> { pub fn buffer(self, buffer: &'a Buffer) -> Self { Self { buffer: Some(buffer), buffer_list: None, ..self } } pub fn buffer_if_some(self, buffer: Option<&'a Buffer>) -> Self { if let Some(buffer) = buffer { self.buffer(buffer) } else { self } } pub fn buffer_list(self, buffer_list: &'a BufferList) -> Self { Self { buffer: None, buffer_list: Some(buffer_list), ..self } } pub fn buffer_list_if_some(self, buffer_list: Option<&'a BufferList>) -> Self { if let Some(buffer_list) = buffer_list { self.buffer_list(buffer_list) } else { self } } pub fn caps(self, caps: &'a Caps) -> Self { Self { caps: Some(caps), ..self } } pub fn caps_if_some(self, caps: Option<&'a Caps>) -> Self { if let Some(caps) = caps { self.caps(caps) } else { self } } pub fn segment(self, segment: &'a FormattedSegment) -> Self { Self { segment: Some(segment.upcast_ref()), ..self } } pub fn segment_if_some( self, segment: Option<&'a FormattedSegment>, ) -> Self { if let Some(segment) = segment { self.segment(segment) } else { self } } pub fn info(self, info: Structure) -> Self { Self { info: Some(info), ..self } } pub fn info_if_some(self, info: Option) -> Self { if let Some(info) = info { self.info(info) } else { self } } #[must_use = "Building the sample without using it has no effect"] pub fn build(self) -> Sample { unsafe { let info = self .info .map(|i| i.into_glib_ptr()) .unwrap_or(ptr::null_mut()); let sample: Sample = from_glib_full(ffi::gst_sample_new( self.buffer.to_glib_none().0, self.caps.to_glib_none().0, self.segment.to_glib_none().0, info, )); if let Some(buffer_list) = self.buffer_list { ffi::gst_sample_set_buffer_list( sample.to_glib_none().0, buffer_list.to_glib_none().0, ); } sample } } } impl Sample { pub fn builder<'a>() -> SampleBuilder<'a> { assert_initialized_main_thread!(); SampleBuilder { buffer: None, buffer_list: None, caps: None, segment: None, info: None, } } } impl SampleRef { #[doc(alias = "get_buffer")] #[doc(alias = "gst_sample_get_buffer")] pub fn buffer(&self) -> Option<&BufferRef> { unsafe { let ptr = ffi::gst_sample_get_buffer(self.as_mut_ptr()); if ptr.is_null() { None } else { Some(BufferRef::from_ptr(ptr)) } } } #[doc(alias = "get_buffer_owned")] pub fn buffer_owned(&self) -> Option { unsafe { self.buffer().map(|buffer| from_glib_none(buffer.as_ptr())) } } #[doc(alias = "get_buffer_list")] #[doc(alias = "gst_sample_get_buffer_list")] pub fn buffer_list(&self) -> Option<&BufferListRef> { unsafe { let ptr = ffi::gst_sample_get_buffer_list(self.as_mut_ptr()); if ptr.is_null() { None } else { Some(BufferListRef::from_ptr(ptr)) } } } #[doc(alias = "get_buffer_list_owned")] pub fn buffer_list_owned(&self) -> Option { unsafe { self.buffer_list().map(|list| from_glib_none(list.as_ptr())) } } #[doc(alias = "get_caps")] #[doc(alias = "gst_sample_get_caps")] pub fn caps(&self) -> Option<&CapsRef> { unsafe { let ptr = ffi::gst_sample_get_caps(self.as_mut_ptr()); if ptr.is_null() { None } else { Some(CapsRef::from_ptr(ptr)) } } } #[doc(alias = "get_caps_owned")] pub fn caps_owned(&self) -> Option { unsafe { self.caps().map(|caps| from_glib_none(caps.as_ptr())) } } #[doc(alias = "get_segment")] #[doc(alias = "gst_sample_get_segment")] pub fn segment(&self) -> Option<&Segment> { unsafe { let ptr = ffi::gst_sample_get_segment(self.as_mut_ptr()); if ptr.is_null() { None } else { Some(crate::Segment::from_glib_ptr_borrow(ptr)) } } } #[doc(alias = "get_info")] #[doc(alias = "gst_sample_get_info")] pub fn info(&self) -> Option<&StructureRef> { unsafe { let ptr = ffi::gst_sample_get_info(self.as_mut_ptr()); if ptr.is_null() { None } else { Some(StructureRef::from_glib_borrow(ptr)) } } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "gst_sample_set_buffer")] pub fn set_buffer(&mut self, buffer: Option<&Buffer>) { unsafe { ffi::gst_sample_set_buffer(self.as_mut_ptr(), buffer.to_glib_none().0) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "gst_sample_set_buffer_list")] pub fn set_buffer_list(&mut self, buffer_list: Option<&BufferList>) { unsafe { ffi::gst_sample_set_buffer_list(self.as_mut_ptr(), buffer_list.to_glib_none().0) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "gst_sample_set_caps")] pub fn set_caps(&mut self, caps: Option<&Caps>) { unsafe { ffi::gst_sample_set_caps(self.as_mut_ptr(), caps.to_glib_none().0) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "gst_sample_set_segment")] pub fn set_segment(&mut self, segment: Option<&Segment>) { unsafe { ffi::gst_sample_set_segment(self.as_mut_ptr(), segment.to_glib_none().0) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "gst_sample_set_info")] pub fn set_info(&mut self, info: Option) { unsafe { ffi::gst_sample_set_info( self.as_mut_ptr(), info.map(|i| i.into_glib_ptr()).unwrap_or(ptr::null_mut()), ); } } } impl fmt::Debug for Sample { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { SampleRef::fmt(self, f) } } impl fmt::Debug for SampleRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Sample") .field("buffer", &self.buffer()) .field("caps", &self.caps()) .field("segment", &self.segment()) .field("info", &self.info()) .finish() } } #[cfg(test)] mod tests { #[test] fn test_sample_new_with_info() { use crate::{Sample, Structure}; crate::init().unwrap(); let info = Structure::builder("sample.info") .field("f3", 123i32) .build(); let sample = Sample::builder().info(info).build(); assert!(sample.info().is_some()); } } gstreamer-0.23.5/src/sample_serde.rs000064400000000000000000000304741046102023000155140ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use serde::{ de::{Deserialize, Deserializer}, ser::{Serialize, SerializeStruct, Serializer}, }; use crate::{Buffer, BufferList, Caps, Sample, SampleRef, Segment, Structure}; impl Serialize for SampleRef { fn serialize(&self, serializer: S) -> Result { let mut sample = serializer.serialize_struct("Sample", 5)?; sample.serialize_field("buffer", &self.buffer())?; sample.serialize_field("buffer_list", &self.buffer_list())?; sample.serialize_field("caps", &self.caps())?; sample.serialize_field("segment", &self.segment())?; sample.serialize_field("info", &self.info())?; sample.end() } } impl Serialize for Sample { fn serialize(&self, serializer: S) -> Result { self.as_ref().serialize(serializer) } } #[derive(serde::Deserialize)] struct SampleDe { buffer: Option, buffer_list: Option, caps: Option, segment: Option, info: Option, } impl From for Sample { fn from(buf_de: SampleDe) -> Self { skip_assert_initialized!(); let mut builder = Sample::builder(); if let Some(buffer) = buf_de.buffer.as_ref() { builder = builder.buffer(buffer); } if let Some(buffer_list) = buf_de.buffer_list.as_ref() { builder = builder.buffer_list(buffer_list); } if let Some(caps) = buf_de.caps.as_ref() { builder = builder.caps(caps); } if let Some(segment) = buf_de.segment.as_ref() { builder = builder.segment(segment); } if let Some(info) = buf_de.info { builder = builder.info(info); } builder.build() } } impl<'de> Deserialize<'de> for Sample { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); SampleDe::deserialize(deserializer).map(|sample_de| sample_de.into()) } } #[cfg(test)] mod tests { use crate::{ Buffer, Caps, ClockTime, Format, GenericFormattedValue, Sample, Segment, SegmentFlags, Structure, }; #[test] fn test_serialize() { crate::init().unwrap(); let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string()); let sample = { let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(Some(ClockTime::NSECOND)); buffer.set_offset(0); buffer.set_offset_end(4); buffer.set_duration(Some(4 * ClockTime::NSECOND)); } let caps = Caps::builder("sample/caps") .field("int", 12) .field("bool", true) .build(); let mut segment = Segment::new(); segment.set_flags(SegmentFlags::RESET | SegmentFlags::SEGMENT); segment.set_rate(1f64); segment.set_applied_rate(0.9f64); segment.set_format(Format::Time); segment.set_base(GenericFormattedValue::from(ClockTime::from_nseconds(123))); segment.set_offset(GenericFormattedValue::from(ClockTime::from_nseconds(42))); segment.set_start(GenericFormattedValue::from(ClockTime::from_nseconds(1024))); segment.set_stop(GenericFormattedValue::from(ClockTime::from_nseconds(2048))); segment.set_time(GenericFormattedValue::from(ClockTime::from_nseconds(1042))); segment.set_position(GenericFormattedValue::from(ClockTime::from_nseconds(256))); segment.set_duration(GenericFormattedValue::from(ClockTime::NONE)); let info = Structure::builder("sample.info") .field("f3", 123i32) .build(); Sample::builder() .buffer(&buffer) .caps(&caps) .segment(&segment) .info(info) .build() }; let res = ron::ser::to_string_pretty(&sample, pretty_config.clone()); assert_eq!( Ok(concat!( "(", " buffer: Some((", " pts: Some(1),", " dts: None,", " duration: Some(4),", " offset: 0,", " offset_end: 4,", " flags: \"\",", " buffer: \"AQIDBA==\",", " )),", " buffer_list: None,", " caps: Some(Some([", " ((\"sample/caps\", [", " (\"int\", \"i32\", 12),", " (\"bool\", \"bool\", true),", " ]), None),", " ])),", " segment: Some((", " flags: \"reset+segment\",", " rate: 1.0,", " applied_rate: 0.9,", " format: Time,", " base: 123,", " offset: 42,", " start: 1024,", " stop: 2048,", " time: 1042,", " position: 256,", " duration: -1,", " )),", " info: Some((\"sample.info\", [", " (\"f3\", \"i32\", 123),", " ])),", ")" ) .to_owned()), res ); let sample = { let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(Some(ClockTime::NSECOND)); buffer.set_offset(0); buffer.set_offset_end(4); buffer.set_duration(Some(4 * ClockTime::NSECOND)); } Sample::builder().buffer(&buffer).build() }; // `Sample`'s `Segment` is allocated in GStreamer 1.x, should be fixed in version 2.0 let res = ron::ser::to_string_pretty(&sample, pretty_config); assert_eq!( Ok(concat!( "(", " buffer: Some((", " pts: Some(1),", " dts: None,", " duration: Some(4),", " offset: 0,", " offset_end: 4,", " flags: \"\",", " buffer: \"AQIDBA==\",", " )),", " buffer_list: None,", " caps: None,", " segment: Some((", " flags: \"\",", " rate: 1.0,", " applied_rate: 1.0,", " format: Time,", " base: 0,", " offset: 0,", " start: 0,", " stop: -1,", " time: 0,", " position: 0,", " duration: -1,", " )),", " info: None,", ")" ) .to_owned()), res ); } #[test] fn test_deserialize() { crate::init().unwrap(); let buffer_ron = r#" ( buffer: Some(( pts: Some(1), dts: None, duration: Some(4), offset: 0, offset_end: 4, flags: "", buffer: "AQIDBA==", )), buffer_list: None, caps: Some(Some([ (("sample/caps", [ ("int", "i32", 12), ("bool", "bool", true), ]), None), ])), segment: Some(( flags: "", rate: 1, applied_rate: 0.9, format: Time, base: 123, offset: 42, start: 1024, stop: 2048, time: 1042, position: 256, duration: -1, )), info: Some(("sample.info", [ ("f3", "i32", 123), ])), )"#; let sample: Sample = ron::de::from_str(buffer_ron).unwrap(); let buffer = sample.buffer().unwrap(); assert_eq!(buffer.pts(), Some(ClockTime::NSECOND)); assert_eq!(buffer.offset_end(), 4); { let data = buffer.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); } assert!(sample.buffer_list().is_none()); assert!(sample.caps().is_some()); assert!(sample.segment().is_some()); assert!(sample.info().is_some()); let buffer_ron = r#" ( buffer: None, buffer_list: Some([ ( pts: Some(1), dts: None, duration: Some(4), offset: 0, offset_end: 4, flags: "", buffer: "AQIDBA==", ), ]), caps: None, segment: None, info: None, )"#; let sample: Sample = ron::de::from_str(buffer_ron).unwrap(); assert!(sample.buffer().is_none()); assert!(sample.buffer_list().is_some()); assert!(sample.caps().is_none()); // Not true in GStreamer 1.x, should be fixed in version 2.0 //assert!(sample.get_segment().is_none()); assert!(sample.info().is_none()); } #[test] fn test_roundrip() { crate::init().unwrap(); // Segment present let sample = { let mut buffer = Buffer::from_slice(vec![1, 2, 3, 4]); { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(Some(ClockTime::NSECOND)); buffer.set_offset(0); buffer.set_offset_end(4); buffer.set_duration(Some(4 * ClockTime::NSECOND)); } let caps = Caps::builder("sample/caps") .field("int", 12) .field("bool", true) .build(); let mut segment = Segment::new(); segment.set_flags(SegmentFlags::RESET | SegmentFlags::SEGMENT); segment.set_rate(1f64); segment.set_applied_rate(0.9f64); segment.set_format(Format::Time); segment.set_base(GenericFormattedValue::from(ClockTime::from_nseconds(123))); segment.set_offset(GenericFormattedValue::from(ClockTime::from_nseconds(42))); segment.set_start(GenericFormattedValue::from(ClockTime::from_nseconds(1024))); segment.set_stop(GenericFormattedValue::from(ClockTime::from_nseconds(2048))); segment.set_time(GenericFormattedValue::from(ClockTime::from_nseconds(1042))); segment.set_position(GenericFormattedValue::from(ClockTime::from_nseconds(256))); segment.set_duration(GenericFormattedValue::from(ClockTime::NONE)); let info = Structure::builder("sample.info") .field("f3", 123i32) .build(); Sample::builder() .buffer(&buffer) .caps(&caps) .segment(&segment) .info(info) .build() }; let sample_ser = ron::ser::to_string(&sample).unwrap(); let sample_de: Sample = ron::de::from_str(sample_ser.as_str()).unwrap(); let buffer_de = sample_de.buffer().unwrap(); assert_eq!(buffer_de.pts(), Some(ClockTime::NSECOND)); assert_eq!(buffer_de.offset_end(), 4); { let data = buffer_de.map_readable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); } assert!(sample_de.buffer_list().is_none()); assert!(sample_de.caps().is_some()); assert!(sample_de.segment().is_some()); assert!(sample_de.info().is_some()); } } gstreamer-0.23.5/src/segment.rs000064400000000000000000000542431046102023000145130ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use std::{fmt, marker::PhantomData, mem}; use glib::{prelude::*, translate::*}; use crate::{ ffi, format::{ CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic, FormattedValueNoneBuilder, NoneSignedBuilder, UnsignedIntoSigned, }, Format, GenericFormattedValue, SeekFlags, SeekType, }; pub type Segment = FormattedSegment; glib::wrapper! { #[doc(alias = "GstSegment")] pub struct FormattedSegment(BoxedInline); match fn { copy => |ptr| ffi::gst_segment_copy(ptr), free => |ptr| ffi::gst_segment_free(ptr), init => |_ptr| (), copy_into => |dest, src| { *dest = *src; }, clear => |_ptr| (), } } impl Segment { #[inline] pub fn reset_with_format(&mut self, format: Format) { unsafe { ffi::gst_segment_init(self.to_glib_none_mut().0, format.into_glib()); } } #[inline] pub fn set_format(&mut self, format: Format) { self.inner.format = format.into_glib(); } #[inline] pub fn downcast(self) -> Result, Self> { if T::default_format() == Format::Undefined || T::default_format() == self.format() { Ok(FormattedSegment { inner: self.inner, phantom: PhantomData, }) } else { Err(self) } } #[inline] pub fn downcast_ref(&self) -> Option<&FormattedSegment> { if T::default_format() == Format::Undefined || T::default_format() == self.format() { Some(unsafe { &*(self as *const FormattedSegment as *const FormattedSegment) }) } else { None } } #[inline] pub fn downcast_mut(&mut self) -> Option<&mut FormattedSegment> { if T::default_format() == Format::Undefined || T::default_format() == self.format() { Some(unsafe { &mut *(self as *mut FormattedSegment as *mut FormattedSegment) }) } else { None } } } impl FormattedSegment { #[inline] pub fn new() -> Self { assert_initialized_main_thread!(); let segment = unsafe { let mut segment = mem::MaybeUninit::uninit(); ffi::gst_segment_init(segment.as_mut_ptr(), T::default_format().into_glib()); segment.assume_init() }; FormattedSegment { inner: segment, phantom: PhantomData, } } #[inline] pub fn upcast(self) -> Segment { FormattedSegment { inner: self.inner, phantom: PhantomData, } } #[inline] pub fn upcast_ref(&self) -> &Segment { unsafe { &*(self as *const FormattedSegment as *const FormattedSegment) } } #[inline] pub fn reset(&mut self) { unsafe { ffi::gst_segment_init(&mut self.inner, T::default_format().into_glib()); } } #[doc(alias = "gst_segment_clip")] pub fn clip( &self, start: impl CompatibleFormattedValue, stop: impl CompatibleFormattedValue, ) -> Option<(T::FullRange, T::FullRange)> { let start = start.try_into_checked_explicit(self.format()).unwrap(); let stop = stop.try_into_checked_explicit(self.format()).unwrap(); unsafe { let mut clip_start = mem::MaybeUninit::uninit(); let mut clip_stop = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_segment_clip( &self.inner, start.format().into_glib(), start.into_raw_value() as u64, stop.into_raw_value() as u64, clip_start.as_mut_ptr(), clip_stop.as_mut_ptr(), )); if ret { Some(( T::FullRange::from_raw(self.format(), clip_start.assume_init() as i64), T::FullRange::from_raw(self.format(), clip_stop.assume_init() as i64), )) } else { None } } } #[allow(clippy::too_many_arguments)] #[doc(alias = "gst_segment_do_seek")] pub fn do_seek( &mut self, rate: f64, flags: SeekFlags, start_type: SeekType, start: impl CompatibleFormattedValue, stop_type: SeekType, stop: impl CompatibleFormattedValue, ) -> Option { let start = start.try_into_checked_explicit(self.format()).unwrap(); let stop = stop.try_into_checked_explicit(self.format()).unwrap(); unsafe { let mut update = mem::MaybeUninit::uninit(); let ret = from_glib(ffi::gst_segment_do_seek( &mut self.inner, rate, self.format().into_glib(), flags.into_glib(), start_type.into_glib(), start.into_raw_value() as u64, stop_type.into_glib(), stop.into_raw_value() as u64, update.as_mut_ptr(), )); if ret { Some(from_glib(update.assume_init())) } else { None } } } #[doc(alias = "gst_segment_offset_running_time")] #[inline] pub fn offset_running_time(&mut self, offset: i64) -> Result<(), glib::BoolError> { unsafe { glib::result_from_gboolean!( ffi::gst_segment_offset_running_time( &mut self.inner, self.format().into_glib(), offset, ), "Offset is not in the segment" ) } } #[doc(alias = "gst_segment_set_running_time")] #[inline] pub fn set_running_time( &mut self, running_time: impl CompatibleFormattedValue, ) -> Result<(), glib::BoolError> { let running_time = running_time .try_into_checked_explicit(self.format()) .unwrap(); unsafe { glib::result_from_gboolean!( ffi::gst_segment_set_running_time( &mut self.inner, self.format().into_glib(), running_time.into_raw_value() as u64, ), "Running time is not in the segment" ) } } #[doc(alias = "get_flags")] #[inline] pub fn flags(&self) -> crate::SegmentFlags { unsafe { from_glib(self.inner.flags) } } #[inline] pub fn set_flags(&mut self, flags: crate::SegmentFlags) { self.inner.flags = flags.into_glib(); } #[doc(alias = "get_rate")] #[inline] pub fn rate(&self) -> f64 { self.inner.rate } #[allow(clippy::float_cmp)] #[inline] pub fn set_rate(&mut self, rate: f64) { assert_ne!(rate, 0.0); self.inner.rate = rate; } #[doc(alias = "get_applied_rate")] #[inline] pub fn applied_rate(&self) -> f64 { self.inner.applied_rate } #[allow(clippy::float_cmp)] #[inline] pub fn set_applied_rate(&mut self, applied_rate: f64) { assert_ne!(applied_rate, 0.0); self.inner.applied_rate = applied_rate; } #[doc(alias = "get_format")] #[inline] pub fn format(&self) -> Format { unsafe { from_glib(self.inner.format) } } #[doc(alias = "get_base")] #[inline] pub fn base(&self) -> T::FullRange { unsafe { T::FullRange::from_raw(self.format(), self.inner.base as i64) } } #[inline] pub fn set_base(&mut self, base: impl CompatibleFormattedValue) { let base = base.try_into_checked_explicit(self.format()).unwrap(); self.inner.base = unsafe { base.into_raw_value() } as u64; } #[doc(alias = "get_offset")] #[inline] pub fn offset(&self) -> T::FullRange { unsafe { T::FullRange::from_raw(self.format(), self.inner.offset as i64) } } #[inline] pub fn set_offset(&mut self, offset: impl CompatibleFormattedValue) { let offset = offset.try_into_checked_explicit(self.format()).unwrap(); self.inner.offset = unsafe { offset.into_raw_value() } as u64; } #[doc(alias = "get_start")] #[inline] pub fn start(&self) -> T::FullRange { unsafe { T::FullRange::from_raw(self.format(), self.inner.start as i64) } } #[inline] pub fn set_start(&mut self, start: impl CompatibleFormattedValue) { let start = start.try_into_checked_explicit(self.format()).unwrap(); self.inner.start = unsafe { start.into_raw_value() } as u64; } #[doc(alias = "get_stop")] #[inline] pub fn stop(&self) -> T::FullRange { unsafe { T::FullRange::from_raw(self.format(), self.inner.stop as i64) } } #[inline] pub fn set_stop(&mut self, stop: impl CompatibleFormattedValue) { let stop = stop.try_into_checked_explicit(self.format()).unwrap(); self.inner.stop = unsafe { stop.into_raw_value() } as u64; } #[doc(alias = "get_time")] #[inline] pub fn time(&self) -> T::FullRange { unsafe { T::FullRange::from_raw(self.format(), self.inner.time as i64) } } #[inline] pub fn set_time(&mut self, time: impl CompatibleFormattedValue) { let time = time.try_into_checked_explicit(self.format()).unwrap(); self.inner.time = unsafe { time.into_raw_value() } as u64; } #[doc(alias = "get_position")] #[inline] pub fn position(&self) -> T::FullRange { unsafe { T::FullRange::from_raw(self.format(), self.inner.position as i64) } } #[inline] pub fn set_position(&mut self, position: impl CompatibleFormattedValue) { let position = position.try_into_checked_explicit(self.format()).unwrap(); self.inner.position = unsafe { position.into_raw_value() } as u64; } #[doc(alias = "get_duration")] #[inline] pub fn duration(&self) -> T::FullRange { unsafe { T::FullRange::from_raw(self.format(), self.inner.duration as i64) } } #[inline] pub fn set_duration(&mut self, duration: impl CompatibleFormattedValue) { let duration = duration.try_into_checked_explicit(self.format()).unwrap(); self.inner.duration = unsafe { duration.into_raw_value() } as u64; } } impl PartialEq for FormattedSegment { #[inline] #[doc(alias = "gst_segment_is_equal")] fn eq(&self, other: &Self) -> bool { unsafe { from_glib(ffi::gst_segment_is_equal(&self.inner, &other.inner)) } } } impl FormattedSegment where T: FormattedValueIntrinsic, T::FullRange: FormattedValueNoneBuilder, { #[doc(alias = "gst_segment_position_from_running_time")] pub fn position_from_running_time( &self, running_time: impl CompatibleFormattedValue, ) -> T::FullRange { let running_time = running_time .try_into_checked_explicit(self.format()) .unwrap(); if running_time.is_none() { return T::FullRange::none_for_format(self.format()); } unsafe { T::FullRange::from_raw( self.format(), ffi::gst_segment_position_from_running_time( &self.inner, self.format().into_glib(), running_time.into_raw_value() as u64, ) as i64, ) } } #[doc(alias = "gst_segment_position_from_stream_time")] pub fn position_from_stream_time( &self, stream_time: impl CompatibleFormattedValue, ) -> T::FullRange { let stream_time = stream_time .try_into_checked_explicit(self.format()) .unwrap(); if stream_time.is_none() { return T::FullRange::none_for_format(self.format()); } unsafe { T::FullRange::from_raw( self.format(), ffi::gst_segment_position_from_stream_time( &self.inner, self.format().into_glib(), stream_time.into_raw_value() as u64, ) as i64, ) } } #[doc(alias = "gst_segment_to_running_time")] pub fn to_running_time(&self, position: impl CompatibleFormattedValue) -> T::FullRange { let position = position.try_into_checked_explicit(self.format()).unwrap(); if position.is_none() { return T::FullRange::none_for_format(self.format()); } unsafe { T::FullRange::from_raw( self.format(), ffi::gst_segment_to_running_time( &self.inner, self.format().into_glib(), position.into_raw_value() as u64, ) as i64, ) } } #[doc(alias = "gst_segment_to_stream_time")] pub fn to_stream_time(&self, position: impl CompatibleFormattedValue) -> T::FullRange { let position = position.try_into_checked_explicit(self.format()).unwrap(); if position.is_none() { return T::FullRange::none_for_format(self.format()); } unsafe { T::FullRange::from_raw( self.format(), ffi::gst_segment_to_stream_time( &self.inner, self.format().into_glib(), position.into_raw_value() as u64, ) as i64, ) } } } impl FormattedSegment where T: FormattedValueIntrinsic, T::FullRange: UnsignedIntoSigned, T::FullRange: NoneSignedBuilder::Signed>, { #[doc(alias = "gst_segment_position_from_running_time_full")] pub fn position_from_running_time_full( &self, running_time: impl CompatibleFormattedValue, ) -> ::Signed { let running_time = running_time .try_into_checked_explicit(self.format()) .unwrap(); if running_time.is_none() { return T::FullRange::none_signed_for_format(self.format()); } unsafe { let mut position = mem::MaybeUninit::uninit(); let sign = ffi::gst_segment_position_from_running_time_full( &self.inner, self.format().into_glib(), running_time.into_raw_value() as u64, position.as_mut_ptr(), ); T::FullRange::from_raw(self.format(), position.assume_init() as i64).into_signed(sign) } } #[doc(alias = "gst_segment_position_from_stream_time_full")] pub fn position_from_stream_time_full( &self, stream_time: impl CompatibleFormattedValue, ) -> ::Signed { let stream_time = stream_time .try_into_checked_explicit(self.format()) .unwrap(); if stream_time.is_none() { return T::FullRange::none_signed_for_format(self.format()); } unsafe { let mut position = mem::MaybeUninit::uninit(); let sign = ffi::gst_segment_position_from_stream_time_full( &self.inner, self.format().into_glib(), stream_time.into_raw_value() as u64, position.as_mut_ptr(), ); T::FullRange::from_raw(self.format(), position.assume_init() as i64).into_signed(sign) } } #[doc(alias = "gst_segment_to_running_time_full")] pub fn to_running_time_full( &self, position: impl CompatibleFormattedValue, ) -> ::Signed { let position = position.try_into_checked_explicit(self.format()).unwrap(); if position.is_none() { return T::FullRange::none_signed_for_format(self.format()); } unsafe { let mut running_time = mem::MaybeUninit::uninit(); let sign = ffi::gst_segment_to_running_time_full( &self.inner, self.format().into_glib(), position.into_raw_value() as u64, running_time.as_mut_ptr(), ); T::FullRange::from_raw(self.format(), running_time.assume_init() as i64) .into_signed(sign) } } #[doc(alias = "gst_segment_to_stream_time_full")] pub fn to_stream_time_full( &self, position: impl CompatibleFormattedValue, ) -> ::Signed { let position = position.try_into_checked_explicit(self.format()).unwrap(); if position.is_none() { return T::FullRange::none_signed_for_format(self.format()); } unsafe { let mut stream_time = mem::MaybeUninit::uninit(); let sign = ffi::gst_segment_to_stream_time_full( &self.inner, self.format().into_glib(), position.into_raw_value() as u64, stream_time.as_mut_ptr(), ); T::FullRange::from_raw(self.format(), stream_time.assume_init() as i64) .into_signed(sign) } } } impl Eq for FormattedSegment {} unsafe impl Send for FormattedSegment {} unsafe impl Sync for FormattedSegment {} impl AsRef for FormattedSegment { #[inline] fn as_ref(&self) -> &Segment { unsafe { &*(self as *const FormattedSegment as *const FormattedSegment) } } } impl fmt::Debug for FormattedSegment { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use crate::utils::Displayable; let segment = self.as_ref(); match segment.format() { Format::Undefined => f .debug_struct("Segment") .field("format", &Format::Undefined) .finish(), Format::Time => { let segment = segment.downcast_ref::().unwrap(); f.debug_struct("Segment") .field("format", &Format::Time) .field("start", &segment.start().display()) .field("offset", &segment.offset().display()) .field("stop", &segment.stop().display()) .field("rate", &segment.rate()) .field("applied_rate", &segment.applied_rate()) .field("flags", &segment.flags()) .field("time", &segment.time().display()) .field("base", &segment.base().display()) .field("position", &segment.position().display()) .field("duration", &segment.duration().display()) .finish() } _ => f .debug_struct("Segment") .field("format", &segment.format()) .field("start", &segment.start()) .field("offset", &segment.offset()) .field("stop", &segment.stop()) .field("rate", &segment.rate()) .field("applied_rate", &segment.applied_rate()) .field("flags", &segment.flags()) .field("time", &segment.time()) .field("base", &segment.base()) .field("position", &segment.position()) .field("duration", &segment.duration()) .finish(), } } } impl Default for FormattedSegment { #[inline] fn default() -> Self { Self::new() } } impl glib::types::StaticType for FormattedSegment { #[inline] fn static_type() -> glib::types::Type { unsafe { glib::translate::from_glib(ffi::gst_segment_get_type()) } } } impl glib::value::ValueType for Segment { type Type = Self; } #[doc(hidden)] unsafe impl<'a> glib::value::FromValue<'a> for Segment { type Checker = glib::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); from_glib_none( glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut ffi::GstSegment ) } } #[doc(hidden)] unsafe impl<'a> glib::value::FromValue<'a> for &'a Segment { type Checker = glib::value::GenericValueTypeOrNoneChecker; #[inline] unsafe fn from_value(value: &'a glib::Value) -> Self { skip_assert_initialized!(); Segment::from_glib_ptr_borrow( glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const ffi::GstSegment ) } } #[doc(hidden)] impl glib::value::ToValue for FormattedSegment { #[inline] fn to_value(&self) -> glib::Value { let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, self.to_glib_none().0 as *mut _, ) } value } #[inline] fn value_type(&self) -> glib::Type { Self::static_type() } } #[doc(hidden)] impl glib::value::ToValueOptional for FormattedSegment { #[inline] fn to_value_optional(s: Option<&Self>) -> glib::Value { skip_assert_initialized!(); let mut value = glib::Value::for_value_type::(); unsafe { glib::gobject_ffi::g_value_set_boxed( value.to_glib_none_mut().0, s.to_glib_none().0 as *mut _, ) } value } } impl From> for glib::Value { #[inline] fn from(v: FormattedSegment) -> glib::Value { skip_assert_initialized!(); glib::value::ToValue::to_value(&v) } } gstreamer-0.23.5/src/segment_serde.rs000064400000000000000000000244311046102023000156710ustar 00000000000000// Take a look at the license at the top of the repository in the LICENSE file. use serde::{ de, de::{Deserialize, Deserializer}, ser::{Serialize, Serializer}, }; use crate::{ format::{FormattedValue, FormattedValueIntrinsic, SpecificFormattedValueIntrinsic}, Format, FormattedSegment, GenericFormattedValue, Segment, SegmentFlags, }; #[derive(serde::Serialize, serde::Deserialize)] struct FormattedSegmentSerde { flags: SegmentFlags, rate: f64, applied_rate: f64, format: Format, base: i64, offset: i64, start: i64, stop: i64, time: i64, position: i64, duration: i64, } impl Serialize for FormattedSegment { fn serialize(&self, serializer: S) -> Result { let fmt_seg = unsafe { FormattedSegmentSerde { flags: self.flags(), rate: self.rate(), applied_rate: self.applied_rate(), format: self.format(), base: self.base().into_raw_value(), offset: self.offset().into_raw_value(), start: self.start().into_raw_value(), stop: self.stop().into_raw_value(), time: self.time().into_raw_value(), position: self.position().into_raw_value(), duration: self.duration().into_raw_value(), } }; fmt_seg.serialize(serializer) } } impl<'de> Deserialize<'de> for Segment { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); FormattedSegmentSerde::deserialize(deserializer).map(|fmt_seg_de| { let mut segment = Self::new(); segment.set_flags(fmt_seg_de.flags); segment.set_rate(fmt_seg_de.rate); segment.set_applied_rate(fmt_seg_de.applied_rate); segment.set_format(fmt_seg_de.format); segment.set_base(GenericFormattedValue::new( fmt_seg_de.format, fmt_seg_de.base, )); segment.set_offset(GenericFormattedValue::new( fmt_seg_de.format, fmt_seg_de.offset, )); segment.set_start(GenericFormattedValue::new( fmt_seg_de.format, fmt_seg_de.start, )); segment.set_stop(GenericFormattedValue::new( fmt_seg_de.format, fmt_seg_de.stop, )); segment.set_time(GenericFormattedValue::new( fmt_seg_de.format, fmt_seg_de.time, )); segment.set_position(GenericFormattedValue::new( fmt_seg_de.format, fmt_seg_de.position, )); segment.set_duration(GenericFormattedValue::new( fmt_seg_de.format, fmt_seg_de.duration, )); segment }) } } impl<'de, T: SpecificFormattedValueIntrinsic> Deserialize<'de> for FormattedSegment { fn deserialize>(deserializer: D) -> Result { skip_assert_initialized!(); Segment::deserialize(deserializer).and_then(|segment| { segment.downcast::().map_err(|segment| { de::Error::custom(format!( "failed to convert segment with format {:?} to {:?}", segment.format(), T::default_format(), )) }) }) } } #[cfg(test)] mod tests { use crate::{ClockTime, Format, GenericFormattedValue, Segment, SegmentFlags}; #[test] fn test_serialize() { crate::init().unwrap(); let mut segment = Segment::new(); segment.set_flags(SegmentFlags::RESET | SegmentFlags::SEGMENT); segment.set_rate(1f64); segment.set_applied_rate(0.9f64); segment.set_format(Format::Time); segment.set_base(GenericFormattedValue::from(ClockTime::from_nseconds(123))); segment.set_offset(GenericFormattedValue::from(ClockTime::from_nseconds(42))); segment.set_start(GenericFormattedValue::from(ClockTime::from_nseconds(1024))); segment.set_stop(GenericFormattedValue::from(ClockTime::from_nseconds(2048))); segment.set_time(GenericFormattedValue::from(ClockTime::from_nseconds(1042))); segment.set_position(GenericFormattedValue::from(ClockTime::from_nseconds(256))); segment.set_duration(GenericFormattedValue::from(ClockTime::NONE)); let pretty_config = ron::ser::PrettyConfig::new().new_line("".to_string()); let res = ron::ser::to_string_pretty(&segment, pretty_config); assert_eq!( Ok(concat!( "(", " flags: \"reset+segment\",", " rate: 1.0,", " applied_rate: 0.9,", " format: Time,", " base: 123,", " offset: 42,", " start: 1024,", " stop: 2048,", " time: 1042,", " position: 256,", " duration: -1,", ")" ) .to_owned()), res, ); } #[test] fn test_deserialize_segment() { crate::init().unwrap(); let segment_ron = r#" ( flags: "reset+segment", rate: 1, applied_rate: 0.9, format: Time, base: 123, offset: 42, start: 1024, stop: 2048, time: 1042, position: 256, duration: -1, ) "#; let segment: Segment = ron::de::from_str(segment_ron).unwrap(); assert_eq!(segment.flags(), SegmentFlags::RESET | SegmentFlags::SEGMENT); assert!((segment.rate() - 1f64).abs() < f64::EPSILON); assert!((segment.applied_rate() - 0.9f64).abs() < f64::EPSILON); assert_eq!(segment.format(), Format::Time); assert_eq!(segment.flags(), SegmentFlags::RESET | SegmentFlags::SEGMENT); assert!((segment.rate() - 1f64).abs() < f64::EPSILON); assert!((segment.applied_rate() - 0.9f64).abs() < f64::EPSILON); assert_eq!(segment.format(), Format::Time); assert_eq!( segment.base(), GenericFormattedValue::from(ClockTime::from_nseconds(123)), ); assert_eq!( segment.offset(), GenericFormattedValue::from(ClockTime::from_nseconds(42)), ); assert_eq!( segment.start(), GenericFormattedValue::from(ClockTime::from_nseconds(1024)), ); assert_eq!( segment.stop(), GenericFormattedValue::from(ClockTime::from_nseconds(2048)), ); assert_eq!( segment.time(), GenericFormattedValue::from(ClockTime::from_nseconds(1042)), ); assert_eq!( segment.position(), GenericFormattedValue::from(ClockTime::from_nseconds(256)), ); assert_eq!( segment.duration(), GenericFormattedValue::from(ClockTime::NONE), ); } #[test] fn test_deserialize_formatted() { use crate::{format::Time, FormattedSegment}; crate::init().unwrap(); let segment_ron = r#" ( flags: "reset+segment", rate: 1, applied_rate: 0.9, format: Time, base: 123, offset: 42, start: 1024, stop: 2048, time: 1042, position: 256, duration: -1, ) "#; let fmt_seg: FormattedSegment