From e218f7a93c461f2638068328fc8ab96af352e4e9 Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Thu, 3 Aug 2017 16:26:52 +0100 Subject: [PATCH] examples: appsink: improved error handling The program should now exit gracefully with human readable messages. --- examples/src/bin/appsink.rs | 106 ++++++++++++++++++++++++++++-------- 1 file changed, 83 insertions(+), 23 deletions(-) diff --git a/examples/src/bin/appsink.rs b/examples/src/bin/appsink.rs index 8bcc34805..7753fa570 100644 --- a/examples/src/bin/appsink.rs +++ b/examples/src/bin/appsink.rs @@ -3,21 +3,63 @@ use gst::*; extern crate gstreamer_app as gst_app; use gst_app::*; +extern crate glib; + +use std::fmt; use std::u64; use std::i16; use std::i32; -fn main() { - gst::init().unwrap(); +#[derive(Debug)] +enum AppSinkExError { + InitFailed(glib::Error), + ElementNotFound(&'static str), + ElementLinkFailed(&'static str, &'static str), + SetStateError(&'static str), + ElementError(std::string::String, glib::Error, std::string::String), +} +impl fmt::Display for AppSinkExError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + AppSinkExError::InitFailed(ref e) => { + write!(f, "GStreamer initialization failed: {:?}", e) + } + AppSinkExError::ElementNotFound(ref e) => write!(f, "Element {} not found", e), + AppSinkExError::ElementLinkFailed(ref e1, ref e2) => { + write!(f, "Link failed between {} and {}", e1, e2) + } + AppSinkExError::SetStateError(ref state) => { + write!(f, "Pipeline failed to switch to state {}", state) + } + AppSinkExError::ElementError(ref element, ref err, ref debug) => { + write!(f, "Error from {}: {} ({:?})", element, err, debug) + } + } + } +} + +fn create_pipeline() -> Result { + gst::init().map_err(|e| AppSinkExError::InitFailed(e))?; let pipeline = gst::Pipeline::new(None); - let src = gst::ElementFactory::make("audiotestsrc", None).unwrap(); - let sink = gst::ElementFactory::make("appsink", None).unwrap(); + let src = gst::ElementFactory::make("audiotestsrc", None) + .ok_or(AppSinkExError::ElementNotFound("audiotestsrc"))?; + let sink = gst::ElementFactory::make("appsink", None) + .ok_or(AppSinkExError::ElementNotFound("appsink"))?; - pipeline.add_many(&[&src, &sink]).unwrap(); - gst::Element::link_many(&[&src, &sink]).unwrap(); + pipeline + .add_many(&[&src, &sink]) + .expect("Unable to add elements in the pipeline"); + + gst::Element::link(&src, &sink) + .map_err(|_| { + AppSinkExError::ElementLinkFailed("audiotestsrc", "appsink") + })?; + + let appsink = sink.clone() + .dynamic_cast::() + .expect("Sink element is expected to be an appsink!"); - let appsink = sink.clone().dynamic_cast::().unwrap(); appsink.set_caps(&Caps::new_simple( "audio/x-raw", &[ @@ -40,9 +82,11 @@ fn main() { Some(sample) => sample, }; - let buffer = sample.get_buffer().unwrap(); + let buffer = sample + .get_buffer() + .expect("Unable to extract buffer from the sample"); assert_eq!(buffer.get_size() % 2, 0); - let map = buffer.map_read().unwrap(); + let map = buffer.map_read().expect("Unable to map buffer for reading"); let data = map.as_slice(); let sum: f64 = data.chunks(2) .map(|sample| { @@ -58,12 +102,19 @@ fn main() { }, )); - assert_ne!( - pipeline.set_state(gst::State::Playing), - gst::StateChangeReturn::Failure - ); + Ok(pipeline) +} - let bus = pipeline.get_bus().unwrap(); +fn main_loop() -> Result<(), AppSinkExError> { + let pipeline = create_pipeline()?; + + if let gst::StateChangeReturn::Failure = pipeline.set_state(gst::State::Playing) { + return Err(AppSinkExError::SetStateError("playing")); + } + + let bus = pipeline + .get_bus() + .expect("Pipeline without bus. Shouldn't happen!"); loop { let msg = match bus.timed_pop(u64::MAX) { @@ -74,20 +125,29 @@ fn main() { match msg.view() { MessageView::Eos(..) => break, MessageView::Error(err) => { - println!( - "Error from {}: {} ({:?})", + if let gst::StateChangeReturn::Failure = pipeline.set_state(gst::State::Null) { + return Err(AppSinkExError::SetStateError("null")); + } + return Err(AppSinkExError::ElementError( msg.get_src().get_path_string(), err.get_error(), - err.get_debug() - ); - break; + err.get_debug().unwrap(), + )); } _ => (), } } - assert_ne!( - pipeline.set_state(gst::State::Null), - gst::StateChangeReturn::Failure - ); + if let gst::StateChangeReturn::Failure = pipeline.set_state(gst::State::Null) { + return Err(AppSinkExError::SetStateError("null")); + } + + Ok(()) +} + +fn main() { + match main_loop() { + Ok(r) => r, + Err(e) => eprintln!("Error! {}", e), + } }