use gstreamer::prelude::*; use gstreamer::{Element, ElementFactory, Pipeline}; use gstreamer_app::AppSink; use std::str::FromStr; use std::sync::{Arc, Mutex}; pub struct WebcamPipeline { pub pipeline: Pipeline, pub src: Element, pub converter: Element, pub tee: Element, pub queue_app: Element, pub sink_paintable: Element, pub queue: Element, pub resize: Element, pub sink_frame: Arc>, } impl WebcamPipeline { pub fn new() -> WebcamPipeline { 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"); let convert = ElementFactory::make("videoconvert") .build() .expect("Could not build video convert for GStreamer"); let tee = ElementFactory::make("tee") .build() .expect("Could not create tee element"); let queue_app = ElementFactory::make("queue") .build() .expect("Could not create the queue buffer"); let sink_paintable = ElementFactory::make("gtk4paintablesink") .name("gtk4_output") .build() .expect("Could not build gtk sink for GStreamer"); let queue = ElementFactory::make("queue") .build() .expect("Could not create the queue buffer"); let resize = ElementFactory::make("videoscale") .build() .expect("Could not build videoscale for GStreamer"); let caps_string = String::from("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 sink_frame = AppSink::builder() .name("frame_output") .sync(false) .max_buffers(1u32) .drop(true) .caps(&appsrc_caps) .build(); sink_frame.set_property("caps", &appsrc_caps.to_value()); pipeline .add_many(&[ &source, &convert, &tee, &queue_app, &sink_paintable, &resize, &queue, &sink_frame.upcast_ref(), ]) .expect("Could not link the elements to the pipeline"); source .link(&convert) .expect("Could not link video source to converter"); convert.link(&tee).expect("Could not link converter 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"); queue_app .link(&sink_paintable) .expect("Could not link app queue to paintable sink"); let tee_src_2 = tee .request_pad_simple("src_%u") .expect("Could not create src pad 2"); let sink_frameoutput_sinkpad = queue .static_pad("sink") .expect("Could not get sink pad for frameoutput sink"); tee_src_2 .link(&sink_frameoutput_sinkpad) .expect("Could not link tee srcpad 2 to frame output sink pad"); queue.link(&resize).expect("Could not link queue to resize"); resize .link(&sink_frame) .expect("Could not bind resize to appsrc"); WebcamPipeline { pipeline, src: source, converter: convert, tee, queue_app, sink_paintable, resize, queue, sink_frame: Arc::new(Mutex::new(sink_frame)), } } }