From f1149a6b5e6ed79c2c167ecabf1e2872dc878e1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Cerveau?= Date: Fri, 3 Dec 2021 14:47:20 +0100 Subject: [PATCH] pipeline: implement parse launch playback Can now play/pause/stop a playback from a parse launch description GST pipeline. rename getters in pipeline.rs --- Cargo.lock | 237 +++++++--------------------------- Cargo.toml | 5 +- src/app.rs | 81 +++++++++--- src/graphmanager/graphview.rs | 5 + src/pipeline.rs | 192 ++++++++++++++++++++++----- 5 files changed, 277 insertions(+), 243 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 77bd848..2fbf29f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,7 +28,7 @@ checksum = "9164355c892b026d6257e696dde5f3cb39beb3718297f0f161b562fe2ee3ab86" dependencies = [ "bitflags", "cairo-sys-rs", - "glib 0.14.8", + "glib", "libc", "thiserror", ] @@ -39,7 +39,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c9c3928781e8a017ece15eace05230f04b647457d170d2d9641c94a444ff80" dependencies = [ - "glib-sys 0.14.0", + "glib-sys", "libc", "system-deps 3.2.0", ] @@ -116,19 +116,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" -[[package]] -name = "futures-macro" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" -dependencies = [ - "autocfg", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "futures-task" version = "0.3.17" @@ -143,12 +130,9 @@ checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ "autocfg", "futures-core", - "futures-macro", "futures-task", "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] @@ -160,7 +144,7 @@ checksum = "534192cb8f01daeb8fab2c8d4baa8f9aae5b7a39130525779f5c2608e235b10f" dependencies = [ "gdk-pixbuf-sys", "gio", - "glib 0.14.8", + "glib", "libc", ] @@ -171,8 +155,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f097c0704201fbc8f69c1762dc58c6947c8bb188b8ed0bc7e65259f1894fe590" dependencies = [ "gio-sys", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys", + "gobject-sys", "libc", "system-deps 3.2.0", ] @@ -188,7 +172,7 @@ dependencies = [ "gdk-pixbuf", "gdk4-sys", "gio", - "glib 0.14.8", + "glib", "libc", "pango", ] @@ -202,8 +186,8 @@ dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", "gio-sys", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys", + "gobject-sys", "graphene-sys", "libc", "pango-sys", @@ -221,7 +205,7 @@ dependencies = [ "futures-core", "futures-io", "gio-sys", - "glib 0.14.8", + "glib", "libc", "once_cell", "thiserror", @@ -233,32 +217,13 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0a41df66e57fcc287c4bcf74fc26b884f31901ea9792ec75607289b456f48fa" dependencies = [ - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys", + "gobject-sys", "libc", "system-deps 3.2.0", "winapi", ] -[[package]] -name = "glib" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5" -dependencies = [ - "bitflags", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "glib-macros 0.10.1", - "glib-sys 0.10.1", - "gobject-sys 0.10.0", - "libc", - "once_cell", -] - [[package]] name = "glib" version = "0.14.8" @@ -270,30 +235,14 @@ dependencies = [ "futures-core", "futures-executor", "futures-task", - "glib-macros 0.14.1", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-macros", + "glib-sys", + "gobject-sys", "libc", "once_cell", "smallvec", ] -[[package]] -name = "glib-macros" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039" -dependencies = [ - "anyhow", - "heck", - "itertools 0.9.0", - "proc-macro-crate 0.1.5", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "glib-macros" version = "0.14.1" @@ -302,23 +251,13 @@ checksum = "2aad66361f66796bfc73f530c51ef123970eb895ffba991a234fcf7bea89e518" dependencies = [ "anyhow", "heck", - "proc-macro-crate 1.1.0", + "proc-macro-crate", "proc-macro-error", "proc-macro2", "quote", "syn", ] -[[package]] -name = "glib-sys" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" -dependencies = [ - "libc", - "system-deps 1.3.2", -] - [[package]] name = "glib-sys" version = "0.14.0" @@ -329,24 +268,13 @@ dependencies = [ "system-deps 3.2.0", ] -[[package]] -name = "gobject-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c" -dependencies = [ - "glib-sys 0.10.1", - "libc", - "system-deps 1.3.2", -] - [[package]] name = "gobject-sys" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5" dependencies = [ - "glib-sys 0.14.0", + "glib-sys", "libc", "system-deps 3.2.0", ] @@ -357,7 +285,7 @@ version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3380f132530ef9eb9e0a2bac180e30390aa5e49892d20294f822a974117a563" dependencies = [ - "glib 0.14.8", + "glib", "graphene-sys", "libc", ] @@ -368,7 +296,7 @@ version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a9ac7450b3aa80792513a3c029920a2ede419de13fb5169a4e51b07a5685332" dependencies = [ - "glib-sys 0.14.0", + "glib-sys", "libc", "pkg-config", "system-deps 3.2.0", @@ -383,7 +311,7 @@ dependencies = [ "bitflags", "cairo-rs", "gdk4", - "glib 0.14.8", + "glib", "graphene-rs", "gsk4-sys", "libc", @@ -398,8 +326,8 @@ checksum = "13aa53ce70234da02f9954339d988d5ab853d746a8f47a4ae17735ff873545b5" dependencies = [ "cairo-sys-rs", "gdk4-sys", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys", + "gobject-sys", "graphene-sys", "libc", "pango-sys", @@ -411,6 +339,7 @@ name = "gst_pipeline_studio" version = "0.1.0" dependencies = [ "anyhow", + "glib", "gstreamer", "gtk4", "log", @@ -420,21 +349,20 @@ dependencies = [ [[package]] name = "gstreamer" -version = "0.16.7" +version = "0.17.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff5d0f7ff308ae37e6eb47b6ded17785bdea06e438a708cd09e0288c1862f33" +checksum = "c6a255f142048ba2c4a4dce39106db1965abe355d23f4b5335edea43a553faa4" dependencies = [ "bitflags", "cfg-if", "futures-channel", "futures-core", "futures-util", - "glib 0.10.3", - "glib-sys 0.10.1", - "gobject-sys 0.10.0", + "glib", "gstreamer-sys", "libc", "muldiv", + "num-integer", "num-rational", "once_cell", "paste", @@ -444,14 +372,14 @@ dependencies = [ [[package]] name = "gstreamer-sys" -version = "0.9.1" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1f154082d01af5718c5f8a8eb4f565a4ea5586ad8833a8fc2c2aa6844b601d" +checksum = "a81704feeb3e8599913bdd1e738455c2991a01ff4a1780cb62200993e454cc3e" dependencies = [ - "glib-sys 0.10.1", - "gobject-sys 0.10.0", + "glib-sys", + "gobject-sys", "libc", - "system-deps 1.3.2", + "system-deps 3.2.0", ] [[package]] @@ -467,7 +395,7 @@ dependencies = [ "gdk-pixbuf", "gdk4", "gio", - "glib 0.14.8", + "glib", "graphene-rs", "gsk4", "gtk4-macros", @@ -485,8 +413,8 @@ checksum = "5068d4354af02454f44687adc613100aa98ae11e273cdcac84f89dc08be2b4a1" dependencies = [ "anyhow", "heck", - "itertools 0.10.1", - "proc-macro-crate 1.1.0", + "itertools", + "proc-macro-crate", "proc-macro-error", "proc-macro2", "quote", @@ -503,8 +431,8 @@ dependencies = [ "gdk-pixbuf-sys", "gdk4-sys", "gio-sys", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys", + "gobject-sys", "graphene-sys", "gsk4-sys", "libc", @@ -521,15 +449,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.10.1" @@ -565,9 +484,9 @@ dependencies = [ [[package]] name = "muldiv" -version = "0.2.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204" +checksum = "b5136edda114182728ccdedb9f5eda882781f35fa6e80cc360af12a8932507f3" [[package]] name = "num-integer" @@ -581,9 +500,9 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" dependencies = [ "autocfg", "num-integer", @@ -612,7 +531,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "546fd59801e5ca735af82839007edd226fe7d3bb06433ec48072be4439c28581" dependencies = [ "bitflags", - "glib 0.14.8", + "glib", "libc", "once_cell", "pango-sys", @@ -624,8 +543,8 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2367099ca5e761546ba1d501955079f097caa186bb53ce0f718dca99ac1942fe" dependencies = [ - "glib-sys 0.14.0", - "gobject-sys 0.14.0", + "glib-sys", + "gobject-sys", "libc", "system-deps 3.2.0", ] @@ -669,15 +588,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5c99d529f0d30937f6f4b8a86d988047327bb88d04d2c4afc356de74722131" -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - [[package]] name = "proc-macro-crate" version = "1.1.0" @@ -712,18 +622,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" version = "1.0.30" @@ -787,30 +685,12 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" -[[package]] -name = "strum" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" - [[package]] name = "strum" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" -[[package]] -name = "strum_macros" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "strum_macros" version = "0.21.1" @@ -834,21 +714,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "system-deps" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" -dependencies = [ - "heck", - "pkg-config", - "strum 0.18.0", - "strum_macros 0.18.0", - "thiserror", - "toml", - "version-compare 0.0.10", -] - [[package]] name = "system-deps" version = "3.2.0" @@ -858,13 +723,13 @@ dependencies = [ "anyhow", "cfg-expr 0.8.1", "heck", - "itertools 0.10.1", + "itertools", "pkg-config", - "strum 0.21.0", - "strum_macros 0.21.1", + "strum", + "strum_macros", "thiserror", "toml", - "version-compare 0.0.11", + "version-compare", ] [[package]] @@ -877,7 +742,7 @@ dependencies = [ "heck", "pkg-config", "toml", - "version-compare 0.0.11", + "version-compare", ] [[package]] @@ -927,12 +792,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" -[[package]] -name = "version-compare" -version = "0.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" - [[package]] name = "version-compare" version = "0.0.11" diff --git a/Cargo.toml b/Cargo.toml index 59a5025..09d3a7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,8 @@ edition = "2018" [dependencies] gtk = { version = "0.3", package = "gtk4" } anyhow = "1" -gstreamer = "0.16" +glib = "0.14" +gstreamer = "0.17" log = "0.4.11" once_cell = "1.7.2" -xml-rs = "0.8.4" \ No newline at end of file +xml-rs = "0.8.4" diff --git a/src/app.rs b/src/app.rs index 14ba146..4a589a7 100644 --- a/src/app.rs +++ b/src/app.rs @@ -26,7 +26,7 @@ use std::cell::RefCell; use std::rc::{Rc, Weak}; use std::{error, ops}; -use crate::pipeline::Pipeline; +use crate::pipeline::{Pipeline, PipelineState}; use crate::pluginlist; use crate::graphmanager::{GraphView, Node}; @@ -113,6 +113,33 @@ impl GPSApp { app.drop(); }); } + pub fn show_error_dialog(fatal: bool, message: &str) { + let app = gio::Application::default() + .expect("No default application") + .downcast::() + .expect("Default application has wrong type"); + + let dialog = gtk::MessageDialog::new( + app.active_window().as_ref(), + gtk::DialogFlags::MODAL, + gtk::MessageType::Error, + gtk::ButtonsType::Ok, + message, + ); + + dialog.connect_response(move |dialog, _| { + let app = gio::Application::default().expect("No default application"); + + dialog.destroy(); + + if fatal { + app.quit(); + } + }); + + dialog.set_resizable(false); + dialog.show(); + } pub fn build_ui(&self, application: &Application) { let drawing_area_window: Viewport = self @@ -236,8 +263,35 @@ impl GPSApp { let app_weak = self.downgrade(); add_button.connect_clicked(glib::clone!(@weak window => move |_| { // entry.set_text("Clicked!"); - let _app = upgrade_weak!(app_weak); - + let app = upgrade_weak!(app_weak); + let graph_view = app.graphview.borrow(); + let pipeline = app.pipeline.borrow(); + if pipeline.state() == PipelineState::Stopped { + pipeline.create_pipeline(&graph_view.render_gst()).expect("Unable to create the pipeline"); + pipeline.set_state(PipelineState::Playing).expect("Unable to change state"); + } else if pipeline.state() == PipelineState::Paused { + pipeline.set_state(PipelineState::Playing).expect("Unable to change state"); + } else { + pipeline.set_state(PipelineState::Paused).expect("Unable to change state"); + } + })); + let add_button: Button = self + .builder + .object("button-pause") + .expect("Couldn't get app_button"); + let app_weak = self.downgrade(); + add_button.connect_clicked(glib::clone!(@weak window => move |_| { + let app = upgrade_weak!(app_weak); + let graph_view = app.graphview.borrow(); + let pipeline = app.pipeline.borrow(); + if pipeline.state() == PipelineState::Stopped { + pipeline.create_pipeline(&graph_view.render_gst()).expect("Unable to create the pipeline"); + pipeline.set_state(PipelineState::Paused).expect("Unable to change state"); + } else if pipeline.state() == PipelineState::Paused { + pipeline.set_state(PipelineState::Playing).expect("Unable to change state"); + } else { + pipeline.set_state(PipelineState::Paused).expect("Unable to change state"); + } })); let add_button: Button = self .builder @@ -246,21 +300,8 @@ impl GPSApp { let app_weak = self.downgrade(); add_button.connect_clicked(glib::clone!(@weak window => move |_| { let app = upgrade_weak!(app_weak); - let graph_view = app.graphview.borrow_mut(); - graph_view.remove_all_nodes(); - let node_id = graph_view.get_next_node_id(); - let element_name = String::from("appsink"); - let pads = Pipeline::get_pads(&element_name, false); - graph_view.add_node_with_port(node_id, Node::new(node_id, &element_name, Pipeline::get_element_type(&element_name)), pads.0, pads.1); - let node_id = graph_view.get_next_node_id(); - let element_name = String::from("videotestsrc"); - let pads = Pipeline::get_pads(&element_name, false); - graph_view.add_node_with_port(node_id, Node::new(node_id, &element_name, Pipeline::get_element_type(&element_name)), pads.0, pads.1); - let node_id = graph_view.get_next_node_id(); - let element_name = String::from("videoconvert"); - let pads = Pipeline::get_pads(&element_name, false); - graph_view.add_node_with_port(node_id, Node::new(node_id, &element_name, Pipeline::get_element_type(&element_name)), pads.0, pads.1); - + let pipeline = app.pipeline.borrow(); + pipeline.set_state(PipelineState::Stopped).expect("Unable to change state to STOP"); })); let add_button: Button = self .builder @@ -285,13 +326,13 @@ impl GPSApp { pub fn add_new_element(&self, element_name: String) { let graph_view = self.graphview.borrow_mut(); let node_id = graph_view.next_node_id(); - let pads = Pipeline::get_pads(&element_name, false); + let pads = Pipeline::pads(&element_name, false); graph_view.add_node_with_port( node_id, Node::new( node_id, &element_name, - Pipeline::get_element_type(&element_name), + Pipeline::element_type(&element_name), ), pads.0, pads.1, diff --git a/src/graphmanager/graphview.rs b/src/graphmanager/graphview.rs index 6cc5a98..c909333 100644 --- a/src/graphmanager/graphview.rs +++ b/src/graphmanager/graphview.rs @@ -582,6 +582,11 @@ impl GraphView { } // Render graph methods + pub fn render_gst(&self) -> String { + let description = String::from("videotestsrc ! videoconvert ! autovideosink"); + description + } + pub fn render_xml(&self, filename: &str) -> anyhow::Result<(), Box> { let mut file = File::create(filename).unwrap(); let mut writer = EmitterConfig::new() diff --git a/src/pipeline.rs b/src/pipeline.rs index e050d47..42fcdc8 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -16,10 +16,15 @@ // along with this program. If not, see . // // SPDX-License-Identifier: GPL-3.0-only +use crate::app::GPSApp; use crate::graphmanager::NodeType; use gst::prelude::*; use gstreamer as gst; +use std::cell::{Cell, RefCell}; use std::error; +use std::fmt; +use std::ops; +use std::rc::{Rc, Weak}; #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct ElementInfo { @@ -38,38 +43,153 @@ impl Default for ElementInfo { } } -#[derive(Debug)] -pub struct Pipeline { - initialized: bool, +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum PipelineState { + Playing, + Paused, + Stopped, } -impl Default for Pipeline { - fn default() -> Pipeline { - Pipeline { initialized: false } +impl fmt::Display for PipelineState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) } } +#[derive(Debug, Clone)] +pub struct Pipeline(Rc); + +// Deref into the contained struct to make usage a bit more ergonomic +impl ops::Deref for Pipeline { + type Target = PipelineInner; + + fn deref(&self) -> &PipelineInner { + &*self.0 + } +} + +#[derive(Debug, Clone)] +pub struct PipelineWeak(Weak); + +impl PipelineWeak { + pub fn upgrade(&self) -> Option { + self.0.upgrade().map(Pipeline) + } +} + +#[derive(Debug)] +pub struct PipelineInner { + initialized: bool, + pipeline: RefCell>, + current_state: Cell, +} + impl Pipeline { pub fn new() -> Result> { gst::init()?; - Ok(Self { initialized: true }) + let pipeline = Pipeline(Rc::new(PipelineInner { + initialized: true, + pipeline: RefCell::new(None), + current_state: Cell::new(PipelineState::Stopped), + })); + + Ok(pipeline) + } + + pub fn create_pipeline(&self, description: &str) -> Result<(), Box> { + println!("Creating pipeline {}", description); + + /* create playbin */ + + let pipeline = gst::parse_launch(&description.to_string())?; + let pipeline = pipeline + .downcast::() + .expect("Couldn't downcast pipeline"); + + //pipeline.set_property_message_forward(true); + + let bus = pipeline.bus().expect("Pipeline had no bus"); + let pipeline_weak = self.downgrade(); + bus.add_watch_local(move |_bus, msg| { + let pipeline = upgrade_weak!(pipeline_weak, glib::Continue(false)); + + pipeline.on_pipeline_message(msg); + + glib::Continue(true) + })?; + + *self.pipeline.borrow_mut() = Some(pipeline); + /* start playing */ + + Ok(()) + } + + pub fn set_state(&self, state: PipelineState) -> Result<(), Box> { + if let Some(pipeline) = self.pipeline.borrow().to_owned() { + match state { + PipelineState::Playing => pipeline.set_state(gst::State::Playing)?, + PipelineState::Paused => pipeline.set_state(gst::State::Paused)?, + PipelineState::Stopped => { + pipeline.set_state(gst::State::Null)?; + gst::StateChangeSuccess::Success + } + }; + self.current_state.set(state); + } + Ok(()) + } + + pub fn state(&self) -> PipelineState { + self.current_state.get() + } + + pub fn downgrade(&self) -> PipelineWeak { + PipelineWeak(Rc::downgrade(&self.0)) + } + + fn on_pipeline_message(&self, msg: &gst::MessageRef) { + use gst::MessageView; + match msg.view() { + MessageView::Error(err) => { + GPSApp::show_error_dialog( + false, + format!( + "Error from {:?}: {} ({:?})", + err.src().map(|s| s.path_string()), + err.error(), + err.debug() + ) + .as_str(), + ); + } + MessageView::Application(msg) => match msg.structure() { + // Here we can send ourselves messages from any thread and show them to the user in + // the UI in case something goes wrong + Some(s) if s.name() == "warning" => { + let text = s.get::<&str>("text").expect("Warning message without text"); + GPSApp::show_error_dialog(false, text); + } + _ => (), + }, + _ => (), + }; } pub fn elements_list() -> Result, Box> { let registry = gst::Registry::get(); let mut elements: Vec = Vec::new(); - let plugins = gst::Registry::get_plugin_list(®istry); + let plugins = gst::Registry::plugin_list(®istry); for plugin in plugins { - let plugin_name = gst::Plugin::get_plugin_name(&plugin); - let features = gst::Registry::get_feature_list_by_plugin(®istry, &plugin_name); + let plugin_name = gst::Plugin::plugin_name(&plugin); + let features = gst::Registry::feature_list_by_plugin(®istry, &plugin_name); for feature in features { let mut element = ElementInfo::default(); if let Ok(factory) = feature.downcast::() { let feature = factory.upcast::(); - element.name = Some(gst::PluginFeature::get_name(&feature).as_str().to_owned()); + element.name = Some(gst::PluginFeature::name(&feature).as_str().to_owned()); element.plugin_name = - Some(gst::Plugin::get_plugin_name(&plugin).as_str().to_owned()); + Some(gst::Plugin::plugin_name(&plugin).as_str().to_owned()); elements.push(element); } } @@ -100,12 +220,12 @@ impl Pipeline { if let Ok(factory) = feature.downcast::() { desc.push_str("Factory details:\n"); desc.push_str("Name:"); - desc.push_str(&factory.get_name()); + desc.push_str(&factory.name()); desc.push('\n'); - let element_keys = factory.get_metadata_keys(); + let element_keys = factory.metadata_keys(); for key in element_keys { - let val = factory.get_metadata(&key); + let val = factory.metadata(&key); if let Some(val) = val { desc.push_str(""); desc.push_str(&key); @@ -115,52 +235,45 @@ impl Pipeline { } } let feature = factory.upcast::(); - let plugin = gst::PluginFeature::get_plugin(&feature); + let plugin = gst::PluginFeature::plugin(&feature); if let Some(plugin) = plugin { desc.push('\n'); desc.push_str("Plugin details:"); desc.push('\n'); desc.push_str("Name:"); desc.push_str(""); - desc.push_str(gst::Plugin::get_plugin_name(&plugin).as_str()); + desc.push_str(gst::Plugin::plugin_name(&plugin).as_str()); desc.push('\n'); desc.push_str("Description:"); desc.push_str(""); - desc.push_str( - >k::glib::markup_escape_text(&plugin.get_description()).to_string(), - ); + desc.push_str(>k::glib::markup_escape_text(&plugin.description()).to_string()); desc.push('\n'); desc.push_str("Filename:"); desc.push_str(""); desc.push_str( >k::glib::markup_escape_text( - &plugin - .get_filename() - .unwrap() - .as_path() - .display() - .to_string(), + &plugin.filename().unwrap().as_path().display().to_string(), ) .to_string(), ); desc.push('\n'); desc.push_str("Version:"); desc.push_str(""); - desc.push_str(>k::glib::markup_escape_text(&plugin.get_version()).to_string()); + desc.push_str(>k::glib::markup_escape_text(&plugin.version()).to_string()); desc.push('\n'); } } Ok(desc) } - pub fn get_pads(element_name: &str, include_on_request: bool) -> (u32, u32) { + pub fn pads(element_name: &str, include_on_request: bool) -> (u32, u32) { let feature = Pipeline::element_feature(element_name).expect("Unable to get feature"); let mut input = 0; let mut output = 0; if let Ok(factory) = feature.downcast::() { - if factory.get_num_pad_templates() > 0 { - let pads = factory.get_static_pad_templates(); + if factory.num_pad_templates() > 0 { + let pads = factory.static_pad_templates(); for pad in pads { if pad.presence() == gst::PadPresence::Always || (include_on_request @@ -179,8 +292,8 @@ impl Pipeline { (input, output) } - pub fn get_element_type(element_name: &str) -> NodeType { - let pads = Pipeline::get_pads(element_name, true); + pub fn element_type(element_name: &str) -> NodeType { + let pads = Pipeline::pads(element_name, true); let mut element_type = NodeType::Source; if pads.0 > 0 { if pads.1 > 0 { @@ -195,3 +308,18 @@ impl Pipeline { element_type } } + +impl Drop for PipelineInner { + fn drop(&mut self) { + // TODO: If a recording is currently running we would like to finish that first + // before quitting the pipeline and shutting down the pipeline. + if let Some(pipeline) = self.pipeline.borrow().to_owned() { + // We ignore any errors here + let _ = pipeline.set_state(gst::State::Null); + + // Remove the message watch from the bus + let bus = pipeline.bus().expect("Pipeline had no bus"); + let _ = bus.remove_watch(); + } + } +}