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<EncodingProfile> 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
This commit is contained in:
Thiago Santos 2018-10-07 21:44:17 -07:00 committed by Sebastian Dröge
parent 43235969be
commit 382138b75a
12 changed files with 549 additions and 181 deletions

View file

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

View file

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

View file

@ -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<ffi::GstDiscoverer, ffi::GstDiscovererClass>);
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<Discoverer, Error> {
assert_initialized_main_thread!();
unsafe {

View file

@ -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<ffi::GstDiscovererAudioInfo>): 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<String> {
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)

View file

@ -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<ffi::GstDiscovererContainerInfo>): 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<DiscovererStreamInfo> {
unsafe {
FromGlibPtrContainer::from_glib_full(ffi::gst_discoverer_container_info_get_streams(self.to_glib_none().0))

View file

@ -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<ffi::GstDiscovererInfo>);
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<DiscovererInfo> {
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<DiscovererStreamInfo>;
/// 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<DiscovererStreamInfo>;
///
/// # 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<gst::Structure>;
/// 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<String>;
///
/// # 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<DiscovererStreamInfo>;
///
/// # Returns
///
/// the list of
/// all streams contained in the `info`. Free after usage
/// with `DiscovererStreamInfo::list_free`.
fn get_stream_list(&self) -> Vec<DiscovererStreamInfo>;
/// 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<DiscovererStreamInfo>;
/// 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<DiscovererStreamInfo>;
///
/// # 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<gst::TagList>;
///
/// # 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<gst::Toc>;
///
/// # 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<String>;
/// 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<DiscovererStreamInfo>;
/// 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<glib::Variant>;
}

View file

@ -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<ffi::GstDiscovererStreamInfo>);
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<gst::Caps>;
///
/// # 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<gst::Structure>;
///
/// # 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<DiscovererStreamInfo>;
///
/// # 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<DiscovererStreamInfo>;
///
/// # 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<String>;
///
/// # 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<gst::TagList>;
///
/// # 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<gst::Toc>;
}

View file

@ -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<ffi::GstDiscovererSubtitleInfo>): 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<String> {
unsafe {
from_glib_none(ffi::gst_discoverer_subtitle_info_get_language(self.to_glib_none().0))

View file

@ -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<ffi::GstDiscovererVideoInfo>): 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))

View file

@ -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<gst::Caps>;
fn set_property_restriction_caps(&self, restriction_caps: Option<&gst::Caps>);
fn connect_property_restriction_caps_notify<F: Fn(&Self) + Send + Sync + 'static>(&self, f: F) -> SignalHandlerId;
fn is_equal<P: IsA<EncodingProfile>>(&self, b: &P) -> bool;
}
impl<O: IsA<EncodingProfile> + IsA<glib::object::Object>> EncodingProfileExt for O {
impl<O: IsA<EncodingProfile>> 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<O: IsA<EncodingProfile> + IsA<glib::object::Object>> EncodingProfileExt for
}
}
fn get_property_restriction_caps(&self) -> Option<gst::Caps> {
fn is_equal<P: IsA<EncodingProfile>>(&self, b: &P) -> bool {
unsafe {
let mut value = Value::from_type(<gst::Caps as StaticType>::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<F: Fn(&Self) + Send + Sync + 'static>(&self, f: F) -> SignalHandlerId {
unsafe {
let f: Box_<Box_<Fn(&Self) + Send + Sync + 'static>> = Box_::new(Box_::new(f));
connect(self.to_glib_none().0, "notify::restriction-caps",
transmute(notify_restriction_caps_trampoline::<Self> 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<P>(this: *mut ffi::GstEncodingProfile, _param_spec: glib_ffi::gpointer, f: glib_ffi::gpointer)
where P: IsA<EncodingProfile> {
let f: &&(Fn(&P) + Send + Sync + 'static) = transmute(f);
f(&EncodingProfile::from_glib_borrow(this).downcast_unchecked())
}

View file

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

View file

@ -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<Option<&'a str>>>(&self, description: P);
@ -37,11 +35,13 @@ trait EncodingProfileEdit {
fn set_restriction<'a, P: Into<Option<&'a gst::Caps>>>(&self, restriction: P);
}
impl<O: IsA<EncodingProfile> + IsA<glib::object::Object>> EncodingProfileEdit for O {
impl<O: IsA<EncodingProfile> + IsA<glib::object::Object>> 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<O: IsA<EncodingProfile> + IsA<glib::object::Object>> EncodingProfileEdit fo
}
impl EncodingAudioProfile {
fn new<'a, 'b, P: Into<Option<&'a str>>, Q: Into<Option<&'b gst::Caps>>>(format: &gst::Caps, preset: P, restriction: Q, presence: u32) -> EncodingAudioProfile {
fn new<'a, 'b, P: Into<Option<&'a str>>, Q: Into<Option<&'b gst::Caps>>>(
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<Option<&'a str>>, Q: Into<Option<&'b gst::Caps>>>(format: &gst::Caps, preset: P, restriction: Q, presence: u32) -> EncodingVideoProfile {
fn new<'a, 'b, P: Into<Option<&'a str>>, Q: Into<Option<&'b gst::Caps>>>(
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<Option<&'a str>>, Q: Into<Option<&'b str>>, R: Into<Option<&'c str>>>(name: P, description: Q, format: &gst::Caps, preset: R) -> EncodingContainerProfile {
fn new<
'a,
'b,
'c,
P: Into<Option<&'a str>>,
Q: Into<Option<&'b str>>,
R: Into<Option<&'c str>>,
>(
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<P: IsA<EncodingProfile>>(&self, profile: &P) -> Result<(), glib::error::BoolError> {
fn add_profile<P: IsA<EncodingProfile>>(
&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<T: EncodingProfileEdit>(profile: &mut T, base_data: &EncodingProfileBuilderData) {
fn set_common_fields<T: EncodingProfileBuilderCommon>(
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<T: EncodingProfileEdit>(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<EncodingProfile, EncodingProfileBuilderError> {
pub fn build(self) -> Result<EncodingAudioProfile, EncodingProfileBuilderError> {
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<EncodingProfile, EncodingProfileBuilderError> {
pub fn build(self) -> Result<EncodingVideoProfile, EncodingProfileBuilderError> {
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<EncodingProfile> 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<EncodingProfile, EncodingProfileBuilderError> {
pub fn build(self) -> Result<EncodingContainerProfile, EncodingProfileBuilderError> {
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<P: IsA<EncodingProfile>>(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);