mirror of
https://gitlab.freedesktop.org/dabrain34/GstPipelineStudio.git
synced 2024-09-27 06:00:07 +00:00
pipeline: add gtk4paintablesink
Add a way to draw whenever possible the video render into the preview box in UI
This commit is contained in:
parent
42e0057829
commit
b84483057b
7 changed files with 166 additions and 11 deletions
84
Cargo.lock
generated
84
Cargo.lock
generated
|
@ -476,6 +476,30 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gst-plugin-gtk4"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f70501fa85dfdbeebecea35d747791351d04266f5c2c4aa23014d9fe74132290"
|
||||||
|
dependencies = [
|
||||||
|
"fragile",
|
||||||
|
"gst-plugin-version-helper",
|
||||||
|
"gstreamer",
|
||||||
|
"gstreamer-base",
|
||||||
|
"gstreamer-video",
|
||||||
|
"gtk4",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gst-plugin-version-helper"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a6a4dd1cb931cc6b49af354a68f21b3aee46b5b07370215d942f3a71542123f"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gst_pipeline_studio"
|
name = "gst_pipeline_studio"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -484,6 +508,7 @@ dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-executor",
|
"futures-executor",
|
||||||
"gettext-rs",
|
"gettext-rs",
|
||||||
|
"gst-plugin-gtk4",
|
||||||
"gstreamer",
|
"gstreamer",
|
||||||
"gtk4",
|
"gtk4",
|
||||||
"log 0.4.14",
|
"log 0.4.14",
|
||||||
|
@ -520,6 +545,33 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer-base"
|
||||||
|
version = "0.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "224f35f36582407caf58ded74854526beeecc23d0cf64b8d1c3e00584ed6863f"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"cfg-if",
|
||||||
|
"glib",
|
||||||
|
"gstreamer",
|
||||||
|
"gstreamer-base-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer-base-sys"
|
||||||
|
version = "0.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a083493c3c340e71fa7c66eebda016e9fafc03eb1b4804cf9b2bad61994b078e"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"gstreamer-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gstreamer-sys"
|
name = "gstreamer-sys"
|
||||||
version = "0.18.0"
|
version = "0.18.0"
|
||||||
|
@ -532,6 +584,38 @@ dependencies = [
|
||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer-video"
|
||||||
|
version = "0.18.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "410c72d885a67aeb7dbfa49c347e6c85d60f54e1cdaf6aadf8b5364892451261"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"cfg-if",
|
||||||
|
"fragile",
|
||||||
|
"futures-channel",
|
||||||
|
"glib",
|
||||||
|
"gstreamer",
|
||||||
|
"gstreamer-base",
|
||||||
|
"gstreamer-video-sys",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gstreamer-video-sys"
|
||||||
|
version = "0.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "255c487bf6dd145e23558eaf1c92ef0946ee1999d22bdadc1e492b463609c4b6"
|
||||||
|
dependencies = [
|
||||||
|
"glib-sys",
|
||||||
|
"gobject-sys",
|
||||||
|
"gstreamer-base-sys",
|
||||||
|
"gstreamer-sys",
|
||||||
|
"libc",
|
||||||
|
"system-deps",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gtk4"
|
name = "gtk4"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
|
|
@ -9,7 +9,8 @@ edition = "2018"
|
||||||
gtk = { version = "0.4.1", package = "gtk4" }
|
gtk = { version = "0.4.1", package = "gtk4" }
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
gettext-rs = {version = "0.7", features = ["gettext-system"]}
|
gettext-rs = {version = "0.7", features = ["gettext-system"]}
|
||||||
gstreamer = "0.18.1"
|
gst = { package = "gstreamer", version = "0.18.1" }
|
||||||
|
gst-plugin-gtk4 = { version = "0.1.0", optional=true }
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
once_cell = "1.7.2"
|
once_cell = "1.7.2"
|
||||||
xml-rs = "0.8.4"
|
xml-rs = "0.8.4"
|
||||||
|
@ -21,3 +22,7 @@ futures-channel = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
futures-executor = "0.3"
|
futures-executor = "0.3"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["gtk4-plugin"]
|
||||||
|
gtk4-plugin = ["gst-plugin-gtk4"]
|
17
src/app.rs
17
src/app.rs
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use glib::SignalHandlerId;
|
use glib::SignalHandlerId;
|
||||||
use glib::Value;
|
use glib::Value;
|
||||||
use gtk::gdk::Rectangle;
|
use gtk::gdk;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::{gio, gio::SimpleAction, glib, graphene};
|
use gtk::{gio, gio::SimpleAction, glib, graphene};
|
||||||
use gtk::{
|
use gtk::{
|
||||||
|
@ -257,7 +257,7 @@ impl GPSApp {
|
||||||
|
|
||||||
if let Some((x, y)) = widget.translate_coordinates(&mainwindow, x, y) {
|
if let Some((x, y)) = widget.translate_coordinates(&mainwindow, x, y) {
|
||||||
let point = graphene::Point::new(x as f32, y as f32);
|
let point = graphene::Point::new(x as f32, y as f32);
|
||||||
pop_menu.set_pointing_to(Some(&Rectangle::new(
|
pop_menu.set_pointing_to(Some(&gdk::Rectangle::new(
|
||||||
point.to_vec2().x() as i32,
|
point.to_vec2().x() as i32,
|
||||||
point.to_vec2().y() as i32,
|
point.to_vec2().y() as i32,
|
||||||
0,
|
0,
|
||||||
|
@ -363,6 +363,19 @@ impl GPSApp {
|
||||||
status_bar.push(status_bar.context_id("Description"), &state.to_string());
|
status_bar.push(status_bar.context_id("Description"), &state.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_app_preview(&self, paintable: &gdk::Paintable) {
|
||||||
|
let picture = gtk::Picture::new();
|
||||||
|
picture.set_paintable(Some(paintable));
|
||||||
|
let box_preview: gtk::Box = self
|
||||||
|
.builder
|
||||||
|
.object("box-preview")
|
||||||
|
.expect("Couldn't get box_preview");
|
||||||
|
while let Some(child) = box_preview.first_child() {
|
||||||
|
box_preview.remove(&child);
|
||||||
|
}
|
||||||
|
box_preview.append(&picture);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build_ui(&self, application: &Application) {
|
pub fn build_ui(&self, application: &Application) {
|
||||||
let drawing_area_window: Viewport = self
|
let drawing_area_window: Viewport = self
|
||||||
.builder
|
.builder
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gstreamer as gst;
|
|
||||||
|
|
||||||
pub fn init() -> Result<()> {
|
pub fn init() -> Result<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -24,7 +24,6 @@ use crate::GPS_INFO;
|
||||||
|
|
||||||
use gst::glib;
|
use gst::glib;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
use gstreamer as gst;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
|
#[derive(Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
|
@ -62,6 +61,13 @@ impl ElementInfo {
|
||||||
gst::Registry::find_feature(®istry, element_name, gst::ElementFactory::static_type())
|
gst::Registry::find_feature(®istry, element_name, gst::ElementFactory::static_type())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn element_update_rank(element_name: &str, rank: gst::Rank) {
|
||||||
|
let feature: Option<gst::PluginFeature> = ElementInfo::element_feature(element_name);
|
||||||
|
if let Some(feature) = feature {
|
||||||
|
feature.set_rank(rank);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn element_description(element_name: &str) -> anyhow::Result<String> {
|
pub fn element_description(element_name: &str) -> anyhow::Result<String> {
|
||||||
let mut desc = String::from("");
|
let mut desc = String::from("");
|
||||||
let feature = ElementInfo::element_feature(element_name)
|
let feature = ElementInfo::element_feature(element_name)
|
||||||
|
@ -102,7 +108,12 @@ impl ElementInfo {
|
||||||
desc.push_str("</b>");
|
desc.push_str("</b>");
|
||||||
desc.push_str(
|
desc.push_str(
|
||||||
>k::glib::markup_escape_text(
|
>k::glib::markup_escape_text(
|
||||||
&plugin.filename().unwrap().as_path().display().to_string(),
|
&plugin
|
||||||
|
.filename()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.as_path()
|
||||||
|
.display()
|
||||||
|
.to_string(),
|
||||||
)
|
)
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
|
@ -208,4 +219,27 @@ impl ElementInfo {
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn search_fo_element(bin: &gst::Bin, element_name: &str) -> Option<gst::Element> {
|
||||||
|
let mut iter = bin.iterate_elements();
|
||||||
|
let element = loop {
|
||||||
|
match iter.next() {
|
||||||
|
Ok(Some(element)) => {
|
||||||
|
if element.is::<gst::Bin>() {
|
||||||
|
let bin = element.dynamic_cast::<gst::Bin>().unwrap();
|
||||||
|
break ElementInfo::search_fo_element(&bin, element_name);
|
||||||
|
} else {
|
||||||
|
GPS_INFO!("Found factory: {}", element.factory().unwrap().name());
|
||||||
|
if element.factory().unwrap().name() == element_name {
|
||||||
|
GPS_INFO!("Found {}", element_name);
|
||||||
|
break Some(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(gst::IteratorError::Resync) => iter.resync(),
|
||||||
|
_ => break None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
element
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ use crate::gps::ElementInfo;
|
||||||
use crate::graphmanager::{PortDirection, PortPresence};
|
use crate::graphmanager::{PortDirection, PortPresence};
|
||||||
|
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
use gstreamer as gst;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialOrd, PartialEq)]
|
#[derive(Debug, PartialOrd, PartialEq)]
|
||||||
pub struct PadInfo {
|
pub struct PadInfo {
|
||||||
|
|
|
@ -19,12 +19,14 @@
|
||||||
|
|
||||||
use crate::app::{AppState, GPSApp, GPSAppWeak};
|
use crate::app::{AppState, GPSApp, GPSAppWeak};
|
||||||
use crate::graphmanager::{GraphView, Node, NodeType, PortDirection, PropertyExt};
|
use crate::graphmanager::{GraphView, Node, NodeType, PortDirection, PropertyExt};
|
||||||
|
|
||||||
|
use crate::gps::ElementInfo;
|
||||||
use crate::logger;
|
use crate::logger;
|
||||||
use crate::GPS_INFO;
|
use crate::GPS_INFO;
|
||||||
|
|
||||||
use gst::glib;
|
use gst::glib;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
use gstreamer as gst;
|
use gtk::gdk;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -80,6 +82,11 @@ impl Pipeline {
|
||||||
pipeline: RefCell::new(None),
|
pipeline: RefCell::new(None),
|
||||||
current_state: Cell::new(PipelineState::Stopped),
|
current_state: Cell::new(PipelineState::Stopped),
|
||||||
}));
|
}));
|
||||||
|
#[cfg(feature = "gtk4-plugin")]
|
||||||
|
{
|
||||||
|
gstgtk4::plugin_register_static().expect("Failed to register gstgtk4 plugin");
|
||||||
|
ElementInfo::element_update_rank("gtk4paintablesink", gst::Rank::Primary);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(pipeline)
|
Ok(pipeline)
|
||||||
}
|
}
|
||||||
|
@ -88,7 +95,7 @@ impl Pipeline {
|
||||||
*self.app.borrow_mut() = Some(app.upgrade().unwrap());
|
*self.app.borrow_mut() = Some(app.upgrade().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_pipeline(&self, description: &str) -> anyhow::Result<gstreamer::Pipeline> {
|
pub fn create_pipeline(&self, description: &str) -> anyhow::Result<gst::Pipeline> {
|
||||||
GPS_INFO!("Creating pipeline {}", description);
|
GPS_INFO!("Creating pipeline {}", description);
|
||||||
|
|
||||||
// Create pipeline from the description
|
// Create pipeline from the description
|
||||||
|
@ -104,6 +111,18 @@ impl Pipeline {
|
||||||
Ok(pipeline.unwrap())
|
Ok(pipeline.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_for_gtk4sink(&self, pipeline: &gst::Pipeline) {
|
||||||
|
let bin = pipeline.clone().dynamic_cast::<gst::Bin>().unwrap();
|
||||||
|
let gtksink = ElementInfo::search_fo_element(&bin, "gtk4paintablesink");
|
||||||
|
if let Some(gtksink) = gtksink {
|
||||||
|
let paintable = gtksink.property::<gdk::Paintable>("paintable");
|
||||||
|
self.app
|
||||||
|
.borrow()
|
||||||
|
.as_ref()
|
||||||
|
.expect("App should be available")
|
||||||
|
.set_app_preview(&paintable);
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn start_pipeline(
|
pub fn start_pipeline(
|
||||||
&self,
|
&self,
|
||||||
graphview: &GraphView,
|
graphview: &GraphView,
|
||||||
|
@ -116,6 +135,7 @@ impl Pipeline {
|
||||||
GPS_ERROR!("Unable to start a pipeline: {}", err);
|
GPS_ERROR!("Unable to start a pipeline: {}", err);
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let bus = pipeline.bus().expect("Pipeline had no bus");
|
let bus = pipeline.bus().expect("Pipeline had no bus");
|
||||||
let pipeline_weak = self.downgrade();
|
let pipeline_weak = self.downgrade();
|
||||||
bus.add_watch_local(move |_bus, msg| {
|
bus.add_watch_local(move |_bus, msg| {
|
||||||
|
@ -123,7 +143,8 @@ impl Pipeline {
|
||||||
pipeline.on_pipeline_message(msg);
|
pipeline.on_pipeline_message(msg);
|
||||||
glib::Continue(true)
|
glib::Continue(true)
|
||||||
})?;
|
})?;
|
||||||
|
pipeline.set_state(gst::State::Ready)?;
|
||||||
|
self.check_for_gtk4sink(&pipeline);
|
||||||
*self.pipeline.borrow_mut() = Some(pipeline);
|
*self.pipeline.borrow_mut() = Some(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue