mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-12-23 08:36:31 +00:00
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`.
This commit is contained in:
parent
c6cbf86012
commit
951f000622
2 changed files with 41 additions and 51 deletions
|
@ -308,14 +308,13 @@ fn load(gl_context: &glutin::WindowedContext<glutin::PossiblyCurrent>) -> Gl {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Message {
|
enum Message {
|
||||||
Sample(gst::Sample),
|
Frame(gst_video::VideoInfo, gst::Buffer),
|
||||||
BusEvent,
|
BusEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct App {
|
pub(crate) struct App {
|
||||||
pipeline: gst::Pipeline,
|
pipeline: gst::Pipeline,
|
||||||
appsink: gst_app::AppSink,
|
appsink: gst_app::AppSink,
|
||||||
glupload: gst::Element,
|
|
||||||
bus: gst::Bus,
|
bus: gst::Bus,
|
||||||
event_loop: glutin::event_loop::EventLoop<Message>,
|
event_loop: glutin::event_loop::EventLoop<Message>,
|
||||||
windowed_context: glutin::WindowedContext<glutin::PossiblyCurrent>,
|
windowed_context: glutin::WindowedContext<glutin::PossiblyCurrent>,
|
||||||
|
@ -326,7 +325,7 @@ impl App {
|
||||||
pub(crate) fn new(gl_element: Option<&gst::Element>) -> Result<App, Error> {
|
pub(crate) fn new(gl_element: Option<&gst::Element>) -> Result<App, Error> {
|
||||||
gst::init()?;
|
gst::init()?;
|
||||||
|
|
||||||
let (pipeline, appsink, glupload) = App::create_pipeline(gl_element)?;
|
let (pipeline, appsink) = App::create_pipeline(gl_element)?;
|
||||||
let bus = pipeline
|
let bus = pipeline
|
||||||
.bus()
|
.bus()
|
||||||
.expect("Pipeline without bus. Shouldn't happen!");
|
.expect("Pipeline without bus. Shouldn't happen!");
|
||||||
|
@ -458,7 +457,6 @@ impl App {
|
||||||
Ok(App {
|
Ok(App {
|
||||||
pipeline,
|
pipeline,
|
||||||
appsink,
|
appsink,
|
||||||
glupload,
|
|
||||||
bus,
|
bus,
|
||||||
event_loop,
|
event_loop,
|
||||||
windowed_context,
|
windowed_context,
|
||||||
|
@ -473,33 +471,49 @@ impl App {
|
||||||
.new_sample(move |appsink| {
|
.new_sample(move |appsink| {
|
||||||
let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Eos)?;
|
let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Eos)?;
|
||||||
|
|
||||||
{
|
let info = sample
|
||||||
let _buffer = sample.buffer().ok_or_else(|| {
|
.caps()
|
||||||
|
.and_then(|caps| gst_video::VideoInfo::from_caps(caps).ok())
|
||||||
|
.ok_or_else(|| {
|
||||||
element_error!(
|
element_error!(
|
||||||
appsink,
|
appsink,
|
||||||
gst::ResourceError::Failed,
|
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
|
let mut buffer = sample.buffer_owned().unwrap();
|
||||||
.caps()
|
{
|
||||||
.and_then(|caps| gst_video::VideoInfo::from_caps(caps).ok())
|
let context = match (buffer.n_memory() > 0)
|
||||||
.ok_or_else(|| {
|
.then(|| buffer.peek_memory(0))
|
||||||
|
.and_then(|m| m.downcast_memory_ref::<gst_gl::GLBaseMemory>())
|
||||||
|
.map(|m| m.context())
|
||||||
|
{
|
||||||
|
Some(context) => context.clone(),
|
||||||
|
None => {
|
||||||
element_error!(
|
element_error!(
|
||||||
appsink,
|
appsink,
|
||||||
gst::ResourceError::Failed,
|
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::<gst_gl::GLSyncMeta>() {
|
||||||
|
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
|
event_proxy
|
||||||
.send_event(Message::Sample(sample))
|
.send_event(Message::Frame(info, buffer))
|
||||||
.map(|()| gst::FlowSuccess::Ok)
|
.map(|()| gst::FlowSuccess::Ok)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
element_error!(
|
element_error!(
|
||||||
|
@ -529,7 +543,7 @@ impl App {
|
||||||
|
|
||||||
fn create_pipeline(
|
fn create_pipeline(
|
||||||
gl_element: Option<&gst::Element>,
|
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 pipeline = gst::Pipeline::default();
|
||||||
let src = gst::ElementFactory::make("videotestsrc").build()?;
|
let src = gst::ElementFactory::make("videotestsrc").build()?;
|
||||||
|
|
||||||
|
@ -556,7 +570,7 @@ impl App {
|
||||||
glupload.link(gl_element)?;
|
glupload.link(gl_element)?;
|
||||||
gl_element.link(&appsink)?;
|
gl_element.link(&appsink)?;
|
||||||
|
|
||||||
Ok((pipeline, appsink, glupload))
|
Ok((pipeline, appsink))
|
||||||
} else {
|
} else {
|
||||||
let sink = gst::ElementFactory::make("glsinkbin")
|
let sink = gst::ElementFactory::make("glsinkbin")
|
||||||
.property("sink", &appsink)
|
.property("sink", &appsink)
|
||||||
|
@ -565,21 +579,7 @@ impl App {
|
||||||
pipeline.add_many(&[&src, &sink])?;
|
pipeline.add_many(&[&src, &sink])?;
|
||||||
src.link(&sink)?;
|
src.link(&sink)?;
|
||||||
|
|
||||||
// get the glupload element to extract later the used context in it
|
Ok((pipeline, appsink))
|
||||||
let mut iter = sink.downcast_ref::<gst::Bin>().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()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,12 +620,10 @@ pub(crate) fn main_loop(app: App) -> Result<(), Error> {
|
||||||
let gl = load(&app.windowed_context);
|
let gl = load(&app.windowed_context);
|
||||||
|
|
||||||
let mut curr_frame: Option<gst_video::VideoFrame<gst_video::video_frame::Readable>> = None;
|
let mut curr_frame: Option<gst_video::VideoFrame<gst_video::video_frame::Readable>> = None;
|
||||||
let mut gst_gl_context: Option<gst_gl::GLContext> = None;
|
|
||||||
|
|
||||||
let App {
|
let App {
|
||||||
bus,
|
bus,
|
||||||
event_loop,
|
event_loop,
|
||||||
glupload,
|
|
||||||
pipeline,
|
pipeline,
|
||||||
shared_context,
|
shared_context,
|
||||||
windowed_context,
|
windowed_context,
|
||||||
|
@ -660,22 +658,7 @@ pub(crate) fn main_loop(app: App) -> Result<(), Error> {
|
||||||
},
|
},
|
||||||
glutin::event::Event::RedrawRequested(_) => needs_redraw = true,
|
glutin::event::Event::RedrawRequested(_) => needs_redraw = true,
|
||||||
// Receive a frame
|
// Receive a frame
|
||||||
glutin::event::Event::UserEvent(Message::Sample(sample)) => {
|
glutin::event::Event::UserEvent(Message::Frame(info, buffer)) => {
|
||||||
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::<Option<gst_gl::GLContext>>("context");
|
|
||||||
}
|
|
||||||
|
|
||||||
let sync_meta = buffer.meta::<gst_gl::GLSyncMeta>().unwrap();
|
|
||||||
sync_meta.set_sync_point(gst_gl_context.as_ref().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(frame) = gst_video::VideoFrame::from_buffer_readable_gl(buffer, &info) {
|
if let Ok(frame) = gst_video::VideoFrame::from_buffer_readable_gl(buffer, &info) {
|
||||||
curr_frame = Some(frame);
|
curr_frame = Some(frame);
|
||||||
needs_redraw = true;
|
needs_redraw = true;
|
||||||
|
|
|
@ -86,4 +86,11 @@ impl GLBaseMemoryRef {
|
||||||
ffi::gst_gl_base_memory_init_once();
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue