converted pipeilne to return snafu type
This commit is contained in:
parent
4edda4e05a
commit
dce14132ce
1 changed files with 113 additions and 59 deletions
|
@ -1,6 +1,8 @@
|
|||
use gstreamer::prelude::*;
|
||||
use gstreamer::{prelude::*, PadLinkError};
|
||||
use gstreamer::{Element, ElementFactory, Pipeline};
|
||||
use gstreamer_app::AppSink;
|
||||
use gtk::glib::BoolError;
|
||||
use snafu::prelude::*;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
|
@ -19,56 +21,56 @@ pub struct WebcamPipeline {
|
|||
}
|
||||
|
||||
impl WebcamPipeline {
|
||||
pub fn new() -> WebcamPipeline {
|
||||
pub fn new() -> Result<WebcamPipeline, PipelineError> {
|
||||
let pipeline = Pipeline::with_name("webcam_pipeline");
|
||||
|
||||
// All of the following errors are unrecoverable
|
||||
|
||||
let source = ElementFactory::make("mfvideosrc")
|
||||
.build()
|
||||
.expect("Could not build video source for GStreamer");
|
||||
.context(BuildSnafu {
|
||||
element: "mfvideosrc",
|
||||
})?;
|
||||
let convert = ElementFactory::make("videoconvert")
|
||||
.build()
|
||||
.expect("Could not build video convert for GStreamer");
|
||||
.context(BuildSnafu {
|
||||
element: "videoconvert",
|
||||
})?;
|
||||
let rate = ElementFactory::make("videorate")
|
||||
.build()
|
||||
.expect("Could not build the video rate element");
|
||||
.context(BuildSnafu {
|
||||
element: "videorate",
|
||||
})?;
|
||||
|
||||
let tee = ElementFactory::make("tee")
|
||||
.build()
|
||||
.expect("Could not create tee element");
|
||||
.context(BuildSnafu { element: "tee" })?;
|
||||
|
||||
let queue_app = ElementFactory::make("queue")
|
||||
.build()
|
||||
.expect("Could not create the queue buffer");
|
||||
let queue_app = ElementFactory::make("queue").build().context(BuildSnafu {
|
||||
element: "paintable queue",
|
||||
})?;
|
||||
let sink_paintable = ElementFactory::make("gtk4paintablesink")
|
||||
.name("gtk4_output")
|
||||
.build()
|
||||
.expect("Could not build gtk sink for GStreamer");
|
||||
.context(BuildSnafu {
|
||||
element: "gtkpaintablesink",
|
||||
})?;
|
||||
|
||||
let queue = ElementFactory::make("queue")
|
||||
.build()
|
||||
.expect("Could not create the queue buffer");
|
||||
let queue = ElementFactory::make("queue").build().context(BuildSnafu {
|
||||
element: "appsink queue",
|
||||
})?;
|
||||
|
||||
let resize = ElementFactory::make("videoscale")
|
||||
.build()
|
||||
.expect("Could not build videoscale for GStreamer");
|
||||
.context(BuildSnafu {
|
||||
element: "videoscale",
|
||||
})?;
|
||||
|
||||
let caps_string = "video/x-raw,format=RGB,width=640,height=480,max-buffers=1,drop=true";
|
||||
// let caps_string = String::from("video/x-raw,format=RGB,max-buffers=1,drop=true");
|
||||
let appsrc_caps =
|
||||
gstreamer::Caps::from_str(caps_string).expect("Couldn't create appsrc caps");
|
||||
|
||||
/*
|
||||
// let sink_frame = ElementFactory::make("appsink")
|
||||
// .name("frame_output")
|
||||
// .property("sync", &false)
|
||||
// .build()
|
||||
// .expect("Could not build appsrc for GStreamer");
|
||||
let video_info = gstreamer_video::VideoInfo::builder(gstreamer_video::VideoFormat::Rgb, 650, 480)
|
||||
.build()
|
||||
.expect("Couldn't build video info!");
|
||||
*/
|
||||
let appsrc_caps = gstreamer::Caps::from_str(caps_string).context(BuildSnafu {
|
||||
element: "appsink caps",
|
||||
})?;
|
||||
|
||||
let sink_frame = AppSink::builder()
|
||||
.name("frame_output")
|
||||
|
@ -92,49 +94,81 @@ impl WebcamPipeline {
|
|||
&queue,
|
||||
&sink_frame.upcast_ref(),
|
||||
])
|
||||
.expect("Could not link the elements to the pipeline");
|
||||
.context(LinkSnafu {
|
||||
from: "all",
|
||||
to: "pipeline",
|
||||
})?;
|
||||
|
||||
source
|
||||
.link(&convert)
|
||||
.expect("Could not link video source to converter");
|
||||
source.link(&convert).context(LinkSnafu {
|
||||
from: "mfvideosrc",
|
||||
to: "videoconvert",
|
||||
})?;
|
||||
|
||||
convert.link(&rate)
|
||||
.expect("Could not link rate to tee");
|
||||
convert.link(&rate).context(LinkSnafu {
|
||||
from: "videoconvert",
|
||||
to: "videorate",
|
||||
})?;
|
||||
|
||||
rate.link_filtered(
|
||||
&tee,
|
||||
&gstreamer::caps::Caps::from_str("video/x-raw,framerate=15/1").expect("Could not build framerate caps"),
|
||||
).expect("Could not link converter to rate");
|
||||
let tee_caps =
|
||||
gstreamer::caps::Caps::from_str("video/x-raw,framerate=15/1").context(BuildSnafu {
|
||||
element: "tee caps",
|
||||
})?;
|
||||
|
||||
rate.link_filtered(&tee, &tee_caps).context(LinkSnafu {
|
||||
from: "videorate",
|
||||
to: "tee",
|
||||
})?;
|
||||
|
||||
let tee_src_1 = tee
|
||||
.request_pad_simple("src_%u")
|
||||
.expect("Could not create src pad 1");
|
||||
let sink_paintable_sinkpad = queue_app
|
||||
.static_pad("sink")
|
||||
.expect("Could not get sink pad for paintablesink queue");
|
||||
tee_src_1
|
||||
.link(&sink_paintable_sinkpad)
|
||||
.expect("Could not link tee srcpad 1 to paintablesink pad");
|
||||
.ok_or(PipelineError::PadRequestError {
|
||||
element: "tee pad 1".to_string(),
|
||||
})?;
|
||||
let paintable_queue_sinkpad =
|
||||
queue_app
|
||||
.link(&sink_paintable)
|
||||
.expect("Could not link app queue to paintable sink");
|
||||
.static_pad("sink")
|
||||
.ok_or(PipelineError::PadRequestError {
|
||||
element: "gtk4 sink".to_string(),
|
||||
})?;
|
||||
tee_src_1
|
||||
.link(&paintable_queue_sinkpad)
|
||||
.context(PadLinkSnafu {
|
||||
from: "tee src pad",
|
||||
to: "gtk4 paintable queue",
|
||||
})?;
|
||||
queue_app.link(&sink_paintable).context(LinkSnafu {
|
||||
from: "gtk4 paintable queue",
|
||||
to: "gtk4 paintable",
|
||||
})?;
|
||||
|
||||
let tee_src_2 = tee
|
||||
.request_pad_simple("src_%u")
|
||||
.expect("Could not create src pad 2");
|
||||
let sink_frameoutput_sinkpad = queue
|
||||
.ok_or(PipelineError::PadRequestError {
|
||||
element: "tee pad 2".to_string(),
|
||||
})?;
|
||||
let appsink_queue_sinkpad =
|
||||
queue
|
||||
.static_pad("sink")
|
||||
.expect("Could not get sink pad for frameoutput sink");
|
||||
.ok_or(PipelineError::PadRequestError {
|
||||
element: "appsink queue".to_string(),
|
||||
})?;
|
||||
tee_src_2
|
||||
.link(&sink_frameoutput_sinkpad)
|
||||
.expect("Could not link tee srcpad 2 to frame output sink pad");
|
||||
.link(&appsink_queue_sinkpad)
|
||||
.context(PadLinkSnafu {
|
||||
from: "tee src pad 2",
|
||||
to: "appsink queue sinkpad",
|
||||
})?;
|
||||
|
||||
queue.link(&resize).expect("Could not link queue to resize");
|
||||
resize
|
||||
.link(&sink_frame)
|
||||
.expect("Could not bind resize to appsrc");
|
||||
queue.link(&resize).context(LinkSnafu {
|
||||
from: "appsink queue",
|
||||
to: "videoscale",
|
||||
})?;
|
||||
resize.link(&sink_frame).context(LinkSnafu {
|
||||
from: "videoscale",
|
||||
to: "appsink",
|
||||
})?;
|
||||
|
||||
WebcamPipeline {
|
||||
Ok(WebcamPipeline {
|
||||
pipeline,
|
||||
src: source,
|
||||
converter: convert,
|
||||
|
@ -144,6 +178,26 @@ impl WebcamPipeline {
|
|||
resize,
|
||||
queue,
|
||||
sink_frame: Arc::new(Mutex::new(sink_frame)),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum PipelineError {
|
||||
#[snafu(display("Error during element linking"))]
|
||||
LinkError {
|
||||
source: BoolError,
|
||||
from: String,
|
||||
to: String,
|
||||
},
|
||||
#[snafu(display("Error linking pads"))]
|
||||
PadLinkError {
|
||||
source: PadLinkError,
|
||||
from: String,
|
||||
to: String,
|
||||
},
|
||||
#[snafu(display("Error creating element"))]
|
||||
BuildError { source: BoolError, element: String },
|
||||
#[snafu(display("Error getting pad from element"))]
|
||||
PadRequestError { element: String },
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue