diff --git a/examples/src/bin/encodebin.rs b/examples/src/bin/encodebin.rs index b2c4179cd..7c88ba828 100644 --- a/examples/src/bin/encodebin.rs +++ b/examples/src/bin/encodebin.rs @@ -2,6 +2,8 @@ extern crate gstreamer as gst; use gst::prelude::*; +extern crate gstreamer_pbutils as pbutils; + extern crate glib; use std::env; @@ -32,7 +34,36 @@ struct ErrorMessage { cause: glib::Error, } -fn configure_encodebin(encodebin: &gst::Element) { +fn configure_encodebin(encodebin: &gst::Element) -> Result<(), Error> { + let audio_profile = pbutils::EncodingAudioProfileBuilder::new() + .format(&gst::Caps::new_simple( + "audio/x-vorbis", + &[], + )) + .presence(0) + .build()?; + + let video_profile = pbutils::EncodingVideoProfileBuilder::new() + .format(&gst::Caps::new_simple( + "video/x-theora", + &[], + )) + .presence(0) + .build()?; + + let container_profile = pbutils::EncodingContainerProfileBuilder::new() + .name("container") + .format(&gst::Caps::new_simple( + "video/x-matroska", + &[], + )) + .add_profile(&(video_profile.upcast())) + .add_profile(&(audio_profile.upcast())) + .build()?; + + encodebin.set_property("profile", &container_profile)?; + + Ok(()) } fn example_main() -> Result<(), Error> { @@ -58,18 +89,18 @@ fn example_main() -> Result<(), Error> { src.set_property("uri", &uri)?; sink.set_property("location", &output_file)?; - configure_encodebin(&encodebin); + configure_encodebin(&encodebin)?; pipeline.add_many(&[&src, &encodebin, &sink])?; gst::Element::link_many(&[&encodebin, &sink])?; // Need to move a new reference into the closure let pipeline_clone = pipeline.clone(); - src.connect_pad_added(move |dbin, src_pad| { + src.connect_pad_added(move |dbin, dbin_src_pad| { let pipeline = &pipeline_clone; let (is_audio, is_video) = { - let media_type = src_pad.get_current_caps().and_then(|caps| { + let media_type = dbin_src_pad.get_current_caps().and_then(|caps| { caps.get_structure(0).map(|s| { let name = s.get_name(); (name.starts_with("audio/"), name.starts_with("video/")) @@ -81,7 +112,7 @@ fn example_main() -> Result<(), Error> { gst_element_warning!( dbin, gst::CoreError::Negotiation, - ("Failed to get media type from pad {}", src_pad.get_name()) + ("Failed to get media type from pad {}", dbin_src_pad.get_name()) ); return; @@ -112,7 +143,7 @@ fn example_main() -> Result<(), Error> { } let sink_pad = queue.get_static_pad("sink").expect("queue has no sinkpad"); - src_pad.link(&sink_pad).into_result()?; + dbin_src_pad.link(&sink_pad).into_result()?; } else if is_video { let queue = gst::ElementFactory::make("queue", None).ok_or(MissingElement("queue"))?; @@ -134,7 +165,7 @@ fn example_main() -> Result<(), Error> { } let sink_pad = queue.get_static_pad("sink").expect("queue has no sinkpad"); - src_pad.link(&sink_pad).into_result()?; + dbin_src_pad.link(&sink_pad).into_result()?; } Ok(()) diff --git a/gstreamer-pbutils/src/encoding_audio_profile.rs b/gstreamer-pbutils/src/encoding_audio_profile.rs new file mode 100644 index 000000000..d0e3e962d --- /dev/null +++ b/gstreamer-pbutils/src/encoding_audio_profile.rs @@ -0,0 +1,84 @@ + +use gst; + +use std::error; +use std::fmt; + +use auto::EncodingAudioProfile; + + +#[derive(Debug, Clone)] +pub struct EncodingAudioProfileBuilderError; + +impl fmt::Display for EncodingAudioProfileBuilderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "failed to build encoding audio profile") + } +} + +impl error::Error for EncodingAudioProfileBuilderError { + fn description(&self) -> &str { + "invalid parameters to build encoding audio profile" + } + + fn cause(&self) -> Option<&error::Error> { + None + } +} + +pub struct EncodingAudioProfileBuilder<'a> { + format: Option<& 'a gst::Caps>, + preset: Option<& 'a str>, + restriction: Option<& 'a gst::Caps>, + presence: u32 +} + +impl<'a> EncodingAudioProfileBuilder<'a> { + pub fn new() -> Self { + EncodingAudioProfileBuilder { + format: None, + preset: None, + restriction: None, + presence: 0, + } + } + + pub fn build(self) -> Result { + if self.format.is_none() { + return Err(EncodingAudioProfileBuilderError); + } + + let profile = EncodingAudioProfile::new( + self.format.unwrap(), self.preset, self.restriction, self.presence); + + Ok(profile) + } + + pub fn format(self, format: & 'a gst::Caps) -> Self { + Self { + format: Some(format), + ..self + } + } + + pub fn restriction(self, restriction: & 'a gst::Caps) -> Self { + Self { + restriction: Some(restriction), + ..self + } + } + + pub fn preset(self, preset: & 'a str) -> Self { + Self { + preset: Some(preset), + ..self + } + } + + pub fn presence(self, presence: u32) -> Self { + Self { + presence: presence, + ..self + } + } +} diff --git a/gstreamer-pbutils/src/encoding_container_profile.rs b/gstreamer-pbutils/src/encoding_container_profile.rs new file mode 100644 index 000000000..fb44d6165 --- /dev/null +++ b/gstreamer-pbutils/src/encoding_container_profile.rs @@ -0,0 +1,99 @@ + +use gst; + +use std::error; +use std::fmt; + +use auto::EncodingProfile; +use auto::EncodingContainerProfile; +use auto::EncodingContainerProfileExt; + +use std::collections::LinkedList; + +#[derive(Debug, Clone)] +pub struct EncodingContainerProfileBuilderError; + +impl fmt::Display for EncodingContainerProfileBuilderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "failed to build encoding video profile") + } +} + +impl error::Error for EncodingContainerProfileBuilderError { + fn description(&self) -> &str { + "invalid parameters to build encoding container profile" + } + + fn cause(&self) -> Option<&error::Error> { + None + } +} + +pub struct EncodingContainerProfileBuilder<'a> { + name: Option<& 'a str>, + description: Option<& 'a str>, + format: Option<& 'a gst::Caps>, + preset: Option<& 'a str>, + profiles: LinkedList<& 'a EncodingProfile> +} + +impl<'a> EncodingContainerProfileBuilder<'a> { + pub fn new() -> Self { + EncodingContainerProfileBuilder { + name: None, + description: None, + format: None, + preset: None, + profiles: LinkedList::new() + } + } + + pub fn build(self) -> Result { + if self.format.is_none() { + return Err(EncodingContainerProfileBuilderError); + } + + let container_profile = EncodingContainerProfile::new( + self.name, self.description, self.format.unwrap(), self.preset); + + for profile in self.profiles { + container_profile.add_profile(profile).or_else(|_error| Err(EncodingContainerProfileBuilderError))?; + } + + Ok(container_profile) + } + + pub fn name(self, name: & 'a str) -> Self { + Self { + name: Some(name), + ..self + } + } + + pub fn description(self, description: & 'a str) -> Self { + Self { + description: Some(description), + ..self + } + } + + pub fn format(self, format: & 'a gst::Caps) -> Self { + Self { + format: Some(format), + ..self + } + } + + pub fn preset(self, preset: & 'a str) -> Self { + Self { + preset: Some(preset), + ..self + } + } + + pub fn add_profile(mut self, profile: & 'a EncodingProfile) -> Self { + self.profiles.push_back(profile); + self + } + +} diff --git a/gstreamer-pbutils/src/encoding_video_profile.rs b/gstreamer-pbutils/src/encoding_video_profile.rs new file mode 100644 index 000000000..c6f97552e --- /dev/null +++ b/gstreamer-pbutils/src/encoding_video_profile.rs @@ -0,0 +1,105 @@ + +use gst; + +use std::error; +use std::fmt; + +use auto::EncodingVideoProfile; + + +#[derive(Debug, Clone)] +pub struct EncodingVideoProfileBuilderError; + +impl fmt::Display for EncodingVideoProfileBuilderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "failed to build encoding video profile") + } +} + +impl error::Error for EncodingVideoProfileBuilderError { + fn description(&self) -> &str { + "invalid parameters to build encoding video profile" + } + + fn cause(&self) -> Option<&error::Error> { + None + } +} + +pub struct EncodingVideoProfileBuilder<'a> { + format: Option<& 'a gst::Caps>, + preset: Option<& 'a str>, + restriction: Option<& 'a gst::Caps>, + presence: u32, + pass: u32, + variable_framerate: bool, +} + +impl<'a> EncodingVideoProfileBuilder<'a> { + pub fn new() -> Self { + EncodingVideoProfileBuilder { + format: None, + preset: None, + restriction: None, + presence: 0, + pass: 0, + variable_framerate: false, + } + } + + pub fn build(self) -> Result { + if self.format.is_none() { + return Err(EncodingVideoProfileBuilderError); + } + + let profile = EncodingVideoProfile::new( + self.format.unwrap(), self.preset, self.restriction, self.presence); + + profile.set_pass(self.pass); + profile.set_variableframerate(self.variable_framerate); + + Ok(profile) + } + + pub fn format(self, format: & 'a gst::Caps) -> Self { + Self { + format: Some(format), + ..self + } + } + + pub fn restriction(self, restriction: & 'a gst::Caps) -> Self { + Self { + restriction: Some(restriction), + ..self + } + } + + pub fn preset(self, preset: & 'a str) -> Self { + Self { + preset: Some(preset), + ..self + } + } + + pub fn presence(self, presence: u32) -> Self { + Self { + presence: presence, + ..self + } + } + + pub fn pass(self, pass: u32) -> Self { + Self { + pass: pass, + ..self + } + } + + pub fn variable_framerate(self, variable_framerate: bool) -> Self { + Self { + variable_framerate: variable_framerate, + ..self + } + } +} diff --git a/gstreamer-pbutils/src/lib.rs b/gstreamer-pbutils/src/lib.rs index 9457bf36e..28aa0a2a4 100644 --- a/gstreamer-pbutils/src/lib.rs +++ b/gstreamer-pbutils/src/lib.rs @@ -55,6 +55,15 @@ pub mod discoverer_stream_info; mod discoverer_video_info; pub use discoverer_video_info::*; +mod encoding_container_profile; +pub use encoding_container_profile::*; + +mod encoding_audio_profile; +pub use encoding_audio_profile::*; + +mod encoding_video_profile; +pub use encoding_video_profile::*; + // Re-export all the traits in a prelude module, so that applications // can always "use gst::prelude::*" without getting conflicts pub mod prelude { @@ -65,5 +74,9 @@ pub mod prelude { pub use discoverer_stream_info::*; pub use discoverer_video_info::*; + pub use encoding_container_profile::*; + pub use encoding_video_profile::*; + pub use encoding_audio_profile::*; + pub use auto::traits::*; }