mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-12-23 00:26:31 +00:00
encoding_profile: add builders for all types
This commit is contained in:
parent
67bdfee1f6
commit
861f052c3d
5 changed files with 339 additions and 7 deletions
|
@ -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(())
|
||||
|
|
84
gstreamer-pbutils/src/encoding_audio_profile.rs
Normal file
84
gstreamer-pbutils/src/encoding_audio_profile.rs
Normal file
|
@ -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<EncodingAudioProfile, EncodingAudioProfileBuilderError> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
99
gstreamer-pbutils/src/encoding_container_profile.rs
Normal file
99
gstreamer-pbutils/src/encoding_container_profile.rs
Normal file
|
@ -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<EncodingContainerProfile, EncodingContainerProfileBuilderError> {
|
||||
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
|
||||
}
|
||||
|
||||
}
|
105
gstreamer-pbutils/src/encoding_video_profile.rs
Normal file
105
gstreamer-pbutils/src/encoding_video_profile.rs
Normal file
|
@ -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<EncodingVideoProfile, EncodingVideoProfileBuilderError> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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::*;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue