From 951f00062293a422ebcb3e5366435e40a4b1613f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 24 Oct 2022 16:51:54 +0300 Subject: [PATCH] examples: glupload: Set sync point on the GL buffer as soon as possible And also add API for getting the GL context from a `GLBaseMemory`. --- examples/src/glupload.rs | 85 ++++++++++++------------------ gstreamer-gl/src/gl_base_memory.rs | 7 +++ 2 files changed, 41 insertions(+), 51 deletions(-) diff --git a/examples/src/glupload.rs b/examples/src/glupload.rs index 812ab62e4..0a4d7a61e 100644 --- a/examples/src/glupload.rs +++ b/examples/src/glupload.rs @@ -308,14 +308,13 @@ fn load(gl_context: &glutin::WindowedContext) -> Gl { #[derive(Debug)] enum Message { - Sample(gst::Sample), + Frame(gst_video::VideoInfo, gst::Buffer), BusEvent, } pub(crate) struct App { pipeline: gst::Pipeline, appsink: gst_app::AppSink, - glupload: gst::Element, bus: gst::Bus, event_loop: glutin::event_loop::EventLoop, windowed_context: glutin::WindowedContext, @@ -326,7 +325,7 @@ impl App { pub(crate) fn new(gl_element: Option<&gst::Element>) -> Result { gst::init()?; - let (pipeline, appsink, glupload) = App::create_pipeline(gl_element)?; + let (pipeline, appsink) = App::create_pipeline(gl_element)?; let bus = pipeline .bus() .expect("Pipeline without bus. Shouldn't happen!"); @@ -458,7 +457,6 @@ impl App { Ok(App { pipeline, appsink, - glupload, bus, event_loop, windowed_context, @@ -473,33 +471,49 @@ impl App { .new_sample(move |appsink| { let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Eos)?; - { - let _buffer = sample.buffer().ok_or_else(|| { + let info = sample + .caps() + .and_then(|caps| gst_video::VideoInfo::from_caps(caps).ok()) + .ok_or_else(|| { element_error!( appsink, gst::ResourceError::Failed, - ("Failed to get buffer from appsink") + ("Failed to get video info from sample") ); - gst::FlowError::Error + gst::FlowError::NotNegotiated })?; - let _info = sample - .caps() - .and_then(|caps| gst_video::VideoInfo::from_caps(caps).ok()) - .ok_or_else(|| { + let mut buffer = sample.buffer_owned().unwrap(); + { + let context = match (buffer.n_memory() > 0) + .then(|| buffer.peek_memory(0)) + .and_then(|m| m.downcast_memory_ref::()) + .map(|m| m.context()) + { + Some(context) => context.clone(), + None => { element_error!( appsink, gst::ResourceError::Failed, - ("Failed to get video info from sample") + ("Failed to get GL context from buffer") ); - gst::FlowError::Error - })?; + return Err(gst::FlowError::Error); + } + }; + + if let Some(meta) = buffer.meta::() { + meta.set_sync_point(&context); + } else { + let buffer = buffer.make_mut(); + let meta = gst_gl::GLSyncMeta::add(buffer, &context); + meta.set_sync_point(&context); + } } event_proxy - .send_event(Message::Sample(sample)) + .send_event(Message::Frame(info, buffer)) .map(|()| gst::FlowSuccess::Ok) .map_err(|e| { element_error!( @@ -529,7 +543,7 @@ impl App { fn create_pipeline( gl_element: Option<&gst::Element>, - ) -> Result<(gst::Pipeline, gst_app::AppSink, gst::Element), Error> { + ) -> Result<(gst::Pipeline, gst_app::AppSink), Error> { let pipeline = gst::Pipeline::default(); let src = gst::ElementFactory::make("videotestsrc").build()?; @@ -556,7 +570,7 @@ impl App { glupload.link(gl_element)?; gl_element.link(&appsink)?; - Ok((pipeline, appsink, glupload)) + Ok((pipeline, appsink)) } else { let sink = gst::ElementFactory::make("glsinkbin") .property("sink", &appsink) @@ -565,21 +579,7 @@ impl App { pipeline.add_many(&[&src, &sink])?; src.link(&sink)?; - // get the glupload element to extract later the used context in it - let mut iter = sink.downcast_ref::().unwrap().iterate_elements(); - let glupload = loop { - match iter.next() { - Ok(Some(element)) => { - if element.factory().map_or(false, |f| f.name() == "glupload") { - break Some(element); - } - } - Err(gst::IteratorError::Resync) => iter.resync(), - _ => break None, - } - }; - - Ok((pipeline, appsink, glupload.unwrap())) + Ok((pipeline, appsink)) } } @@ -620,12 +620,10 @@ pub(crate) fn main_loop(app: App) -> Result<(), Error> { let gl = load(&app.windowed_context); let mut curr_frame: Option> = None; - let mut gst_gl_context: Option = None; let App { bus, event_loop, - glupload, pipeline, shared_context, windowed_context, @@ -660,22 +658,7 @@ pub(crate) fn main_loop(app: App) -> Result<(), Error> { }, glutin::event::Event::RedrawRequested(_) => needs_redraw = true, // Receive a frame - glutin::event::Event::UserEvent(Message::Sample(sample)) => { - let buffer = sample.buffer_owned().unwrap(); - let info = sample - .caps() - .and_then(|caps| gst_video::VideoInfo::from_caps(caps).ok()) - .unwrap(); - - { - if gst_gl_context.is_none() { - gst_gl_context = glupload.property::>("context"); - } - - let sync_meta = buffer.meta::().unwrap(); - sync_meta.set_sync_point(gst_gl_context.as_ref().unwrap()); - } - + glutin::event::Event::UserEvent(Message::Frame(info, buffer)) => { if let Ok(frame) = gst_video::VideoFrame::from_buffer_readable_gl(buffer, &info) { curr_frame = Some(frame); needs_redraw = true; diff --git a/gstreamer-gl/src/gl_base_memory.rs b/gstreamer-gl/src/gl_base_memory.rs index 161b86fcb..42ab36113 100644 --- a/gstreamer-gl/src/gl_base_memory.rs +++ b/gstreamer-gl/src/gl_base_memory.rs @@ -86,4 +86,11 @@ impl GLBaseMemoryRef { ffi::gst_gl_base_memory_init_once(); } } + + pub fn context(&self) -> &crate::GLContext { + unsafe { + &*(&(*self.as_ptr()).context as *const *mut ffi::GstGLContext + as *const crate::GLContext) + } + } }