Skip to content

Commit

Permalink
examples/glupload: Update glutin to 0.26 with winit 0.24
Browse files Browse the repository at this point in the history
Winit 0.19 uses uninitialized variables which is invalid since Rust
1.48, leading to a runtime panic [1].  Updating to the latest version
resolves these issues but requires significant refactoring since the
event loop now runs entirely within a closure.

[1]: rust-windowing/winit#1811
  • Loading branch information
MarijnS95 committed Apr 10, 2021
1 parent 8ab8f00 commit 5e8634e
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 72 deletions.
5 changes: 5 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ name = "gstreamer-rs-lgpl-docs"
multiple-versions = "deny"
wildcards = "allow"
highlight = "all"
skip-tree = [
# Winit introduces quite a few duplicate (outdated!) dependencies together
# with its direct dependant glutin.
{ name = "winit", version = "0.24" }
]

[sources]
unknown-registry = "deny"
Expand Down
3 changes: 1 addition & 2 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ byte-slice-cast = "1"
cairo-rs = { git = "https://github.com/gtk-rs/gtk-rs", features=["use_glib"], optional = true }
pango = { git = "https://github.com/gtk-rs/gtk-rs", optional = true }
pangocairo = { git = "https://github.com/gtk-rs/gtk-rs", optional = true }
glutin = { version = "0.21", optional = true }
winit = { version = "0.19", optional = true }
glutin = { version = "0.26", optional = true }
once_cell = "1.0"
image = { version="0.23", optional = true }

Expand Down
139 changes: 69 additions & 70 deletions examples/src/bin/glupload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use gst_gl::prelude::*;
use std::ffi::CStr;
use std::mem;
use std::ptr;
use std::sync;
use std::sync::mpsc;

use anyhow::Error;
Expand Down Expand Up @@ -184,7 +185,7 @@ impl Gl {
}
}

fn resize(&self, size: glutin::dpi::PhysicalSize) {
fn resize(&self, size: glutin::dpi::PhysicalSize<u32>) {
unsafe {
self.gl
.Viewport(0, 0, size.width as i32, size.height as i32);
Expand Down Expand Up @@ -318,7 +319,7 @@ struct App {
appsink: gst_app::AppSink,
glupload: gst::Element,
bus: gst::Bus,
events_loop: glutin::EventsLoop,
event_loop: glutin::event_loop::EventLoop<()>,
windowed_context: glutin::WindowedContext<glutin::PossiblyCurrent>,
shared_context: gst_gl::GLContext,
}
Expand All @@ -332,11 +333,11 @@ impl App {
.get_bus()
.expect("Pipeline without bus. Shouldn't happen!");

let events_loop = glutin::EventsLoop::new();
let window = glutin::WindowBuilder::new().with_title("GL rendering");
let event_loop = glutin::event_loop::EventLoop::new();
let window = glutin::window::WindowBuilder::new().with_title("GL rendering");
let windowed_context = glutin::ContextBuilder::new()
.with_vsync(true)
.build_windowed(window, &events_loop)?;
.build_windowed(window, &event_loop)?;

let windowed_context = unsafe { windowed_context.make_current().map_err(|(_, err)| err)? };

Expand All @@ -345,10 +346,10 @@ impl App {

let shared_context: gst_gl::GLContext;
if cfg!(target_os = "linux") {
use glutin::os::unix::RawHandle;
use glutin::platform::unix::RawHandle;
#[cfg(any(feature = "gst-gl-x11", feature = "gst-gl-wayland"))]
use glutin::os::unix::WindowExt;
use glutin::os::ContextTraitExt;
use glutin::platform::unix::WindowExtUnix;
use glutin::platform::ContextTraitExt;

let api = App::map_gl_api(windowed_context.get_api());

Expand All @@ -368,7 +369,7 @@ impl App {
};

#[cfg(feature = "gst-gl-wayland")]
if let Some(display) = inner_window.get_wayland_display() {
if let Some(display) = inner_window.wayland_display() {
gl_display = Some(
unsafe {
gst_gl_wayland::GLDisplayWayland::with_display(display as usize)
Expand All @@ -386,7 +387,7 @@ impl App {
}
#[cfg(feature = "gst-gl-x11")]
RawHandle::Glx(glx_context) => {
let gl_display = if let Some(display) = inner_window.get_xlib_display() {
let gl_display = if let Some(display) = inner_window.xlib_display() {
unsafe { gst_gl_x11::GLDisplayX11::with_display(display as usize) }.unwrap()
} else {
panic!("X11 window without X Display");
Expand All @@ -413,7 +414,7 @@ impl App {
shared_context.fill_info()?;

let gl_context = shared_context.clone();
let events_proxy = events_loop.create_proxy();
let event_proxy = sync::Mutex::new(event_loop.create_proxy());

#[allow(clippy::single_match)]
bus.set_sync_handler(move |_, msg| {
Expand Down Expand Up @@ -446,7 +447,9 @@ impl App {
_ => (),
}

let _ = events_proxy.wakeup();
if let Err(e) = event_proxy.lock().unwrap().send_event(()) {
eprintln!("Failed to send BusEvent to event proxy: {}", e)
}

gst::BusSyncReply::Pass
});
Expand All @@ -459,17 +462,17 @@ impl App {
appsink,
glupload,
bus,
events_loop,
event_loop,
windowed_context,
shared_context,
})
}

fn setup(
&self,
events_loop: &glutin::EventsLoop,
event_loop: &glutin::event_loop::EventLoop<()>,
) -> Result<mpsc::Receiver<gst::Sample>, Error> {
let events_proxy = events_loop.create_proxy();
let events_proxy = event_loop.create_proxy();
let (sender, receiver) = mpsc::channel();
self.appsink.set_callbacks(
gst_app::AppSinkCallbacks::builder()
Expand Down Expand Up @@ -506,7 +509,7 @@ impl App {
.map(|_| gst::FlowSuccess::Ok)
.map_err(|_| gst::FlowError::Error)?;

let _ = events_proxy.wakeup();
let _ = events_proxy.send_event(());

Ok(gst::FlowSuccess::Ok)
})
Expand Down Expand Up @@ -595,56 +598,64 @@ impl App {

Ok(())
}

fn into_context(self: App) -> glutin::WindowedContext<glutin::PossiblyCurrent> {
self.windowed_context
}
}

fn main_loop(mut app: App) -> Result<glutin::WindowedContext<glutin::PossiblyCurrent>, Error> {
fn main_loop(app: App) -> Result<(), Error> {
let receiver = app.setup(&app.event_loop)?;

println!(
"Pixel format of the window's GL context {:?}",
app.windowed_context.get_pixel_format()
);

let gl = load(&app.windowed_context);

let receiver = app.setup(&app.events_loop)?;

let mut curr_frame: Option<gst_video::VideoFrame<gst_video::video_frame::Readable>> = None;
let mut running = true;
let mut gst_gl_context: Option<gst_gl::GLContext> = None;
let events_loop = &mut app.events_loop;
let windowed_context = &mut app.windowed_context;
let bus = &app.bus;

while running {
#[allow(clippy::single_match)]
events_loop.poll_events(|event| match event {
glutin::Event::WindowEvent { event, .. } => match event {
glutin::WindowEvent::CloseRequested
| glutin::WindowEvent::KeyboardInput {

let App {
bus,
event_loop,
glupload,
pipeline,
shared_context,
windowed_context,
..
} = app;

event_loop.run(move |event, _, cf| {
*cf = glutin::event_loop::ControlFlow::Wait;

let mut needs_redraw = false;
match event {
glutin::event::Event::LoopDestroyed => {
pipeline.send_event(gst::event::Eos::new());
pipeline.set_state(gst::State::Null).unwrap();
}
glutin::event::Event::WindowEvent { event, .. } => match event {
glutin::event::WindowEvent::CloseRequested
| glutin::event::WindowEvent::KeyboardInput {
input:
glutin::KeyboardInput {
state: glutin::ElementState::Released,
virtual_keycode: Some(glutin::VirtualKeyCode::Escape),
glutin::event::KeyboardInput {
state: glutin::event::ElementState::Released,
virtual_keycode: Some(glutin::event::VirtualKeyCode::Escape),
..
},
..
} => running = false,
glutin::WindowEvent::Resized(logical_size) => {
let dpi_factor = windowed_context.window().get_hidpi_factor();
windowed_context.resize(logical_size.to_physical(dpi_factor));
gl.resize(logical_size.to_physical(dpi_factor));
} => *cf = glutin::event_loop::ControlFlow::Exit,
glutin::event::WindowEvent::Resized(physical_size) => {
windowed_context.resize(physical_size);
gl.resize(physical_size);
}
_ => (),
},
glutin::event::Event::RedrawRequested(_) => needs_redraw = true,
_ => (),
});
}

// Handle all pending messages. Whenever there is a message we will
// wake up the events loop above
App::handle_messages(&bus)?;
App::handle_messages(&bus).unwrap();

// get the last frame in channel
if let Some(sample) = receiver.try_iter().last() {
Expand All @@ -656,8 +667,7 @@ fn main_loop(mut app: App) -> Result<glutin::WindowedContext<glutin::PossiblyCur

{
if gst_gl_context.is_none() {
gst_gl_context = app
.glupload
gst_gl_context = glupload
.get_property("context")
.unwrap()
.get::<gst_gl::GLContext>()
Expand All @@ -670,38 +680,27 @@ fn main_loop(mut app: App) -> Result<glutin::WindowedContext<glutin::PossiblyCur

if let Ok(frame) = gst_video::VideoFrame::from_buffer_readable_gl(buffer, &info) {
curr_frame = Some(frame);
needs_redraw = true;
}
}

if let Some(frame) = curr_frame.as_ref() {
let sync_meta = frame.buffer().get_meta::<gst_gl::GLSyncMeta>().unwrap();
sync_meta.wait(&app.shared_context);
if let Some(texture) = frame.get_texture_id(0) {
gl.draw_frame(texture as gl::types::GLuint);
if needs_redraw {
if let Some(frame) = curr_frame.as_ref() {
let sync_meta = frame.buffer().get_meta::<gst_gl::GLSyncMeta>().unwrap();
sync_meta.wait(&shared_context);
if let Some(texture) = frame.get_texture_id(0) {
gl.draw_frame(texture as gl::types::GLuint);
}
}
windowed_context.swap_buffers().unwrap();
}
windowed_context.swap_buffers()?;
}

app.pipeline.send_event(gst::event::Eos::new());
app.pipeline.set_state(gst::State::Null)?;

Ok(app.into_context())
}

fn cleanup(_windowed_context: glutin::WindowedContext<glutin::PossiblyCurrent>) {
// To ensure that the context stays alive longer than the pipeline or any reference
// inside GStreamer to the GL context, its display or anything else. See
// https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/issues/196
//
// We might do any window/GL specific cleanup here as needed.
})
}

fn example_main() {
match App::new().and_then(main_loop).map(cleanup) {
Ok(r) => r,
Err(e) => eprintln!("Error! {}", e),
}
App::new()
.and_then(main_loop)
.unwrap_or_else(|e| eprintln!("Error! {}", e))
}

fn main() {
Expand Down

0 comments on commit 5e8634e

Please sign in to comment.