gtk4: GL path causes still image to turn blank until state set to Playing
I have a Paused pipeline, to which I add a Paused, pre-rolled playbin3. Specifically when using the GL path and when playbin3 is opening a still image, this causes the image to turn blank until the pipeline is set to Playing. Disabling the GL path fixes the issue, and opening a video also fixes the issue (showing the first video frame as expected). After the pipeline is Playing, it seems that it remains fine, so pausing or seeking does not blank the image again.
Reproducer (based on the gtksink.rs
example), cargo r --example gtksink --features wayland /path/to/image.png
:
use gst::prelude::*;
use gtk::prelude::*;
use gtk::{gdk, gio, glib};
use std::cell::RefCell;
static mut FILE: Option<gio::File> = None;
fn open(app: >k::Application, files: &[gio::File], _: &str) {
unsafe {
FILE = Some(
files
.get(0)
.expect("pass uri as commandline argument")
.clone(),
)
}
app.activate();
}
fn create_ui(app: >k::Application) {
let window = gtk::ApplicationWindow::new(app);
window.set_default_size(640, 480);
let box_ = gtk::Box::new(gtk::Orientation::Horizontal, 0);
box_.set_hexpand(true);
box_.set_homogeneous(true);
window.set_child(Some(&box_));
let pipeline = gst::Pipeline::new(None);
pipeline
.bus()
.unwrap()
.add_watch_local(move |_, msg| {
use gst::MessageView;
match msg.view() {
MessageView::Error(err) => {
println!(
"Error from {:?}: {} ({:?})",
err.src().map(|s| s.path_string()),
err.error(),
err.debug()
);
}
_ => (),
};
glib::Continue(true)
})
.unwrap();
pipeline.set_state(gst::State::Paused).unwrap();
let sink = gst::ElementFactory::make("gtk4paintablesink")
.build()
.unwrap();
sink.set_state(gst::State::Ready).unwrap();
let paintable = sink.property::<gdk::Paintable>("paintable");
assert!(
paintable
.property::<Option<gdk::GLContext>>("gl-context")
.is_some(),
"we need gl-context for this test"
);
// Commenting this out (disabling the GL path) makes the image show up.
let sink = gst::ElementFactory::make("glsinkbin")
.property("sink", &sink)
.build()
.unwrap();
let playbin = gst::ElementFactory::make("playbin3")
.property("uri", unsafe {
FILE.as_ref()
.expect("pass uri as commandline argument")
.uri()
})
.property("video-sink", sink)
.build()
.unwrap();
let picture = gtk::Picture::new();
picture.set_paintable(Some(&paintable));
box_.append(&picture);
// Pre-roll.
playbin.set_state(gst::State::Paused).unwrap();
// Wait until it's pre-rolled.
std::thread::sleep_ms(1000);
pipeline.add(&playbin).unwrap();
window.show();
app.add_window(&window);
// Uncommenting this also makes the image show up.
// pipeline.set_state(gst::State::Playing).unwrap();
let pipeline = RefCell::new(Some(pipeline));
app.connect_shutdown(move |_| {
window.close();
if let Some(pipeline) = pipeline.borrow_mut().take() {
pipeline.set_state(gst::State::Null).unwrap();
pipeline.bus().unwrap().remove_watch().unwrap();
}
});
}
fn main() -> glib::ExitCode {
gst::init().unwrap();
gtk::init().unwrap();
gstgtk4::plugin_register_static().expect("Failed to register gstgtk4 plugin");
let res = {
let app = gtk::Application::new(None::<&str>, gio::ApplicationFlags::HANDLES_OPEN);
app.connect_open(open);
app.connect_activate(create_ui);
app.run()
};
unsafe {
gst::deinit();
}
res
}
cc @slomo