From 382138b75ae17365fc172930a23bbbc827d8cd8a Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Sun, 7 Oct 2018 21:44:17 -0700 Subject: [PATCH] More encoding_profile binding improvements - enable is_equal function again (unsure why it was disabled) - remove restriction-caps property, encoding-profile objects are immutable - remove cast need by using IsA in parameters and returning the correct type of encodingprofile subclass from the build() functions. It used a internal hack for storing those IsA objects in order to keep the API clean and ready to be used, this should be sorted out as soon as we figure out how to store them in the buidlers. - encodebin example: remove Result error propagation when it is caused by programming mistakes. A panic will happen in those cases. - run rustfmt --- Gir_GstPbutils.toml | 16 +- examples/src/bin/encodebin.rs | 20 +- gstreamer-pbutils/src/auto/discoverer.rs | 31 ++ .../src/auto/discoverer_audio_info.rs | 38 +++ .../src/auto/discoverer_container_info.rs | 11 + gstreamer-pbutils/src/auto/discoverer_info.rs | 138 ++++++++ .../src/auto/discoverer_stream_info.rs | 72 ++++ .../src/auto/discoverer_subtitle_info.rs | 10 + .../src/auto/discoverer_video_info.rs | 34 ++ .../src/auto/encoding_profile.rs | 42 +-- gstreamer-pbutils/src/auto/enums.rs | 1 + gstreamer-pbutils/src/encoding_profile.rs | 317 +++++++++++------- 12 files changed, 549 insertions(+), 181 deletions(-) diff --git a/Gir_GstPbutils.toml b/Gir_GstPbutils.toml index c30589af3..2d0672e72 100644 --- a/Gir_GstPbutils.toml +++ b/Gir_GstPbutils.toml @@ -145,11 +145,8 @@ trait = false [[object]] name = "GstPbutils.EncodingProfile" status = "generate" - [[object.function]] - name = "is_equal" - ignore = true - # Ignore all setters, making it imutable. A builder will be provided. + # Ignore all setters, making it immutable. A builder will be provided. [[object.function]] name = "new" ignore = true @@ -172,11 +169,16 @@ status = "generate" [object.function.return] nullable = false + [[object.property]] + name = "restriction-caps" + # encodingprofile is immutable after constructed + ignore = true + [[object]] name = "GstPbutils.EncodingContainerProfile" status = "generate" - # Make it imutable, only able to be constructed for a builder + # Make it immutable, only able to be constructed for a builder [[object.function]] name = "new" ignore = true @@ -211,7 +213,7 @@ status = "generate" name = "GstPbutils.EncodingAudioProfile" status = "generate" trait = false - # Ignore all setters, making it imutable. A builder will be provided. + # Ignore all setters, making it immutable. A builder will be provided. [[object.function]] name = "new" ignore = true @@ -223,7 +225,7 @@ trait = false name = "GstPbutils.EncodingVideoProfile" status = "generate" trait = false - # Ignore all setters, making it imutable. A builder will be provided. + # Ignore all setters, making it immutable. A builder will be provided. [[object.function]] name = "new" ignore = true diff --git a/examples/src/bin/encodebin.rs b/examples/src/bin/encodebin.rs index e106694a4..d6f71da91 100644 --- a/examples/src/bin/encodebin.rs +++ b/examples/src/bin/encodebin.rs @@ -58,11 +58,11 @@ fn configure_encodebin(encodebin: &gst::Element) -> Result<(), Error> { "video/x-matroska", &[], )) - .add_profile(&(video_profile.upcast())) - .add_profile(&(audio_profile.upcast())) + .add_profile(&(video_profile)) + .add_profile(&(audio_profile)) .build()?; - encodebin.set_property("profile", &container_profile)?; + encodebin.set_property("profile", &container_profile).expect("set profile property failed"); Ok(()) } @@ -87,12 +87,12 @@ fn example_main() -> Result<(), Error> { let encodebin = gst::ElementFactory::make("encodebin", None).ok_or(MissingElement("encodebin"))?; let sink = gst::ElementFactory::make("filesink", None).ok_or(MissingElement("filesink"))?; - src.set_property("uri", &uri)?; - sink.set_property("location", &output_file)?; + src.set_property("uri", &uri).expect("setting URI Property failed"); + sink.set_property("location", &output_file).expect("setting location property failed"); configure_encodebin(&encodebin)?; - pipeline.add_many(&[&src, &encodebin, &sink])?; + pipeline.add_many(&[&src, &encodebin, &sink]).expect("failed to add elements to pipeline"); gst::Element::link_many(&[&encodebin, &sink])?; // Need to move a new reference into the closure @@ -122,7 +122,7 @@ fn example_main() -> Result<(), Error> { } }; - let insert_sink = |is_audio, is_video| -> Result<(), Error> { + let link_to_encodebin = |is_audio, is_video| -> Result<(), Error> { if is_audio { let queue = gst::ElementFactory::make("queue", None).ok_or(MissingElement("queue"))?; @@ -132,7 +132,7 @@ fn example_main() -> Result<(), Error> { .ok_or(MissingElement("audioresample"))?; let elements = &[&queue, &convert, &resample]; - pipeline.add_many(elements)?; + pipeline.add_many(elements).expect("failed to add audio elements to pipeline"); gst::Element::link_many(elements)?; let enc_sink_pad = encodebin.get_request_pad("audio_%u").expect("Could not get audio pad from encodebin"); @@ -154,7 +154,7 @@ fn example_main() -> Result<(), Error> { .ok_or(MissingElement("videoscale"))?; let elements = &[&queue, &convert, &scale]; - pipeline.add_many(elements)?; + pipeline.add_many(elements).expect("failed to add video elements to pipeline"); gst::Element::link_many(elements)?; let enc_sink_pad = encodebin.get_request_pad("video_%u").expect("Could not get video pad from encodebin"); @@ -172,7 +172,7 @@ fn example_main() -> Result<(), Error> { Ok(()) }; - if let Err(err) = insert_sink(is_audio, is_video) { + if let Err(err) = link_to_encodebin(is_audio, is_video) { #[cfg(feature = "v1_10")] gst_element_error!( dbin, diff --git a/gstreamer-pbutils/src/auto/discoverer.rs b/gstreamer-pbutils/src/auto/discoverer.rs index 45fc0668e..1893f4c15 100644 --- a/gstreamer-pbutils/src/auto/discoverer.rs +++ b/gstreamer-pbutils/src/auto/discoverer.rs @@ -19,6 +19,26 @@ use std::mem::transmute; use std::ptr; glib_wrapper! { + /// The `Discoverer` is a utility object which allows to get as much + /// information as possible from one or many URIs. + /// + /// It provides two APIs, allowing usage in blocking or non-blocking mode. + /// + /// The blocking mode just requires calling `Discoverer::discover_uri` + /// with the URI one wishes to discover. + /// + /// The non-blocking mode requires a running `glib::MainLoop` iterating a + /// `glib::MainContext`, where one connects to the various signals, appends the + /// URIs to be processed (through `Discoverer::discover_uri_async`) and then + /// asks for the discovery to begin (through `Discoverer::start`). + /// By default this will use the GLib default main context unless you have + /// set a custom context using `glib::MainContext::push_thread_default`. + /// + /// All the information is returned in a `DiscovererInfo` structure. + /// + /// # Implements + /// + /// [`glib::object::ObjectExt`](../glib/object/trait.ObjectExt.html) pub struct Discoverer(Object); match fn { @@ -27,6 +47,17 @@ glib_wrapper! { } impl Discoverer { + /// Creates a new `Discoverer` with the provided timeout. + /// ## `timeout` + /// timeout per file, in nanoseconds. Allowed are values between + /// one second (`GST_SECOND`) and one hour (3600 * `GST_SECOND`) + /// + /// # Returns + /// + /// The new `Discoverer`. + /// If an error occurred when creating the discoverer, `err` will be set + /// accordingly and `None` will be returned. If `err` is set, the caller must + /// free it when no longer needed using `glib::Error::free`. pub fn new(timeout: gst::ClockTime) -> Result { assert_initialized_main_thread!(); unsafe { diff --git a/gstreamer-pbutils/src/auto/discoverer_audio_info.rs b/gstreamer-pbutils/src/auto/discoverer_audio_info.rs index 2407d875c..3becd718e 100644 --- a/gstreamer-pbutils/src/auto/discoverer_audio_info.rs +++ b/gstreamer-pbutils/src/auto/discoverer_audio_info.rs @@ -11,6 +11,11 @@ use std::mem; use std::ptr; glib_wrapper! { + /// `DiscovererStreamInfo` specific to audio streams. + /// + /// # Implements + /// + /// [`DiscovererStreamInfoExt`](trait.DiscovererStreamInfoExt.html), [`glib::object::ObjectExt`](../glib/object/trait.ObjectExt.html) pub struct DiscovererAudioInfo(Object): DiscovererStreamInfo; match fn { @@ -19,12 +24,25 @@ glib_wrapper! { } impl DiscovererAudioInfo { + /// + /// # Returns + /// + /// the average or nominal bitrate of the stream in bits/second. pub fn get_bitrate(&self) -> u32 { unsafe { ffi::gst_discoverer_audio_info_get_bitrate(self.to_glib_none().0) } } + /// + /// Feature: `v1_14` + /// + /// + /// # Returns + /// + /// the channel-mask of the stream, refer to + /// `gst_audio_channel_positions_from_mask` for more + /// information. #[cfg(any(feature = "v1_14", feature = "dox"))] pub fn get_channel_mask(&self) -> u64 { unsafe { @@ -32,30 +50,50 @@ impl DiscovererAudioInfo { } } + /// + /// # Returns + /// + /// the number of channels in the stream. pub fn get_channels(&self) -> u32 { unsafe { ffi::gst_discoverer_audio_info_get_channels(self.to_glib_none().0) } } + /// + /// # Returns + /// + /// the number of bits used per sample in each channel. pub fn get_depth(&self) -> u32 { unsafe { ffi::gst_discoverer_audio_info_get_depth(self.to_glib_none().0) } } + /// + /// # Returns + /// + /// the language of the stream, or NULL if unknown. pub fn get_language(&self) -> Option { unsafe { from_glib_none(ffi::gst_discoverer_audio_info_get_language(self.to_glib_none().0)) } } + /// + /// # Returns + /// + /// the maximum bitrate of the stream in bits/second. pub fn get_max_bitrate(&self) -> u32 { unsafe { ffi::gst_discoverer_audio_info_get_max_bitrate(self.to_glib_none().0) } } + /// + /// # Returns + /// + /// the sample rate of the stream in Hertz. pub fn get_sample_rate(&self) -> u32 { unsafe { ffi::gst_discoverer_audio_info_get_sample_rate(self.to_glib_none().0) diff --git a/gstreamer-pbutils/src/auto/discoverer_container_info.rs b/gstreamer-pbutils/src/auto/discoverer_container_info.rs index 53be43a63..fa6f5159f 100644 --- a/gstreamer-pbutils/src/auto/discoverer_container_info.rs +++ b/gstreamer-pbutils/src/auto/discoverer_container_info.rs @@ -11,6 +11,11 @@ use std::mem; use std::ptr; glib_wrapper! { + /// `DiscovererStreamInfo` specific to container streams. + /// + /// # Implements + /// + /// [`DiscovererStreamInfoExt`](trait.DiscovererStreamInfoExt.html), [`glib::object::ObjectExt`](../glib/object/trait.ObjectExt.html) pub struct DiscovererContainerInfo(Object): DiscovererStreamInfo; match fn { @@ -19,6 +24,12 @@ glib_wrapper! { } impl DiscovererContainerInfo { + /// + /// # Returns + /// + /// the list of + /// `DiscovererStreamInfo` this container stream offers. + /// Free with `DiscovererStreamInfo::list_free` after usage. pub fn get_streams(&self) -> Vec { unsafe { FromGlibPtrContainer::from_glib_full(ffi::gst_discoverer_container_info_get_streams(self.to_glib_none().0)) diff --git a/gstreamer-pbutils/src/auto/discoverer_info.rs b/gstreamer-pbutils/src/auto/discoverer_info.rs index d7212c24a..6a53840cd 100644 --- a/gstreamer-pbutils/src/auto/discoverer_info.rs +++ b/gstreamer-pbutils/src/auto/discoverer_info.rs @@ -16,6 +16,11 @@ use std::mem; use std::ptr; glib_wrapper! { + /// Structure containing the information of a URI analyzed by `Discoverer`. + /// + /// # Implements + /// + /// [`DiscovererInfoExt`](trait.DiscovererInfoExt.html), [`glib::object::ObjectExt`](../glib/object/trait.ObjectExt.html) pub struct DiscovererInfo(Object); match fn { @@ -24,6 +29,14 @@ glib_wrapper! { } impl DiscovererInfo { + /// Parses a `glib::Variant` as produced by `DiscovererInfoExt::to_variant` + /// back to a `DiscovererInfo`. + /// ## `variant` + /// A `glib::Variant` to deserialize into a `DiscovererInfo`. + /// + /// # Returns + /// + /// A newly-allocated `DiscovererInfo`. pub fn from_variant(variant: &glib::Variant) -> Option { assert_initialized_main_thread!(); unsafe { @@ -35,42 +48,167 @@ impl DiscovererInfo { unsafe impl Send for DiscovererInfo {} unsafe impl Sync for DiscovererInfo {} +/// Trait containing all `DiscovererInfo` methods. +/// +/// # Implementors +/// +/// [`DiscovererInfo`](struct.DiscovererInfo.html) pub trait DiscovererInfoExt { + /// + /// # Returns + /// + /// A copy of the `DiscovererInfo` fn copy(&self) -> DiscovererInfo; + /// Finds all the `DiscovererAudioInfo` contained in `self` + /// + /// # Returns + /// + /// A `glib::List` of + /// matching `DiscovererStreamInfo`. The caller should free it with + /// `DiscovererStreamInfo::list_free`. fn get_audio_streams(&self) -> Vec; + /// Finds all the `DiscovererContainerInfo` contained in `self` + /// + /// # Returns + /// + /// A `glib::List` of + /// matching `DiscovererStreamInfo`. The caller should free it with + /// `DiscovererStreamInfo::list_free`. fn get_container_streams(&self) -> Vec; + /// + /// # Returns + /// + /// the duration of the URI in `gst::ClockTime` (nanoseconds). fn get_duration(&self) -> gst::ClockTime; + /// + /// Feature: `v1_14` + /// + /// + /// # Returns + /// + /// whether the URI is live. #[cfg(any(feature = "v1_14", feature = "dox"))] fn get_live(&self) -> bool; + /// + /// # Deprecated + /// + /// This functions is deprecated since version 1.4, use + /// `DiscovererInfoExt::get_missing_elements_installer_details` + /// + /// # Returns + /// + /// Miscellaneous information stored as a `gst::Structure` + /// (for example: information about missing plugins). If you wish to use the + /// `gst::Structure` after the life-time of `self`, you will need to copy it. fn get_misc(&self) -> Option; + /// Get the installer details for missing elements + /// + /// # Returns + /// + /// An array of strings + /// containing informations about how to install the various missing elements + /// for `self` to be usable. If you wish to use the strings after the life-time + /// of `self`, you will need to copy them. fn get_missing_elements_installer_details(&self) -> Vec; + /// + /// # Returns + /// + /// the result of the discovery as a `DiscovererResult`. fn get_result(&self) -> DiscovererResult; + /// + /// # Returns + /// + /// the whether the URI is seekable. fn get_seekable(&self) -> bool; + /// + /// # Returns + /// + /// the structure (or topology) of the URI as a + /// `DiscovererStreamInfo`. + /// This structure can be traversed to see the original hierarchy. Unref with + /// `gst_discoverer_stream_info_unref` after usage. fn get_stream_info(&self) -> Option; + /// + /// # Returns + /// + /// the list of + /// all streams contained in the `info`. Free after usage + /// with `DiscovererStreamInfo::list_free`. fn get_stream_list(&self) -> Vec; + /// Finds the `DiscovererStreamInfo` contained in `self` that match the + /// given `streamtype`. + /// ## `streamtype` + /// a `glib::Type` derived from `DiscovererStreamInfo` + /// + /// # Returns + /// + /// A `glib::List` of + /// matching `DiscovererStreamInfo`. The caller should free it with + /// `DiscovererStreamInfo::list_free`. fn get_streams(&self, streamtype: glib::types::Type) -> Vec; + /// Finds all the `DiscovererSubtitleInfo` contained in `self` + /// + /// # Returns + /// + /// A `glib::List` of + /// matching `DiscovererStreamInfo`. The caller should free it with + /// `DiscovererStreamInfo::list_free`. fn get_subtitle_streams(&self) -> Vec; + /// + /// # Returns + /// + /// all tags contained in the URI. If you wish to use + /// the tags after the life-time of `self`, you will need to copy them. fn get_tags(&self) -> Option; + /// + /// # Returns + /// + /// TOC contained in the URI. If you wish to use + /// the TOC after the life-time of `self`, you will need to copy it. fn get_toc(&self) -> Option; + /// + /// # Returns + /// + /// the URI to which this information corresponds to. + /// Copy it if you wish to use it after the life-time of `self`. fn get_uri(&self) -> Option; + /// Finds all the `DiscovererVideoInfo` contained in `self` + /// + /// # Returns + /// + /// A `glib::List` of + /// matching `DiscovererStreamInfo`. The caller should free it with + /// `DiscovererStreamInfo::list_free`. fn get_video_streams(&self) -> Vec; + /// Serializes `self` to a `glib::Variant` that can be parsed again + /// through `DiscovererInfo::from_variant`. + /// + /// Note that any `gst::Toc` (s) that might have been discovered will not be serialized + /// for now. + /// ## `flags` + /// A combination of `DiscovererSerializeFlags` to specify + /// what needs to be serialized. + /// + /// # Returns + /// + /// A newly-allocated `glib::Variant` representing `self`. fn to_variant(&self, flags: DiscovererSerializeFlags) -> Option; } diff --git a/gstreamer-pbutils/src/auto/discoverer_stream_info.rs b/gstreamer-pbutils/src/auto/discoverer_stream_info.rs index fd7219f93..851a63e31 100644 --- a/gstreamer-pbutils/src/auto/discoverer_stream_info.rs +++ b/gstreamer-pbutils/src/auto/discoverer_stream_info.rs @@ -12,6 +12,25 @@ use std::mem; use std::ptr; glib_wrapper! { + /// Base structure for information concerning a media stream. Depending on the + /// stream type, one can find more media-specific information in + /// `DiscovererAudioInfo`, `DiscovererVideoInfo`, and + /// `DiscovererContainerInfo`. + /// + /// The `DiscovererStreamInfo` represents the topology of the stream. Siblings + /// can be iterated over with `DiscovererStreamInfoExt::get_next` and + /// `DiscovererStreamInfoExt::get_previous`. Children (sub-streams) of a + /// stream can be accessed using the `DiscovererContainerInfo` API. + /// + /// As a simple example, if you run `Discoverer` on an AVI file with one audio + /// and one video stream, you will get a `DiscovererContainerInfo` + /// corresponding to the AVI container, which in turn will have a + /// `DiscovererAudioInfo` sub-stream and a `DiscovererVideoInfo` sub-stream + /// for the audio and video streams respectively. + /// + /// # Implements + /// + /// [`DiscovererStreamInfoExt`](trait.DiscovererStreamInfoExt.html), [`glib::object::ObjectExt`](../glib/object/trait.ObjectExt.html) pub struct DiscovererStreamInfo(Object); match fn { @@ -22,21 +41,74 @@ glib_wrapper! { unsafe impl Send for DiscovererStreamInfo {} unsafe impl Sync for DiscovererStreamInfo {} +/// Trait containing all `DiscovererStreamInfo` methods. +/// +/// # Implementors +/// +/// [`DiscovererAudioInfo`](struct.DiscovererAudioInfo.html), [`DiscovererContainerInfo`](struct.DiscovererContainerInfo.html), [`DiscovererStreamInfo`](struct.DiscovererStreamInfo.html), [`DiscovererSubtitleInfo`](struct.DiscovererSubtitleInfo.html), [`DiscovererVideoInfo`](struct.DiscovererVideoInfo.html) pub trait DiscovererStreamInfoExt { + /// + /// # Returns + /// + /// the `gst::Caps` of the stream. Unref with + /// `gst_caps_unref` after usage. fn get_caps(&self) -> Option; + /// + /// # Deprecated + /// + /// This functions is deprecated since version 1.4, use + /// `DiscovererInfoExt::get_missing_elements_installer_details` + /// + /// # Returns + /// + /// additional information regarding the stream (for + /// example codec version, profile, etc..). If you wish to use the `gst::Structure` + /// after the life-time of `self` you will need to copy it. fn get_misc(&self) -> Option; + /// + /// # Returns + /// + /// the next `DiscovererStreamInfo` in a chain. `None` + /// for final streams. + /// Unref with `gst_discoverer_stream_info_unref` after usage. fn get_next(&self) -> Option; + /// + /// # Returns + /// + /// the previous `DiscovererStreamInfo` in a chain. + /// `None` for starting points. Unref with `gst_discoverer_stream_info_unref` + /// after usage. fn get_previous(&self) -> Option; + /// + /// # Returns + /// + /// the stream ID of this stream. If you wish to + /// use the stream ID after the life-time of `self` you will need to copy it. fn get_stream_id(&self) -> Option; + /// + /// # Returns + /// + /// a human readable name for the stream type of the given `self` (ex : "audio", + /// "container",...). fn get_stream_type_nick(&self) -> String; + /// + /// # Returns + /// + /// the tags contained in this stream. If you wish to + /// use the tags after the life-time of `self` you will need to copy them. fn get_tags(&self) -> Option; + /// + /// # Returns + /// + /// the TOC contained in this stream. If you wish to + /// use the TOC after the life-time of `self` you will need to copy it. fn get_toc(&self) -> Option; } diff --git a/gstreamer-pbutils/src/auto/discoverer_subtitle_info.rs b/gstreamer-pbutils/src/auto/discoverer_subtitle_info.rs index 53b1704fb..a4930c1c5 100644 --- a/gstreamer-pbutils/src/auto/discoverer_subtitle_info.rs +++ b/gstreamer-pbutils/src/auto/discoverer_subtitle_info.rs @@ -11,6 +11,12 @@ use std::mem; use std::ptr; glib_wrapper! { + /// `DiscovererStreamInfo` specific to subtitle streams (this includes text and + /// image based ones). + /// + /// # Implements + /// + /// [`DiscovererStreamInfoExt`](trait.DiscovererStreamInfoExt.html), [`glib::object::ObjectExt`](../glib/object/trait.ObjectExt.html) pub struct DiscovererSubtitleInfo(Object): DiscovererStreamInfo; match fn { @@ -19,6 +25,10 @@ glib_wrapper! { } impl DiscovererSubtitleInfo { + /// + /// # Returns + /// + /// the language of the stream, or NULL if unknown. pub fn get_language(&self) -> Option { unsafe { from_glib_none(ffi::gst_discoverer_subtitle_info_get_language(self.to_glib_none().0)) diff --git a/gstreamer-pbutils/src/auto/discoverer_video_info.rs b/gstreamer-pbutils/src/auto/discoverer_video_info.rs index 3de2a0dc0..26846b084 100644 --- a/gstreamer-pbutils/src/auto/discoverer_video_info.rs +++ b/gstreamer-pbutils/src/auto/discoverer_video_info.rs @@ -11,6 +11,11 @@ use std::mem; use std::ptr; glib_wrapper! { + /// `DiscovererStreamInfo` specific to video streams (this includes images). + /// + /// # Implements + /// + /// [`DiscovererStreamInfoExt`](trait.DiscovererStreamInfoExt.html), [`glib::object::ObjectExt`](../glib/object/trait.ObjectExt.html) pub struct DiscovererVideoInfo(Object): DiscovererStreamInfo; match fn { @@ -19,42 +24,71 @@ glib_wrapper! { } impl DiscovererVideoInfo { + /// + /// # Returns + /// + /// the average or nominal bitrate of the video stream in bits/second. pub fn get_bitrate(&self) -> u32 { unsafe { ffi::gst_discoverer_video_info_get_bitrate(self.to_glib_none().0) } } + /// + /// # Returns + /// + /// the depth in bits of the video stream. pub fn get_depth(&self) -> u32 { unsafe { ffi::gst_discoverer_video_info_get_depth(self.to_glib_none().0) } } + /// + /// # Returns + /// + /// the height of the video stream in pixels. pub fn get_height(&self) -> u32 { unsafe { ffi::gst_discoverer_video_info_get_height(self.to_glib_none().0) } } + /// + /// # Returns + /// + /// the maximum bitrate of the video stream in bits/second. pub fn get_max_bitrate(&self) -> u32 { unsafe { ffi::gst_discoverer_video_info_get_max_bitrate(self.to_glib_none().0) } } + /// + /// # Returns + /// + /// the width of the video stream in pixels. pub fn get_width(&self) -> u32 { unsafe { ffi::gst_discoverer_video_info_get_width(self.to_glib_none().0) } } + /// + /// # Returns + /// + /// `true` if the video stream corresponds to an image (i.e. only contains + /// one frame). pub fn is_image(&self) -> bool { unsafe { from_glib(ffi::gst_discoverer_video_info_is_image(self.to_glib_none().0)) } } + /// + /// # Returns + /// + /// `true` if the stream is interlaced, else `false`. pub fn is_interlaced(&self) -> bool { unsafe { from_glib(ffi::gst_discoverer_video_info_is_interlaced(self.to_glib_none().0)) diff --git a/gstreamer-pbutils/src/auto/encoding_profile.rs b/gstreamer-pbutils/src/auto/encoding_profile.rs index 25d0dba5a..244f0ec39 100644 --- a/gstreamer-pbutils/src/auto/encoding_profile.rs +++ b/gstreamer-pbutils/src/auto/encoding_profile.rs @@ -4,20 +4,12 @@ use DiscovererInfo; use ffi; -use glib; -use glib::StaticType; -use glib::Value; -use glib::object::Downcast; use glib::object::IsA; -use glib::signal::SignalHandlerId; -use glib::signal::connect; use glib::translate::*; use glib_ffi; use gobject_ffi; use gst; -use std::boxed::Box as Box_; use std::mem; -use std::mem::transmute; use std::ptr; glib_wrapper! { @@ -78,14 +70,10 @@ pub trait EncodingProfileExt { fn is_enabled(&self) -> bool; - fn get_property_restriction_caps(&self) -> Option; - - fn set_property_restriction_caps(&self, restriction_caps: Option<&gst::Caps>); - - fn connect_property_restriction_caps_notify(&self, f: F) -> SignalHandlerId; + fn is_equal>(&self, b: &P) -> bool; } -impl + IsA> EncodingProfileExt for O { +impl> EncodingProfileExt for O { fn copy(&self) -> EncodingProfile { unsafe { from_glib_full(ffi::gst_encoding_profile_copy(self.to_glib_none().0)) @@ -164,31 +152,9 @@ impl + IsA> EncodingProfileExt for } } - fn get_property_restriction_caps(&self) -> Option { + fn is_equal>(&self, b: &P) -> bool { unsafe { - let mut value = Value::from_type(::static_type()); - gobject_ffi::g_object_get_property(self.to_glib_none().0, "restriction-caps".to_glib_none().0, value.to_glib_none_mut().0); - value.get() - } - } - - fn set_property_restriction_caps(&self, restriction_caps: Option<&gst::Caps>) { - unsafe { - gobject_ffi::g_object_set_property(self.to_glib_none().0, "restriction-caps".to_glib_none().0, Value::from(restriction_caps).to_glib_none().0); - } - } - - fn connect_property_restriction_caps_notify(&self, f: F) -> SignalHandlerId { - unsafe { - let f: Box_> = Box_::new(Box_::new(f)); - connect(self.to_glib_none().0, "notify::restriction-caps", - transmute(notify_restriction_caps_trampoline:: as usize), Box_::into_raw(f) as *mut _) + from_glib(ffi::gst_encoding_profile_is_equal(self.to_glib_none().0, b.to_glib_none().0)) } } } - -unsafe extern "C" fn notify_restriction_caps_trampoline

(this: *mut ffi::GstEncodingProfile, _param_spec: glib_ffi::gpointer, f: glib_ffi::gpointer) -where P: IsA { - let f: &&(Fn(&P) + Send + Sync + 'static) = transmute(f); - f(&EncodingProfile::from_glib_borrow(this).downcast_unchecked()) -} diff --git a/gstreamer-pbutils/src/auto/enums.rs b/gstreamer-pbutils/src/auto/enums.rs index 37f60915c..1af9e9d3e 100644 --- a/gstreamer-pbutils/src/auto/enums.rs +++ b/gstreamer-pbutils/src/auto/enums.rs @@ -12,6 +12,7 @@ use glib::value::SetValue; use glib::value::Value; use gobject_ffi; +/// Result values for the discovery process. #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Clone, Copy)] pub enum DiscovererResult { diff --git a/gstreamer-pbutils/src/encoding_profile.rs b/gstreamer-pbutils/src/encoding_profile.rs index b0dd540f1..c88289d8e 100644 --- a/gstreamer-pbutils/src/encoding_profile.rs +++ b/gstreamer-pbutils/src/encoding_profile.rs @@ -1,23 +1,21 @@ - -use gst; -use glib; use ffi; +use glib; +use gst; use gst_ffi; use std::error; use std::fmt; -use std::collections::LinkedList; -use glib::Cast; use glib::object::IsA; use glib::translate::*; -use auto::EncodingProfile; use auto::EncodingAudioProfile; -use auto::EncodingVideoProfile; use auto::EncodingContainerProfile; +use auto::EncodingContainerProfileExt; +use auto::EncodingProfile; +use auto::EncodingVideoProfile; -trait EncodingProfileEdit { +trait EncodingProfileBuilderCommon { fn set_allow_dynamic_output(&self, allow_dynamic_output: bool); fn set_description<'a, P: Into>>(&self, description: P); @@ -37,11 +35,13 @@ trait EncodingProfileEdit { fn set_restriction<'a, P: Into>>(&self, restriction: P); } -impl + IsA> EncodingProfileEdit for O { - +impl + IsA> EncodingProfileBuilderCommon for O { fn set_allow_dynamic_output(&self, allow_dynamic_output: bool) { unsafe { - ffi::gst_encoding_profile_set_allow_dynamic_output(self.to_glib_none().0, allow_dynamic_output.to_glib()); + ffi::gst_encoding_profile_set_allow_dynamic_output( + self.to_glib_none().0, + allow_dynamic_output.to_glib(), + ); } } @@ -109,27 +109,47 @@ impl + IsA> EncodingProfileEdit fo } impl EncodingAudioProfile { - fn new<'a, 'b, P: Into>, Q: Into>>(format: &gst::Caps, preset: P, restriction: Q, presence: u32) -> EncodingAudioProfile { + fn new<'a, 'b, P: Into>, Q: Into>>( + format: &gst::Caps, + preset: P, + restriction: Q, + presence: u32, + ) -> EncodingAudioProfile { assert_initialized_main_thread!(); let preset = preset.into(); let preset = preset.to_glib_none(); let restriction = restriction.into(); let restriction = restriction.to_glib_none(); unsafe { - from_glib_full(ffi::gst_encoding_audio_profile_new(format.to_glib_none().0, preset.0, restriction.0, presence)) + from_glib_full(ffi::gst_encoding_audio_profile_new( + format.to_glib_none().0, + preset.0, + restriction.0, + presence, + )) } } } impl EncodingVideoProfile { - fn new<'a, 'b, P: Into>, Q: Into>>(format: &gst::Caps, preset: P, restriction: Q, presence: u32) -> EncodingVideoProfile { + fn new<'a, 'b, P: Into>, Q: Into>>( + format: &gst::Caps, + preset: P, + restriction: Q, + presence: u32, + ) -> EncodingVideoProfile { assert_initialized_main_thread!(); let preset = preset.into(); let preset = preset.to_glib_none(); let restriction = restriction.into(); let restriction = restriction.to_glib_none(); unsafe { - from_glib_full(ffi::gst_encoding_video_profile_new(format.to_glib_none().0, preset.0, restriction.0, presence)) + from_glib_full(ffi::gst_encoding_video_profile_new( + format.to_glib_none().0, + preset.0, + restriction.0, + presence, + )) } } @@ -141,13 +161,28 @@ impl EncodingVideoProfile { fn set_variableframerate(&self, variableframerate: bool) { unsafe { - ffi::gst_encoding_video_profile_set_variableframerate(self.to_glib_none().0, variableframerate.to_glib()); + ffi::gst_encoding_video_profile_set_variableframerate( + self.to_glib_none().0, + variableframerate.to_glib(), + ); } } } impl EncodingContainerProfile { - fn new<'a, 'b, 'c, P: Into>, Q: Into>, R: Into>>(name: P, description: Q, format: &gst::Caps, preset: R) -> EncodingContainerProfile { + fn new< + 'a, + 'b, + 'c, + P: Into>, + Q: Into>, + R: Into>, + >( + name: P, + description: Q, + format: &gst::Caps, + preset: R, + ) -> EncodingContainerProfile { assert_initialized_main_thread!(); let name = name.into(); let name = name.to_glib_none(); @@ -156,13 +191,27 @@ impl EncodingContainerProfile { let preset = preset.into(); let preset = preset.to_glib_none(); unsafe { - from_glib_full(ffi::gst_encoding_container_profile_new(name.0, description.0, format.to_glib_none().0, preset.0)) + from_glib_full(ffi::gst_encoding_container_profile_new( + name.0, + description.0, + format.to_glib_none().0, + preset.0, + )) } } - fn add_profile>(&self, profile: &P) -> Result<(), glib::error::BoolError> { + fn add_profile>( + &self, + profile: &P, + ) -> Result<(), glib::error::BoolError> { unsafe { - glib::error::BoolError::from_glib(ffi::gst_encoding_container_profile_add_profile(self.to_glib_none().0, profile.to_glib_full()), "Failed to add profile") + glib::error::BoolError::from_glib( + ffi::gst_encoding_container_profile_add_profile( + self.to_glib_none().0, + profile.to_glib_full(), + ), + "Failed to add profile", + ) } } } @@ -186,47 +235,47 @@ impl error::Error for EncodingProfileBuilderError { } } -struct EncodingProfileBuilderData<'a> { - name: Option<& 'a str>, - description: Option<& 'a str>, - format: Option<& 'a gst::Caps>, - preset: Option<& 'a str>, - preset_name: Option<& 'a str>, - restriction: Option<& 'a gst::Caps>, +struct EncodingProfileBuilderCommonData<'a> { + name: Option<&'a str>, + description: Option<&'a str>, + format: Option<&'a gst::Caps>, + preset: Option<&'a str>, + preset_name: Option<&'a str>, + restriction: Option<&'a gst::Caps>, presence: u32, allow_dynamic_output: bool, - enabled: bool + enabled: bool, } -impl<'a> EncodingProfileBuilderData<'a> { - fn new() -> EncodingProfileBuilderData<'a> { - EncodingProfileBuilderData { +impl<'a> EncodingProfileBuilderCommonData<'a> { + fn new() -> EncodingProfileBuilderCommonData<'a> { + EncodingProfileBuilderCommonData { name: None, description: None, format: None, preset: None, - preset_name : None, + preset_name: None, restriction: None, presence: 0, allow_dynamic_output: true, - enabled: true + enabled: true, } } } pub trait EncodingProfileBuilder<'a>: Sized { - fn name(self, name: & 'a str) -> Self; - fn description(self, description: & 'a str) -> Self; - fn format(self, format: & 'a gst::Caps) -> Self; - fn preset(self, preset: & 'a str) -> Self; - fn preset_name(self, preset_name: & 'a str) -> Self; - fn restriction(self, format: & 'a gst::Caps) -> Self; + fn name(self, name: &'a str) -> Self; + fn description(self, description: &'a str) -> Self; + fn format(self, format: &'a gst::Caps) -> Self; + fn preset(self, preset: &'a str) -> Self; + fn preset_name(self, preset_name: &'a str) -> Self; + fn restriction(self, format: &'a gst::Caps) -> Self; fn presence(self, presence: u32) -> Self; fn allow_dynamic_output(self, allow: bool) -> Self; fn enabled(self, enabled: bool) -> Self; } -macro_rules! declare_encoding_profile_builder( +macro_rules! declare_encoding_profile_builder_common( ($name:ident) => { impl<'a> EncodingProfileBuilder<'a> for $name<'a> { fn name(mut self, name: &'a str) -> $name<'a> { @@ -277,7 +326,10 @@ macro_rules! declare_encoding_profile_builder( } ); -fn set_common_fields(profile: &mut T, base_data: &EncodingProfileBuilderData) { +fn set_common_fields( + profile: &T, + base_data: &EncodingProfileBuilderCommonData, +) { profile.set_name(base_data.name); profile.set_description(base_data.description); profile.set_preset(base_data.preset); @@ -289,47 +341,49 @@ fn set_common_fields(profile: &mut T, base_data: &Encodi } pub struct EncodingAudioProfileBuilder<'a> { - base : EncodingProfileBuilderData<'a> + base: EncodingProfileBuilderCommonData<'a>, } -declare_encoding_profile_builder!(EncodingAudioProfileBuilder); +declare_encoding_profile_builder_common!(EncodingAudioProfileBuilder); impl<'a> EncodingAudioProfileBuilder<'a> { pub fn new() -> Self { EncodingAudioProfileBuilder { - base: EncodingProfileBuilderData::new(), + base: EncodingProfileBuilderCommonData::new(), } } - pub fn build(self) -> Result { + pub fn build(self) -> Result { if self.base.format.is_none() { return Err(EncodingProfileBuilderError); } let profile = EncodingAudioProfile::new( - self.base.format.unwrap(), self.base.preset, - self.base.restriction, self.base.presence); + self.base.format.unwrap(), + self.base.preset, + self.base.restriction, + self.base.presence, + ); - let mut profile = profile.upcast(); - set_common_fields(&mut profile, &self.base); + set_common_fields(&profile, &self.base); Ok(profile) } } pub struct EncodingVideoProfileBuilder<'a> { - base : EncodingProfileBuilderData<'a>, + base: EncodingProfileBuilderCommonData<'a>, pass: u32, variable_framerate: bool, } -declare_encoding_profile_builder!(EncodingVideoProfileBuilder); +declare_encoding_profile_builder_common!(EncodingVideoProfileBuilder); impl<'a> EncodingVideoProfileBuilder<'a> { pub fn new() -> Self { EncodingVideoProfileBuilder { - base: EncodingProfileBuilderData::new(), + base: EncodingProfileBuilderCommonData::new(), pass: 0, - variable_framerate: false + variable_framerate: false, } } @@ -343,70 +397,90 @@ impl<'a> EncodingVideoProfileBuilder<'a> { self } - pub fn build(self) -> Result { + pub fn build(self) -> Result { if self.base.format.is_none() { return Err(EncodingProfileBuilderError); } let video_profile = EncodingVideoProfile::new( - self.base.format.unwrap(), self.base.preset, self.base.restriction, self.base.presence); + self.base.format.unwrap(), + self.base.preset, + self.base.restriction, + self.base.presence, + ); video_profile.set_pass(self.pass); video_profile.set_variableframerate(self.variable_framerate); - let mut profile = video_profile.upcast(); - set_common_fields(&mut profile, &self.base); - Ok(profile) + set_common_fields(&video_profile, &self.base); + Ok(video_profile) } } pub struct EncodingContainerProfileBuilder<'a> { - base : EncodingProfileBuilderData<'a>, - profiles: LinkedList<& 'a EncodingProfile> + base: EncodingProfileBuilderCommonData<'a>, + /* + * Not proud of this. + * Couldn't figure out how to store a IsA to be used + * only when building the final profile object. So I'm using a real + * EncodingContainerProfile object just as a means to store it under + * the ffi APIs. This preserves the public APIs of this builder as + * they should be at the end. + */ + helper_profile: EncodingContainerProfile, } -declare_encoding_profile_builder!(EncodingContainerProfileBuilder); +declare_encoding_profile_builder_common!(EncodingContainerProfileBuilder); impl<'a> EncodingContainerProfileBuilder<'a> { pub fn new() -> Self { EncodingContainerProfileBuilder { - base: EncodingProfileBuilderData::new(), - profiles: LinkedList::new() + base: EncodingProfileBuilderCommonData::new(), + helper_profile: EncodingContainerProfile::new( + "helper", + None, + &gst::Caps::new_any(), + None, + ), } } - pub fn build(self) -> Result { + pub fn build(self) -> Result { if self.base.format.is_none() { return Err(EncodingProfileBuilderError); } let container_profile = EncodingContainerProfile::new( - self.base.name, self.base.description, self.base.format.unwrap(), self.base.preset); + self.base.name, + self.base.description, + self.base.format.unwrap(), + self.base.preset, + ); - for profile in self.profiles { - container_profile.add_profile(profile).or_else(|_error| Err(EncodingProfileBuilderError))?; + for profile in self.helper_profile.get_profiles() { + container_profile + .add_profile(&profile) + .or_else(|_error| Err(EncodingProfileBuilderError))?; } - let mut profile = container_profile.upcast(); - set_common_fields(&mut profile, &self.base); - Ok(profile) + set_common_fields(&container_profile, &self.base); + Ok(container_profile) } - pub fn add_profile(mut self, profile: & 'a EncodingProfile) -> Self { - self.profiles.push_back(profile); + pub fn add_profile>(mut self, profile: &P) -> Self { + self.helper_profile.add_profile(profile).unwrap(); self } - } #[cfg(test)] mod tests { use super::*; - use gst; - use auto::EncodingProfileExt; - use auto::EncodingVideoProfile; use auto::EncodingContainerProfile; use auto::EncodingContainerProfileExt; + use auto::EncodingProfileExt; + use auto::EncodingVideoProfile; + use gst; const AUDIO_PROFILE_NAME: &'static str = "audio-profile"; const AUDIO_PROFILE_DESCRIPTION: &'static str = "audio-profile-description"; @@ -430,17 +504,9 @@ mod tests { fn test_encoding_audio_profile_builder() { gst::init().unwrap(); - let caps = gst::Caps::new_simple( - "audio/x-raw", - &[], - ); + let caps = gst::Caps::new_simple("audio/x-raw", &[]); - let restriction = gst::Caps::new_simple( - "audio/x-raw", - &[ - ("format", &"S32LE"), - ], - ); + let restriction = gst::Caps::new_simple("audio/x-raw", &[("format", &"S32LE")]); let audio_profile = EncodingAudioProfileBuilder::new() .name(AUDIO_PROFILE_NAME) @@ -452,16 +518,23 @@ mod tests { .presence(PRESENCE) .allow_dynamic_output(ALLOW_DYNAMIC_OUTPUT) .enabled(ENABLED) - .build().unwrap(); + .build() + .unwrap(); assert_eq!(audio_profile.get_name().unwrap(), AUDIO_PROFILE_NAME); - assert_eq!(audio_profile.get_description().unwrap(), AUDIO_PROFILE_DESCRIPTION); + assert_eq!( + audio_profile.get_description().unwrap(), + AUDIO_PROFILE_DESCRIPTION + ); assert_eq!(audio_profile.get_format(), caps); assert_eq!(audio_profile.get_preset().unwrap(), PRESET); assert_eq!(audio_profile.get_preset_name().unwrap(), PRESET_NAME); assert_eq!(audio_profile.get_restriction().unwrap(), restriction); assert_eq!(audio_profile.get_presence(), PRESENCE); - assert_eq!(audio_profile.get_allow_dynamic_output(), ALLOW_DYNAMIC_OUTPUT); + assert_eq!( + audio_profile.get_allow_dynamic_output(), + ALLOW_DYNAMIC_OUTPUT + ); assert_eq!(audio_profile.is_enabled(), ENABLED); } @@ -469,17 +542,9 @@ mod tests { fn test_encoding_video_profile_builder() { gst::init().unwrap(); - let caps = gst::Caps::new_simple( - "video/x-raw", - &[], - ); + let caps = gst::Caps::new_simple("video/x-raw", &[]); - let restriction = gst::Caps::new_simple( - "video/x-raw", - &[ - ("format", &"RGBA"), - ], - ); + let restriction = gst::Caps::new_simple("video/x-raw", &[("format", &"RGBA")]); let video_profile = EncodingVideoProfileBuilder::new() .name(VIDEO_PROFILE_NAME) @@ -493,20 +558,28 @@ mod tests { .enabled(ENABLED) .pass(PASS) .variable_framerate(VARIABLE_FRAMERATE) - .build().unwrap(); + .build() + .unwrap(); assert_eq!(video_profile.get_name().unwrap(), VIDEO_PROFILE_NAME); - assert_eq!(video_profile.get_description().unwrap(), VIDEO_PROFILE_DESCRIPTION); + assert_eq!( + video_profile.get_description().unwrap(), + VIDEO_PROFILE_DESCRIPTION + ); assert_eq!(video_profile.get_format(), caps); assert_eq!(video_profile.get_preset().unwrap(), PRESET); assert_eq!(video_profile.get_preset_name().unwrap(), PRESET_NAME); assert_eq!(video_profile.get_restriction().unwrap(), restriction); assert_eq!(video_profile.get_presence(), PRESENCE); - assert_eq!(video_profile.get_allow_dynamic_output(), ALLOW_DYNAMIC_OUTPUT); + assert_eq!( + video_profile.get_allow_dynamic_output(), + ALLOW_DYNAMIC_OUTPUT + ); assert_eq!(video_profile.is_enabled(), ENABLED); - let video_profile: EncodingVideoProfile = - glib::object::Downcast::downcast(video_profile).ok().unwrap(); + let video_profile: EncodingVideoProfile = glib::object::Downcast::downcast(video_profile) + .ok() + .unwrap(); assert_eq!(video_profile.get_variableframerate(), VARIABLE_FRAMERATE); assert_eq!(video_profile.get_pass(), PASS); } @@ -515,35 +588,23 @@ mod tests { fn test_encoding_container_profile_builder() { gst::init().unwrap(); - let container_caps = gst::Caps::new_simple( - "container/x-caps", - &[], - ); - let restriction = gst::Caps::new_simple( - "container/x-caps", - &[ - ("field", &"somevalue") - ], - ); - let video_caps = gst::Caps::new_simple( - "video/x-raw", - &[], - ); - let audio_caps = gst::Caps::new_simple( - "audio/x-raw", - &[], - ); + let container_caps = gst::Caps::new_simple("container/x-caps", &[]); + let restriction = gst::Caps::new_simple("container/x-caps", &[("field", &"somevalue")]); + let video_caps = gst::Caps::new_simple("video/x-raw", &[]); + let audio_caps = gst::Caps::new_simple("audio/x-raw", &[]); let video_profile = EncodingVideoProfileBuilder::new() .name(VIDEO_PROFILE_NAME) .description(VIDEO_PROFILE_DESCRIPTION) .format(&video_caps) - .build().unwrap(); + .build() + .unwrap(); let audio_profile = EncodingAudioProfileBuilder::new() .name(AUDIO_PROFILE_NAME) .description(AUDIO_PROFILE_DESCRIPTION) .format(&audio_caps) - .build().unwrap(); + .build() + .unwrap(); let profile = EncodingContainerProfileBuilder::new() .name(CONTAINER_PROFILE_NAME) @@ -557,10 +618,14 @@ mod tests { .enabled(ENABLED) .add_profile(&audio_profile) .add_profile(&video_profile) - .build().unwrap(); + .build() + .unwrap(); assert_eq!(profile.get_name().unwrap(), CONTAINER_PROFILE_NAME); - assert_eq!(profile.get_description().unwrap(), CONTAINER_PROFILE_DESCRIPTION); + assert_eq!( + profile.get_description().unwrap(), + CONTAINER_PROFILE_DESCRIPTION + ); assert_eq!(profile.get_format(), container_caps); assert_eq!(profile.get_preset().unwrap(), PRESET); assert_eq!(profile.get_preset_name().unwrap(), PRESET_NAME);