From 1aabeefa08ef5a1e00f929e72bc52e6776c6d684 Mon Sep 17 00:00:00 2001 From: Marco Melorio Date: Sat, 3 Dec 2022 16:51:45 +0100 Subject: [PATCH] message-video: Use gst paintable sink --- Cargo.lock | 316 +++++++++++++++++++++++ Cargo.toml | 3 + src/main.rs | 11 +- src/session/content/message_row/mod.rs | 2 +- src/session/content/message_row/video.rs | 82 +++++- 5 files changed, 400 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 317607f43..f3c04ae49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,12 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" +[[package]] +name = "atomic_refcell" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "857253367827bd9d0fd973f0ef15506a96e79e41b0ad7aa691203a4e3214f6c8" + [[package]] name = "atty" version = "0.2.14" @@ -422,6 +428,55 @@ dependencies = [ "system-deps", ] +[[package]] +name = "gdk4-wayland" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d34175f400cfc1dc20443a97184d8366e78b16ae488f6ad208c44f710713d9a" +dependencies = [ + "gdk4", + "gdk4-wayland-sys", + "gio", + "glib", + "libc", +] + +[[package]] +name = "gdk4-wayland-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a7589f15d81c946598b31aa21113011b2465c5e4459f7b34d4895168f5a3e7" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk4-x11" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2cb4d8362649a35490098008235f242eedff719c6340178a80c3c03ea4dd5a" +dependencies = [ + "gdk4", + "gdk4-x11-sys", + "gio", + "glib", + "libc", +] + +[[package]] +name = "gdk4-x11-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "880be6ce14b75f173525d6e1dd62342d7189a01fab1686c0c6e1d58312acf3f1" +dependencies = [ + "gdk4-sys", + "glib-sys", + "libc", + "system-deps", +] + [[package]] name = "gettext-rs" version = "0.7.0" @@ -589,6 +644,237 @@ dependencies = [ "system-deps", ] +[[package]] +name = "gst-plugin-gtk4" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38df9956c32e9aa41df32cc624adc33397f73e8572d41016d9f31b2b875ccb" +dependencies = [ + "gdk4-wayland", + "gdk4-x11", + "gst-plugin-version-helper", + "gstreamer", + "gstreamer-base", + "gstreamer-gl", + "gstreamer-gl-egl", + "gstreamer-gl-wayland", + "gstreamer-gl-x11", + "gstreamer-video", + "gtk4", + "once_cell", +] + +[[package]] +name = "gst-plugin-version-helper" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87921209945e5dc809848a100115fad65bd127671896f0206f45e272080cc4c9" +dependencies = [ + "chrono", +] + +[[package]] +name = "gstreamer" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d4f183660dc65a607f9c97ce4a3f72a208bf888c0c34d6cd052c7c4b2e086a1" +dependencies = [ + "bitflags", + "cfg-if", + "futures-channel", + "futures-core", + "futures-util", + "glib", + "gstreamer-sys", + "libc", + "muldiv", + "num-integer", + "num-rational", + "once_cell", + "option-operations", + "paste", + "pretty-hex", + "smallvec", + "thiserror", +] + +[[package]] +name = "gstreamer-base" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5598bfedbff12675a6cddbe420b6a3ba5039c64aaf7df130db6339d09b634b0e" +dependencies = [ + "atomic_refcell", + "bitflags", + "cfg-if", + "glib", + "gstreamer", + "gstreamer-base-sys", + "libc", +] + +[[package]] +name = "gstreamer-base-sys" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26114ed96f6668380f5a1554128159e98e06c3a7a8460f216d7cd6dce28f928c" +dependencies = [ + "glib-sys", + "gobject-sys", + "gstreamer-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gstreamer-gl" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b82b83d18ad1c4d890694b4bedde170c748462a11f51a68428671bc1bf93e71e" +dependencies = [ + "bitflags", + "glib", + "gstreamer", + "gstreamer-base", + "gstreamer-gl-sys", + "gstreamer-video", + "libc", + "once_cell", +] + +[[package]] +name = "gstreamer-gl-egl" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec342886c7037cf18e07cf00aa5b60498ef5f9841aa36078a51f28d93970f93" +dependencies = [ + "glib", + "gstreamer", + "gstreamer-gl", + "gstreamer-gl-egl-sys", + "libc", +] + +[[package]] +name = "gstreamer-gl-egl-sys" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f6f24c488311f09198e41826634e5e693149f10c9da1f6aa1be9e4e81e414e" +dependencies = [ + "glib-sys", + "gstreamer-gl-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gstreamer-gl-sys" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f08af9ae5ca5aa01c4875346bb7e61310b75a9afc3607b52a6b73470be93bbc7" +dependencies = [ + "glib-sys", + "gobject-sys", + "gstreamer-base-sys", + "gstreamer-sys", + "gstreamer-video-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gstreamer-gl-wayland" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e8229f920f1703cdd5415ed2a8caaa9dab7794be1a190bd7e3a3d91549f417" +dependencies = [ + "glib", + "gstreamer", + "gstreamer-gl", + "gstreamer-gl-wayland-sys", + "libc", +] + +[[package]] +name = "gstreamer-gl-wayland-sys" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7812f3fd82eb23c3f7f564b4d5c3b175dcc1e1947a4dcb93dde9129d9197232f" +dependencies = [ + "glib-sys", + "gstreamer-gl-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gstreamer-gl-x11" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a82db426e6789bcb36e093100c97f8586f3a118bb7f268f36da9421044f646" +dependencies = [ + "glib", + "gstreamer", + "gstreamer-gl", + "gstreamer-gl-x11-sys", + "libc", +] + +[[package]] +name = "gstreamer-gl-x11-sys" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27467cb653e78d5d4b0b275f45b2bce6520f5b8b6a241867ae98f3c56f23f1" +dependencies = [ + "glib-sys", + "gstreamer-gl-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gstreamer-sys" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e56fe047adef7d47dbafa8bc1340fddb53c325e16574763063702fc94b5786d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gstreamer-video" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef95ad7e9645ef1a96373f1ea50135aec88fd29407b1979af7bb933a2ab0075b" +dependencies = [ + "bitflags", + "cfg-if", + "futures-channel", + "glib", + "gstreamer", + "gstreamer-base", + "gstreamer-video-sys", + "libc", + "once_cell", +] + +[[package]] +name = "gstreamer-video-sys" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66ddb6112d438aac0004d2db6053a572f92b1c5e0e9d6ff6c71d9245f7f73e46" +dependencies = [ + "glib-sys", + "gobject-sys", + "gstreamer-base-sys", + "gstreamer-sys", + "libc", + "system-deps", +] + [[package]] name = "gtk4" version = "0.6.2" @@ -861,6 +1147,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "muldiv" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956787520e75e9bd233246045d19f42fb73242759cc57fba9611d940ae96d4b0" + [[package]] name = "nom8" version = "0.2.0" @@ -935,6 +1227,15 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "option-operations" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c26d27bb1aeab65138e4bf7666045169d1717febcc9ff870166be8348b223d0" +dependencies = [ + "paste", +] + [[package]] name = "pango" version = "0.17.0" @@ -961,6 +1262,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "paste" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" + [[package]] name = "pest" version = "2.5.5" @@ -989,6 +1296,12 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "pretty-hex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" + [[package]] name = "pretty_env_logger" version = "0.4.0" @@ -1273,6 +1586,9 @@ dependencies = [ "ellipse", "futures", "gettext-rs", + "gst-plugin-gtk4", + "gstreamer", + "gstreamer-video", "gtk4", "image", "indexmap", diff --git a/Cargo.toml b/Cargo.toml index 75abffaac..0436259e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,9 @@ anyhow = "1.0" ellipse = "0.2" futures = { version = "0.3", default-features = false } gettext-rs = { version = "0.7", features = ["gettext-system"] } +gst = { version = "0.20", package = "gstreamer" } +gst_gtk = { version = "0.10", package = "gst-plugin-gtk4", features = ["wayland", "x11glx", "x11egl"] } +gst_video = { version = "0.20", package = "gstreamer-video" } gtk = { version = "0.6", package = "gtk4", features = ["gnome_43", "blueprint"] } image = { version = "0.24", default-features = false, features = ["webp"] } indexmap = "1.9" diff --git a/src/main.rs b/src/main.rs index fb8be97b8..aa7b89d23 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,9 @@ pub(crate) static APPLICATION_OPTS: OnceCell = OnceCell::new pub(crate) static TEMP_DIR: OnceCell = OnceCell::new(); fn main() -> glib::ExitCode { + gst::init().unwrap(); + gst_gtk::plugin_register_static().expect("Failed to register gstgtk4 plugin"); + // Prepare i18n gettextrs::setlocale(LocaleCategory::LcAll, ""); gettextrs::bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain"); @@ -90,7 +93,13 @@ fn main() -> glib::ExitCode { } } - app.run() + let res = app.run(); + + unsafe { + gst::deinit(); + } + + res } /// Global options for the application diff --git a/src/session/content/message_row/mod.rs b/src/session/content/message_row/mod.rs index db9e0746b..0716559d3 100644 --- a/src/session/content/message_row/mod.rs +++ b/src/session/content/message_row/mod.rs @@ -329,7 +329,7 @@ impl MessageRow { match message_.content().0 { // FIXME: Re-enable MessageVideo when // https://github.com/melix99/telegrand/issues/410 is fixed - MessageContent::MessageAnimation(_) /*| MessageContent::MessageVideo(_)*/ => { + MessageContent::MessageAnimation(_) | MessageContent::MessageVideo(_) => { self.update_specific_content::<_, MessageVideo>(message_.clone()); } MessageContent::MessagePhoto(_) => { diff --git a/src/session/content/message_row/video.rs b/src/session/content/message_row/video.rs index c0dd31f6f..14c54e25f 100644 --- a/src/session/content/message_row/video.rs +++ b/src/session/content/message_row/video.rs @@ -1,5 +1,5 @@ use glib::clone; -use gtk::prelude::*; +use gst::prelude::*; use gtk::subclass::prelude::*; use gtk::{gdk, glib, CompositeTemplate}; use tdlib::enums::MessageContent; @@ -203,19 +203,20 @@ impl MessageVideo { fn load_video_from_path(&self, path: &str) { let imp = self.imp(); - let media = gtk::MediaFile::for_filename(path); - media.set_muted(true); - media.set_loop(true); - media.play(); + let (pipeline, paintable) = create_pipeline(path); + imp.picture.set_paintable(Some(&paintable)); - if !imp.is_animation.get() { - media.connect_timestamp_notify(clone!(@weak self as obj => move |media| { - let time = (media.duration() - media.timestamp()) / i64::pow(10, 6); - obj.update_remaining_time(time); - })); - } + // TODO: Pause the pipeline when the widget is not visible + pipeline + .set_state(gst::State::Playing) + .expect("Unable to set the pipeline to the `Playing` state"); - imp.picture.set_paintable(Some(&media)); + // if !imp.is_animation.get() { + // media.connect_timestamp_notify(clone!(@weak self as obj => move |media| { + // let time = (media.duration() - media.timestamp()) / i64::pow(10, 6); + // obj.update_remaining_time(time); + // })); + // } } fn update_remaining_time(&self, time: i64) { @@ -232,3 +233,60 @@ impl MessageVideo { } } } + +fn create_pipeline(path: &str) -> (gst::Pipeline, gdk::Paintable) { + let pipeline = gst::Pipeline::new(None); + + let src = gst::ElementFactory::make("filesrc") + .property("location", path) + .build() + .unwrap(); + + let decodebin = gst::ElementFactory::make("decodebin").build().unwrap(); + + let gtksink = gst::ElementFactory::make("gtk4paintablesink") + .build() + .unwrap(); + + // Need to set state to Ready to get a GL context + gtksink.set_state(gst::State::Ready).unwrap(); + let paintable = gtksink.property::("paintable"); + + let sink = if paintable + .property::>("gl-context") + .is_some() + { + gst::ElementFactory::make("glsinkbin") + .property("sink", >ksink) + .build() + .unwrap() + } else { + let sink = gst::Bin::default(); + let convert = gst::ElementFactory::make("videoconvert").build().unwrap(); + + sink.add(&convert).unwrap(); + sink.add(>ksink).unwrap(); + convert.link(>ksink).unwrap(); + + sink.add_pad( + &gst::GhostPad::with_target(Some("sink"), &convert.static_pad("sink").unwrap()) + .unwrap(), + ) + .unwrap(); + + sink.upcast() + }; + + decodebin.connect_pad_added(clone!(@weak sink => move |_, src_pad| { + let sink_pad = sink.static_pad("sink").unwrap(); + if !sink_pad.is_linked() { + src_pad.link(&sink_pad).unwrap(); + } + })); + + pipeline.add_many(&[&src, &decodebin, &sink]).unwrap(); + + src.link(&decodebin).unwrap(); + + (pipeline, paintable) +}