pipeline: implement parse launch playback

Can now play/pause/stop a playback from
a parse launch description GST pipeline.

rename getters in pipeline.rs
This commit is contained in:
Stéphane Cerveau 2021-12-03 14:47:20 +01:00
parent fe93db3458
commit 46e4ad726a
5 changed files with 277 additions and 243 deletions

237
Cargo.lock generated
View file

@ -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"

View file

@ -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"
xml-rs = "0.8.4"

View file

@ -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::<gtk::Application>()
.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,

View file

@ -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<dyn error::Error>> {
let mut file = File::create(filename).unwrap();
let mut writer = EmitterConfig::new()

View file

@ -16,10 +16,15 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// 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<PipelineInner>);
// 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<PipelineInner>);
impl PipelineWeak {
pub fn upgrade(&self) -> Option<Pipeline> {
self.0.upgrade().map(Pipeline)
}
}
#[derive(Debug)]
pub struct PipelineInner {
initialized: bool,
pipeline: RefCell<Option<gst::Pipeline>>,
current_state: Cell<PipelineState>,
}
impl Pipeline {
pub fn new() -> Result<Self, Box<dyn error::Error>> {
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<dyn error::Error>> {
println!("Creating pipeline {}", description);
/* create playbin */
let pipeline = gst::parse_launch(&description.to_string())?;
let pipeline = pipeline
.downcast::<gst::Pipeline>()
.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<dyn error::Error>> {
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<Vec<ElementInfo>, Box<dyn error::Error>> {
let registry = gst::Registry::get();
let mut elements: Vec<ElementInfo> = Vec::new();
let plugins = gst::Registry::get_plugin_list(&registry);
let plugins = gst::Registry::plugin_list(&registry);
for plugin in plugins {
let plugin_name = gst::Plugin::get_plugin_name(&plugin);
let features = gst::Registry::get_feature_list_by_plugin(&registry, &plugin_name);
let plugin_name = gst::Plugin::plugin_name(&plugin);
let features = gst::Registry::feature_list_by_plugin(&registry, &plugin_name);
for feature in features {
let mut element = ElementInfo::default();
if let Ok(factory) = feature.downcast::<gst::ElementFactory>() {
let feature = factory.upcast::<gst::PluginFeature>();
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::<gst::ElementFactory>() {
desc.push_str("<b>Factory details:</b>\n");
desc.push_str("<b>Name:</b>");
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("<b>");
desc.push_str(&key);
@ -115,52 +235,45 @@ impl Pipeline {
}
}
let feature = factory.upcast::<gst::PluginFeature>();
let plugin = gst::PluginFeature::get_plugin(&feature);
let plugin = gst::PluginFeature::plugin(&feature);
if let Some(plugin) = plugin {
desc.push('\n');
desc.push_str("<b>Plugin details:</b>");
desc.push('\n');
desc.push_str("<b>Name:");
desc.push_str("</b>");
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("<b>Description:");
desc.push_str("</b>");
desc.push_str(
&gtk::glib::markup_escape_text(&plugin.get_description()).to_string(),
);
desc.push_str(&gtk::glib::markup_escape_text(&plugin.description()).to_string());
desc.push('\n');
desc.push_str("<b>Filename:");
desc.push_str("</b>");
desc.push_str(
&gtk::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("<b>Version:");
desc.push_str("</b>");
desc.push_str(&gtk::glib::markup_escape_text(&plugin.get_version()).to_string());
desc.push_str(&gtk::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::<gst::ElementFactory>() {
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();
}
}
}