converted pipeilne to return snafu type

This commit is contained in:
Nickiel12 2024-05-20 22:12:29 -06:00
parent 4edda4e05a
commit dce14132ce

View file

@ -1,6 +1,8 @@
use gstreamer::prelude::*; use gstreamer::{prelude::*, PadLinkError};
use gstreamer::{Element, ElementFactory, Pipeline}; use gstreamer::{Element, ElementFactory, Pipeline};
use gstreamer_app::AppSink; use gstreamer_app::AppSink;
use gtk::glib::BoolError;
use snafu::prelude::*;
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -19,56 +21,56 @@ pub struct WebcamPipeline {
} }
impl WebcamPipeline { impl WebcamPipeline {
pub fn new() -> WebcamPipeline { pub fn new() -> Result<WebcamPipeline, PipelineError> {
let pipeline = Pipeline::with_name("webcam_pipeline"); let pipeline = Pipeline::with_name("webcam_pipeline");
// All of the following errors are unrecoverable // All of the following errors are unrecoverable
let source = ElementFactory::make("mfvideosrc") let source = ElementFactory::make("mfvideosrc")
.build() .build()
.expect("Could not build video source for GStreamer"); .context(BuildSnafu {
element: "mfvideosrc",
})?;
let convert = ElementFactory::make("videoconvert") let convert = ElementFactory::make("videoconvert")
.build() .build()
.expect("Could not build video convert for GStreamer"); .context(BuildSnafu {
element: "videoconvert",
})?;
let rate = ElementFactory::make("videorate") let rate = ElementFactory::make("videorate")
.build() .build()
.expect("Could not build the video rate element"); .context(BuildSnafu {
element: "videorate",
})?;
let tee = ElementFactory::make("tee") let tee = ElementFactory::make("tee")
.build() .build()
.expect("Could not create tee element"); .context(BuildSnafu { element: "tee" })?;
let queue_app = ElementFactory::make("queue") let queue_app = ElementFactory::make("queue").build().context(BuildSnafu {
.build() element: "paintable queue",
.expect("Could not create the queue buffer"); })?;
let sink_paintable = ElementFactory::make("gtk4paintablesink") let sink_paintable = ElementFactory::make("gtk4paintablesink")
.name("gtk4_output") .name("gtk4_output")
.build() .build()
.expect("Could not build gtk sink for GStreamer"); .context(BuildSnafu {
element: "gtkpaintablesink",
})?;
let queue = ElementFactory::make("queue") let queue = ElementFactory::make("queue").build().context(BuildSnafu {
.build() element: "appsink queue",
.expect("Could not create the queue buffer"); })?;
let resize = ElementFactory::make("videoscale") let resize = ElementFactory::make("videoscale")
.build() .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 = "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 caps_string = String::from("video/x-raw,format=RGB,max-buffers=1,drop=true");
let appsrc_caps = let appsrc_caps = gstreamer::Caps::from_str(caps_string).context(BuildSnafu {
gstreamer::Caps::from_str(caps_string).expect("Couldn't create appsrc caps"); element: "appsink 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 sink_frame = AppSink::builder() let sink_frame = AppSink::builder()
.name("frame_output") .name("frame_output")
@ -92,49 +94,81 @@ impl WebcamPipeline {
&queue, &queue,
&sink_frame.upcast_ref(), &sink_frame.upcast_ref(),
]) ])
.expect("Could not link the elements to the pipeline"); .context(LinkSnafu {
from: "all",
to: "pipeline",
})?;
source source.link(&convert).context(LinkSnafu {
.link(&convert) from: "mfvideosrc",
.expect("Could not link video source to converter"); to: "videoconvert",
})?;
convert.link(&rate) convert.link(&rate).context(LinkSnafu {
.expect("Could not link rate to tee"); from: "videoconvert",
to: "videorate",
})?;
rate.link_filtered( let tee_caps =
&tee, gstreamer::caps::Caps::from_str("video/x-raw,framerate=15/1").context(BuildSnafu {
&gstreamer::caps::Caps::from_str("video/x-raw,framerate=15/1").expect("Could not build framerate caps"), element: "tee caps",
).expect("Could not link converter to rate"); })?;
rate.link_filtered(&tee, &tee_caps).context(LinkSnafu {
from: "videorate",
to: "tee",
})?;
let tee_src_1 = tee let tee_src_1 = tee
.request_pad_simple("src_%u") .request_pad_simple("src_%u")
.expect("Could not create src pad 1"); .ok_or(PipelineError::PadRequestError {
let sink_paintable_sinkpad = queue_app element: "tee pad 1".to_string(),
.static_pad("sink") })?;
.expect("Could not get sink pad for paintablesink queue"); let paintable_queue_sinkpad =
tee_src_1
.link(&sink_paintable_sinkpad)
.expect("Could not link tee srcpad 1 to paintablesink pad");
queue_app queue_app
.link(&sink_paintable) .static_pad("sink")
.expect("Could not link app queue to paintable 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 let tee_src_2 = tee
.request_pad_simple("src_%u") .request_pad_simple("src_%u")
.expect("Could not create src pad 2"); .ok_or(PipelineError::PadRequestError {
let sink_frameoutput_sinkpad = queue element: "tee pad 2".to_string(),
})?;
let appsink_queue_sinkpad =
queue
.static_pad("sink") .static_pad("sink")
.expect("Could not get sink pad for frameoutput sink"); .ok_or(PipelineError::PadRequestError {
element: "appsink queue".to_string(),
})?;
tee_src_2 tee_src_2
.link(&sink_frameoutput_sinkpad) .link(&appsink_queue_sinkpad)
.expect("Could not link tee srcpad 2 to frame output sink pad"); .context(PadLinkSnafu {
from: "tee src pad 2",
to: "appsink queue sinkpad",
})?;
queue.link(&resize).expect("Could not link queue to resize"); queue.link(&resize).context(LinkSnafu {
resize from: "appsink queue",
.link(&sink_frame) to: "videoscale",
.expect("Could not bind resize to appsrc"); })?;
resize.link(&sink_frame).context(LinkSnafu {
from: "videoscale",
to: "appsink",
})?;
WebcamPipeline { Ok(WebcamPipeline {
pipeline, pipeline,
src: source, src: source,
converter: convert, converter: convert,
@ -144,6 +178,26 @@ impl WebcamPipeline {
resize, resize,
queue, queue,
sink_frame: Arc::new(Mutex::new(sink_frame)), 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 },
}