2022-01-18 15:03:34 +00:00
|
|
|
// element.rs
|
|
|
|
//
|
|
|
|
// Copyright 2022 Stéphane Cerveau <scerveau@collabora.com>
|
|
|
|
//
|
2022-02-09 10:28:59 +00:00
|
|
|
// This file is part of GstPipelineStudio
|
2022-01-18 15:03:34 +00:00
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
|
|
|
|
use crate::gps::PadInfo;
|
|
|
|
use crate::graphmanager::{NodeType, PortDirection, PortPresence};
|
|
|
|
use crate::logger;
|
|
|
|
use crate::GPS_INFO;
|
|
|
|
|
|
|
|
use gst::glib;
|
|
|
|
use gst::prelude::*;
|
|
|
|
use std::collections::HashMap;
|
2022-09-06 10:38:22 +00:00
|
|
|
use std::fmt::Write as _;
|
2022-01-18 15:03:34 +00:00
|
|
|
|
2022-01-19 15:03:19 +00:00
|
|
|
#[derive(Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
|
2022-01-18 15:03:34 +00:00
|
|
|
pub struct ElementInfo {
|
2022-01-19 15:03:19 +00:00
|
|
|
pub name: String,
|
|
|
|
plugin_name: String,
|
2022-01-18 15:03:34 +00:00
|
|
|
rank: i32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ElementInfo {
|
|
|
|
pub fn elements_list() -> anyhow::Result<Vec<ElementInfo>> {
|
|
|
|
let registry = gst::Registry::get();
|
|
|
|
let mut elements: Vec<ElementInfo> = Vec::new();
|
2022-01-19 11:24:13 +00:00
|
|
|
let plugins = gst::Registry::plugins(®istry);
|
2022-01-18 15:03:34 +00:00
|
|
|
for plugin in plugins {
|
|
|
|
let plugin_name = gst::Plugin::plugin_name(&plugin);
|
2022-01-19 11:24:13 +00:00
|
|
|
let features = gst::Registry::features_by_plugin(®istry, &plugin_name);
|
2022-01-18 15:03:34 +00:00
|
|
|
for feature in features {
|
|
|
|
let mut element = ElementInfo::default();
|
|
|
|
if let Ok(factory) = feature.downcast::<gst::ElementFactory>() {
|
|
|
|
let feature = factory.upcast::<gst::PluginFeature>();
|
|
|
|
|
2022-01-19 15:03:19 +00:00
|
|
|
element.name = gst::PluginFeature::name(&feature).as_str().to_owned();
|
|
|
|
element.plugin_name = gst::Plugin::plugin_name(&plugin).as_str().to_owned();
|
2022-01-18 15:03:34 +00:00
|
|
|
elements.push(element);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
elements.sort();
|
|
|
|
Ok(elements)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn element_feature(element_name: &str) -> Option<gst::PluginFeature> {
|
|
|
|
let registry = gst::Registry::get();
|
|
|
|
gst::Registry::find_feature(®istry, element_name, gst::ElementFactory::static_type())
|
|
|
|
}
|
|
|
|
|
2022-01-28 14:24:30 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-18 15:03:34 +00:00
|
|
|
pub fn element_description(element_name: &str) -> anyhow::Result<String> {
|
|
|
|
let mut desc = String::from("");
|
|
|
|
let feature = ElementInfo::element_feature(element_name)
|
|
|
|
.ok_or_else(|| glib::bool_error!("Failed get element feature"))?;
|
2022-01-31 12:37:03 +00:00
|
|
|
let rank = feature.rank();
|
2022-01-18 15:03:34 +00:00
|
|
|
if let Ok(factory) = feature.downcast::<gst::ElementFactory>() {
|
|
|
|
desc.push_str("<b>Factory details:</b>\n");
|
2022-01-31 12:37:03 +00:00
|
|
|
desc.push_str("<b>Rank:</b>");
|
2022-09-06 10:38:22 +00:00
|
|
|
let _ = write!(desc, "{:?}", rank);
|
2022-01-31 12:37:03 +00:00
|
|
|
desc.push('\n');
|
2022-01-18 15:03:34 +00:00
|
|
|
desc.push_str("<b>Name:</b>");
|
|
|
|
desc.push_str(&factory.name());
|
|
|
|
desc.push('\n');
|
|
|
|
|
|
|
|
let element_keys = factory.metadata_keys();
|
|
|
|
for key in element_keys {
|
|
|
|
let val = factory.metadata(&key);
|
|
|
|
if let Some(val) = val {
|
|
|
|
desc.push_str("<b>");
|
|
|
|
desc.push_str(&key);
|
|
|
|
desc.push_str("</b>:");
|
2022-09-06 10:38:22 +00:00
|
|
|
desc.push_str(>k::glib::markup_escape_text(val));
|
2022-01-18 15:03:34 +00:00
|
|
|
desc.push('\n');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let feature = factory.upcast::<gst::PluginFeature>();
|
|
|
|
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::plugin_name(&plugin).as_str());
|
|
|
|
desc.push('\n');
|
|
|
|
desc.push_str("<b>Description:");
|
|
|
|
desc.push_str("</b>");
|
2022-09-06 10:38:22 +00:00
|
|
|
desc.push_str(>k::glib::markup_escape_text(&plugin.description()));
|
2022-01-18 15:03:34 +00:00
|
|
|
desc.push('\n');
|
|
|
|
desc.push_str("<b>Filename:");
|
|
|
|
desc.push_str("</b>");
|
2022-09-06 10:38:22 +00:00
|
|
|
desc.push_str(>k::glib::markup_escape_text(
|
|
|
|
&plugin
|
|
|
|
.filename()
|
|
|
|
.unwrap_or_default()
|
|
|
|
.as_path()
|
|
|
|
.display()
|
|
|
|
.to_string(),
|
|
|
|
));
|
2022-01-18 15:03:34 +00:00
|
|
|
desc.push('\n');
|
|
|
|
desc.push_str("<b>Version:");
|
|
|
|
desc.push_str("</b>");
|
2022-09-06 10:38:22 +00:00
|
|
|
desc.push_str(>k::glib::markup_escape_text(&plugin.version()));
|
2022-01-18 15:03:34 +00:00
|
|
|
desc.push('\n');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(desc)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn element_type(element_name: &str) -> NodeType {
|
|
|
|
let (inputs, outputs) = PadInfo::pads(element_name, true);
|
|
|
|
let mut element_type = NodeType::Source;
|
|
|
|
if !inputs.is_empty() {
|
|
|
|
if !outputs.is_empty() {
|
|
|
|
element_type = NodeType::Transform;
|
|
|
|
} else {
|
|
|
|
element_type = NodeType::Sink;
|
|
|
|
}
|
|
|
|
} else if !outputs.is_empty() {
|
|
|
|
element_type = NodeType::Source;
|
|
|
|
}
|
|
|
|
|
|
|
|
element_type
|
|
|
|
}
|
2022-01-20 17:18:52 +00:00
|
|
|
pub fn element_property(element_name: &str, property_name: &str) -> anyhow::Result<String> {
|
|
|
|
let feature = ElementInfo::element_feature(element_name).expect("Unable to get feature");
|
2022-01-18 15:03:34 +00:00
|
|
|
|
2022-01-20 17:18:52 +00:00
|
|
|
let factory = feature
|
|
|
|
.downcast::<gst::ElementFactory>()
|
|
|
|
.expect("Unable to get the factory from the feature");
|
2022-11-29 08:42:12 +00:00
|
|
|
let element = factory.create().build()?;
|
2022-01-20 17:18:52 +00:00
|
|
|
let value = element
|
2022-11-29 08:42:12 +00:00
|
|
|
.property_value(property_name)
|
|
|
|
.transform::<String>()
|
|
|
|
.expect("Unable to transform to string")
|
|
|
|
.get::<String>()
|
2022-01-20 17:18:52 +00:00
|
|
|
.unwrap_or_default();
|
|
|
|
Ok(value)
|
2022-01-18 15:03:34 +00:00
|
|
|
}
|
|
|
|
|
2022-01-20 17:18:52 +00:00
|
|
|
pub fn element_properties(
|
|
|
|
element_name: &str,
|
|
|
|
) -> anyhow::Result<HashMap<String, glib::ParamSpec>> {
|
2022-01-18 15:03:34 +00:00
|
|
|
let mut properties_list = HashMap::new();
|
|
|
|
let feature = ElementInfo::element_feature(element_name).expect("Unable to get feature");
|
|
|
|
|
|
|
|
let factory = feature
|
|
|
|
.downcast::<gst::ElementFactory>()
|
|
|
|
.expect("Unable to get the factory from the feature");
|
2022-11-29 08:42:12 +00:00
|
|
|
let element = factory.create().build()?;
|
2022-01-18 15:03:34 +00:00
|
|
|
let params = element.class().list_properties();
|
|
|
|
|
2022-01-19 11:24:13 +00:00
|
|
|
for param in params.iter() {
|
2022-11-29 08:42:12 +00:00
|
|
|
GPS_INFO!("Property_name {}", param.name());
|
|
|
|
if param.flags().contains(glib::ParamFlags::READABLE) {
|
|
|
|
match element.property_value(param.name()).transform::<String>() {
|
|
|
|
Ok(value) => {
|
|
|
|
GPS_INFO!(
|
|
|
|
"Property_name {}={} type={:?}",
|
|
|
|
param.name(),
|
|
|
|
value.get::<String>().unwrap_or_default(),
|
|
|
|
param.type_()
|
|
|
|
);
|
|
|
|
properties_list.insert(String::from(param.name()), param.clone());
|
|
|
|
}
|
|
|
|
Err(_e) => {
|
|
|
|
GPS_ERROR!("Unable to convert the param {} to string ", param.name())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
GPS_ERROR!("The param {} is not readable", param.name())
|
|
|
|
}
|
2022-01-18 15:03:34 +00:00
|
|
|
}
|
|
|
|
Ok(properties_list)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn element_is_uri_src_handler(element_name: &str) -> bool {
|
|
|
|
let feature = ElementInfo::element_feature(element_name).expect("Unable to get feature");
|
|
|
|
|
|
|
|
let factory = feature
|
|
|
|
.downcast::<gst::ElementFactory>()
|
|
|
|
.expect("Unable to get the factory from the feature");
|
|
|
|
let element = factory
|
2022-11-29 08:42:12 +00:00
|
|
|
.create()
|
|
|
|
.build()
|
2022-01-18 15:03:34 +00:00
|
|
|
.expect("Unable to create an element from the feature");
|
|
|
|
match element.dynamic_cast::<gst::URIHandler>() {
|
|
|
|
Ok(uri_handler) => uri_handler.uri_type() == gst::URIType::Src,
|
|
|
|
Err(_e) => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-13 14:53:36 +00:00
|
|
|
pub fn element_is_capsfilter(element_name: &str) -> bool {
|
|
|
|
matches!(element_name, "capsfilter")
|
|
|
|
}
|
|
|
|
|
2022-01-24 13:28:42 +00:00
|
|
|
pub fn element_supports_new_pad_request(
|
|
|
|
element_name: &str,
|
|
|
|
direction: PortDirection,
|
|
|
|
) -> Option<PadInfo> {
|
2022-01-18 15:03:34 +00:00
|
|
|
let (inputs, outputs) = PadInfo::pads(element_name, true);
|
|
|
|
if direction == PortDirection::Input {
|
|
|
|
for input in inputs {
|
|
|
|
if input.presence() == PortPresence::Sometimes {
|
2022-01-24 13:28:42 +00:00
|
|
|
return Some(input);
|
2022-01-18 15:03:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if direction == PortDirection::Output {
|
|
|
|
for output in outputs {
|
|
|
|
if output.presence() == PortPresence::Sometimes {
|
2022-01-24 13:28:42 +00:00
|
|
|
return Some(output);
|
2022-01-18 15:03:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
GPS_ERROR!("Port direction unknown");
|
|
|
|
}
|
2022-01-24 13:28:42 +00:00
|
|
|
None
|
2022-01-18 15:03:34 +00:00
|
|
|
}
|
2022-01-28 14:24:30 +00:00
|
|
|
|
2022-02-01 10:46:39 +00:00
|
|
|
pub fn search_fo_element(bin: &gst::Bin, element_name: &str) -> Vec<gst::Element> {
|
2022-01-28 14:24:30 +00:00
|
|
|
let mut iter = bin.iterate_elements();
|
2022-02-01 10:46:39 +00:00
|
|
|
let mut elements: Vec<gst::Element> = Vec::new();
|
2022-09-06 10:38:22 +00:00
|
|
|
elements = loop {
|
2022-01-28 14:24:30 +00:00
|
|
|
match iter.next() {
|
|
|
|
Ok(Some(element)) => {
|
|
|
|
if element.is::<gst::Bin>() {
|
|
|
|
let bin = element.dynamic_cast::<gst::Bin>().unwrap();
|
2022-02-01 10:46:39 +00:00
|
|
|
let mut bin_elements = ElementInfo::search_fo_element(&bin, element_name);
|
|
|
|
elements.append(&mut bin_elements);
|
2022-01-28 14:24:30 +00:00
|
|
|
} else {
|
|
|
|
GPS_INFO!("Found factory: {}", element.factory().unwrap().name());
|
2022-02-04 16:34:56 +00:00
|
|
|
if element.factory().unwrap().name() == element_name
|
|
|
|
|| element_name.is_empty()
|
|
|
|
{
|
2022-01-28 14:24:30 +00:00
|
|
|
GPS_INFO!("Found {}", element_name);
|
2022-02-01 10:46:39 +00:00
|
|
|
elements.push(element);
|
2022-01-28 14:24:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(gst::IteratorError::Resync) => iter.resync(),
|
2022-02-01 10:46:39 +00:00
|
|
|
_ => break elements,
|
2022-01-28 14:24:30 +00:00
|
|
|
}
|
|
|
|
};
|
2022-02-01 10:46:39 +00:00
|
|
|
elements
|
2022-01-28 14:24:30 +00:00
|
|
|
}
|
2022-01-18 15:03:34 +00:00
|
|
|
}
|