Commit c81e177c authored by Thiago Sousa Santos's avatar Thiago Sousa Santos Committed by Sebastian Dröge

pbutils: add discoverer APIs

Fixes https://github.com/sdroege/gstreamer-rs/pull/84
parent e6265341
......@@ -11,6 +11,7 @@ members = [
"gstreamer-rtsp-server",
"gstreamer-sdp",
"gstreamer-video",
"gstreamer-pbutils",
"examples",
"tutorials",
]
[options]
girs_dir = "gir-files"
library = "GstPbutils"
version = "1.0"
min_cfg_version = "1.8"
target_path = "gstreamer-pbutils"
work_mode = "normal"
concurrency = "send+sync"
generate_safety_asserts = true
external_libraries = [
"GLib",
"GObject",
"Gst",
]
generate = [
"GstPbutils.DiscovererResult",
"GstPbutils.DiscovererSerializeFlags",
]
manual = [
"GLib.Error",
"GLib.Source",
"GLib.DateTime",
"GLib.Variant",
"GObject.Object",
"Gst.Object",
"Gst.Element",
]
[[object]]
name = "Gst.Toc"
status = "manual"
ref_mode = "ref"
[[object]]
name = "Gst.Caps"
status = "manual"
ref_mode = "ref"
[[object]]
name = "Gst.Message"
status = "manual"
ref_mode = "ref"
[[object]]
name = "Gst.Buffer"
status = "manual"
ref_mode = "ref"
[[object]]
name = "Gst.Event"
status = "manual"
ref_mode = "ref"
[[object]]
name = "Gst.TagList"
status = "manual"
ref_mode = "ref"
[[object]]
name = "Gst.Structure"
status = "manual"
ref_mode = "ref-mut"
[[object]]
name = "Gst.ClockTime"
status = "manual"
conversion_type = "scalar"
[[object]]
name = "GstPbutils.Discoverer"
status = "generate"
trait = false
[[object.function]]
name = "discover_uri_async"
[object.function.return]
bool_return_is_error = "Failed to add URI to list of discovers"
# Manually implemented to use ClockTime
[[object.property]]
name = "timeout"
ignore = true
[[object]]
name = "GstPbutils.DiscovererInfo"
status = "generate"
[[object.function]]
name = "copy"
[object.function.return]
nullable = false
[[object]]
name = "GstPbutils.DiscovererStreamInfo"
status = "generate"
# Not useful
[[object.function]]
name = "list_free"
ignore = true
[[object.function]]
name = "get_stream_type_nick"
[object.function.return]
nullable = false
[[object]]
name = "GstPbutils.DiscovererAudioInfo"
status = "generate"
trait = false
[[object]]
name = "GstPbutils.DiscovererVideoInfo"
status = "generate"
trait = false
# Implement manually to expose as gst::Fraction
[[object.function]]
name = "get_framerate_num"
ignore = true
[[object.function]]
name = "get_framerate_denom"
ignore = true
[[object.function]]
name = "get_par_num"
ignore = true
[[object.function]]
name = "get_par_denom"
ignore = true
[[object]]
name = "GstPbutils.DiscovererSubtitleInfo"
status = "generate"
trait = false
[[object]]
name = "GstPbutils.DiscovererContainerInfo"
status = "generate"
trait = false
This diff is collapsed.
......@@ -9,6 +9,7 @@ gstreamer = { path = "../gstreamer" }
gstreamer-app = { path = "../gstreamer-app" }
gstreamer-audio = { path = "../gstreamer-audio" }
gstreamer-video = { path = "../gstreamer-video" }
gstreamer-pbutils = { path = "../gstreamer-pbutils" }
gstreamer-player = { path = "../gstreamer-player", optional = true }
gstreamer-rtsp = { path = "../gstreamer-rtsp", optional = true }
gstreamer-rtsp-server = { path = "../gstreamer-rtsp-server", optional = true }
......
extern crate gstreamer as gst;
extern crate gstreamer_pbutils as pbutils;
use pbutils::prelude::*;
use pbutils::DiscovererStreamInfo;
use pbutils::DiscovererInfo;
extern crate glib;
extern crate failure;
use failure::Error;
#[macro_use]
extern crate failure_derive;
use std::env;
#[path = "../examples-common.rs"]
mod examples_common;
#[derive(Debug, Fail)]
#[fail(display = "Discoverer error {}", _0)]
struct DiscovererError(&'static str);
fn print_tags(info: &DiscovererInfo) {
println!("Tags:");
let tags = info.get_tags();
match tags {
Some(taglist) => {
println!(" {}", taglist.to_string()); // FIXME use an iterator
}
None => {
println!(" no tags");
}
}
}
fn print_stream_info(stream: &DiscovererStreamInfo) {
println!("Stream: ");
match stream.get_stream_id() {
Some(id) => println!(" Stream id: {}", id),
None => {}
}
let caps_str = match stream.get_caps() {
Some(caps) => caps.to_string(),
None => String::from("--")
};
println!(" Format: {}", caps_str);
}
fn print_discoverer_info(info: &DiscovererInfo) -> Result<(), Error> {
let uri = info.get_uri().ok_or(DiscovererError("URI should not be null"))?;
println!("URI: {}", uri);
println!("Duration: {}", info.get_duration());
print_tags(info);
print_stream_info(&info.get_stream_info().ok_or(DiscovererError("Error while obtaining stream info"))?);
let children = info.get_stream_list();
println!("Children streams:");
for child in children {
print_stream_info(&child);
}
Ok(())
}
fn run_discoverer() -> Result<(), Error> {
gst::init()?;
let args: Vec<_> = env::args().collect();
let uri: &str = if args.len() == 2 {
args[1].as_ref()
} else {
println!("Usage: discoverer uri");
std::process::exit(-1)
};
let timeout: gst::ClockTime = gst::ClockTime::from_seconds(15);
let discoverer = pbutils::Discoverer::new(timeout)?;
let info = discoverer.discover_uri(uri)?;
print_discoverer_info(&info)?;
Ok(())
}
fn example_main() {
match run_discoverer() {
Ok(_) => (),
Err(e) => eprintln!("Error: {}", e)
}
}
fn main() {
// tutorials_common::run is only required to set up the application environent on macOS
// (but not necessary in normal Cocoa applications where this is set up autmatically)
examples_common::run(example_main);
}
......@@ -458,11 +458,15 @@ depending on the circumstances of the error.</doc>
<doc xml:space="preserve">the results #GstDiscovererInfo</doc>
<type name="DiscovererInfo"/>
</parameter>
<parameter name="error" transfer-ownership="none">
<doc xml:space="preserve">#GError, which will be non-NULL if an error
occurred during discovery. You must not
free this #GError, it will be freed by
the discoverer.</doc>
<parameter name="error"
transfer-ownership="none"
nullable="1"
allow-none="1">
<doc xml:space="preserve">#GError, which will be non-NULL
if an error occurred during
discovery. You must not free
this #GError, it will be freed by
the discoverer.</doc>
<type name="GLib.Error"/>
</parameter>
</parameters>
......@@ -1903,7 +1907,10 @@ during the encoding</doc>
<doc xml:space="preserve">a #GstEncodingProfile</doc>
<type name="EncodingProfile" c:type="GstEncodingProfile*"/>
</instance-parameter>
<parameter name="description" transfer-ownership="none">
<parameter name="description"
transfer-ownership="none"
nullable="1"
allow-none="1">
<doc xml:space="preserve">the description to set on the profile</doc>
<type name="utf8" c:type="const gchar*"/>
</parameter>
......@@ -1953,7 +1960,10 @@ internally.</doc>
<doc xml:space="preserve">a #GstEncodingProfile</doc>
<type name="EncodingProfile" c:type="GstEncodingProfile*"/>
</instance-parameter>
<parameter name="name" transfer-ownership="none">
<parameter name="name"
transfer-ownership="none"
nullable="1"
allow-none="1">
<doc xml:space="preserve">the name to set on the profile</doc>
<type name="utf8" c:type="const gchar*"/>
</parameter>
......@@ -2009,7 +2019,10 @@ This is the name that has been set when saving the preset.</doc>
<doc xml:space="preserve">a #GstEncodingProfile</doc>
<type name="EncodingProfile" c:type="GstEncodingProfile*"/>
</instance-parameter>
<parameter name="preset_name" transfer-ownership="none">
<parameter name="preset_name"
transfer-ownership="none"
nullable="1"
allow-none="1">
<doc xml:space="preserve">The name of the preset to use in this @profile.</doc>
<type name="utf8" c:type="const gchar*"/>
</parameter>
......@@ -2028,7 +2041,10 @@ for more about restrictions. Does not apply to #GstEncodingContainerProfile.</do
<doc xml:space="preserve">a #GstEncodingProfile</doc>
<type name="EncodingProfile" c:type="GstEncodingProfile*"/>
</instance-parameter>
<parameter name="restriction" transfer-ownership="full">
<parameter name="restriction"
transfer-ownership="full"
nullable="1"
allow-none="1">
<doc xml:space="preserve">the restriction to apply</doc>
<type name="Gst.Caps" c:type="GstCaps*"/>
</parameter>
......@@ -2132,7 +2148,7 @@ valid for target names).</doc>
<parameters>
<parameter name="filepath" transfer-ownership="none">
<doc xml:space="preserve">The file location to load the #GstEncodingTarget from</doc>
<type name="utf8" c:type="const gchar*"/>
<type name="filename" c:type="gchar*"/>
</parameter>
</parameters>
</function>
......@@ -2259,7 +2275,7 @@ count.</doc>
</instance-parameter>
<parameter name="filepath" transfer-ownership="none">
<doc xml:space="preserve">the location to store the @target at.</doc>
<type name="utf8" c:type="const gchar*"/>
<type name="filename" c:type="gchar*"/>
</parameter>
</parameters>
</method>
......
[package]
name = "gstreamer-pbutils"
version = "0.11.0"
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
categories = ["api-bindings", "multimedia"]
description = "Rust bindings for GStreamer Base Utils library"
repository = "https://github.com/sdroege/gstreamer-rs"
license = "MIT/Apache-2.0"
readme = "README.md"
homepage = "https://gstreamer.freedesktop.org"
documentation = "https://sdroege.github.io/rustdoc/gstreamer/gstreamer_pbutils"
keywords = ["gstreamer", "multimedia", "audio", "pbutils", "gnome"]
build = "build.rs"
[dependencies]
bitflags = "1.0"
libc = "0.2"
glib-sys = { git = "https://github.com/gtk-rs/sys" }
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
gstreamer-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
gstreamer-pbutils-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] }
glib = { git = "https://github.com/gtk-rs/glib" }
gstreamer = { path = "../gstreamer" }
[build-dependencies.rustdoc-stripper]
version = "0.1"
optional = true
[features]
v1_10 = ["gstreamer-sys/v1_10", "gstreamer-pbutils-sys/v1_10"]
v1_12 = ["gstreamer-sys/v1_12", "gstreamer-pbutils-sys/v1_12", "v1_10"]
embed-lgpl-docs = ["rustdoc-stripper"]
purge-lgpl-docs = ["rustdoc-stripper"]
dox = ["gstreamer-pbutils-sys/dox"]
default-features = []
[badges]
travis-ci = { repository = "sdroege/gstreamer-rs", branch = "master" }
fn main() {
manage_docs();
}
#[cfg(any(feature = "embed-lgpl-docs", feature = "purge-lgpl-docs"))]
fn manage_docs() {
extern crate stripper_lib;
use std::io;
let path = "src";
let ignores: &[&str] = &[];
stripper_lib::loop_over_files(
path.as_ref(),
&mut |w, s| stripper_lib::strip_comments(w, s, &mut io::sink(), true),
&ignores,
false,
);
#[cfg(feature = "embed-lgpl-docs")]
{
let docs = include_str!("../docs/gstreamer-pbutils/docs.md");
let mut infos = stripper_lib::parse_cmts(docs.lines(), true);
stripper_lib::loop_over_files(
path.as_ref(),
&mut |w, s| stripper_lib::regenerate_comments(w, s, &mut infos, true, true),
&ignores,
false,
);
}
}
#[cfg(not(any(feature = "embed-lgpl-docs", feature = "purge-lgpl-docs")))]
fn manage_docs() {}
// This file was generated by gir (https://github.com/gtk-rs/gir @ bd67955)
// from gir-files (https://github.com/gtk-rs/gir-files @ ???)
// DO NOT EDIT
use DiscovererInfo;
use Error;
use ffi;
use glib;
use glib::signal::SignalHandlerId;
use glib::signal::connect;
use glib::translate::*;
use glib_ffi;
use gobject_ffi;
use gst;
use gst_ffi;
use std::boxed::Box as Box_;
use std::mem;
use std::mem::transmute;
use std::ptr;
glib_wrapper! {
pub struct Discoverer(Object<ffi::GstDiscoverer, ffi::GstDiscovererClass>);
match fn {
get_type => || ffi::gst_discoverer_get_type(),
}
}
impl Discoverer {
pub fn new(timeout: gst::ClockTime) -> Result<Discoverer, Error> {
assert_initialized_main_thread!();
unsafe {
let mut error = ptr::null_mut();
let ret = ffi::gst_discoverer_new(timeout.to_glib(), &mut error);
if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) }
}
}
pub fn discover_uri(&self, uri: &str) -> Result<DiscovererInfo, Error> {
unsafe {
let mut error = ptr::null_mut();
let ret = ffi::gst_discoverer_discover_uri(self.to_glib_none().0, uri.to_glib_none().0, &mut error);
if error.is_null() { Ok(from_glib_full(ret)) } else { Err(from_glib_full(error)) }
}
}
pub fn discover_uri_async(&self, uri: &str) -> Result<(), glib::error::BoolError> {
unsafe {
glib::error::BoolError::from_glib(ffi::gst_discoverer_discover_uri_async(self.to_glib_none().0, uri.to_glib_none().0), "Failed to add URI to list of discovers")
}
}
pub fn start(&self) {
unsafe {
ffi::gst_discoverer_start(self.to_glib_none().0);
}
}
pub fn stop(&self) {
unsafe {
ffi::gst_discoverer_stop(self.to_glib_none().0);
}
}
pub fn connect_discovered<F: Fn(&Discoverer, &DiscovererInfo, &Option<Error>) + Send + Sync + 'static>(&self, f: F) -> SignalHandlerId {
unsafe {
let f: Box_<Box_<Fn(&Discoverer, &DiscovererInfo, &Option<Error>) + Send + Sync + 'static>> = Box_::new(Box_::new(f));
connect(self.to_glib_none().0, "discovered",
transmute(discovered_trampoline as usize), Box_::into_raw(f) as *mut _)
}
}
pub fn connect_finished<F: Fn(&Discoverer) + Send + Sync + 'static>(&self, f: F) -> SignalHandlerId {
unsafe {
let f: Box_<Box_<Fn(&Discoverer) + Send + Sync + 'static>> = Box_::new(Box_::new(f));
connect(self.to_glib_none().0, "finished",
transmute(finished_trampoline as usize), Box_::into_raw(f) as *mut _)
}
}
pub fn connect_source_setup<F: Fn(&Discoverer, &gst::Element) + Send + Sync + 'static>(&self, f: F) -> SignalHandlerId {
unsafe {
let f: Box_<Box_<Fn(&Discoverer, &gst::Element) + Send + Sync + 'static>> = Box_::new(Box_::new(f));
connect(self.to_glib_none().0, "source-setup",
transmute(source_setup_trampoline as usize), Box_::into_raw(f) as *mut _)
}
}
pub fn connect_starting<F: Fn(&Discoverer) + Send + Sync + 'static>(&self, f: F) -> SignalHandlerId {
unsafe {
let f: Box_<Box_<Fn(&Discoverer) + Send + Sync + 'static>> = Box_::new(Box_::new(f));
connect(self.to_glib_none().0, "starting",
transmute(starting_trampoline as usize), Box_::into_raw(f) as *mut _)
}
}
}
unsafe impl Send for Discoverer {}
unsafe impl Sync for Discoverer {}
unsafe extern "C" fn discovered_trampoline(this: *mut ffi::GstDiscoverer, info: *mut ffi::GstDiscovererInfo, error: *mut glib_ffi::GError, f: glib_ffi::gpointer) {
let f: &&(Fn(&Discoverer, &DiscovererInfo, &Option<Error>) + Send + Sync + 'static) = transmute(f);
f(&from_glib_borrow(this), &from_glib_borrow(info), &from_glib_borrow(error))
}
unsafe extern "C" fn finished_trampoline(this: *mut ffi::GstDiscoverer, f: glib_ffi::gpointer) {
let f: &&(Fn(&Discoverer) + Send + Sync + 'static) = transmute(f);
f(&from_glib_borrow(this))
}
unsafe extern "C" fn source_setup_trampoline(this: *mut ffi::GstDiscoverer, source: *mut gst_ffi::GstElement, f: glib_ffi::gpointer) {
let f: &&(Fn(&Discoverer, &gst::Element) + Send + Sync + 'static) = transmute(f);
f(&from_glib_borrow(this), &from_glib_borrow(source))
}
unsafe extern "C" fn starting_trampoline(this: *mut ffi::GstDiscoverer, f: glib_ffi::gpointer) {
let f: &&(Fn(&Discoverer) + Send + Sync + 'static) = transmute(f);
f(&from_glib_borrow(this))
}
// This file was generated by gir (https://github.com/gtk-rs/gir @ bd67955)
// from gir-files (https://github.com/gtk-rs/gir-files @ ???)
// DO NOT EDIT
use DiscovererStreamInfo;
use ffi;
use glib::translate::*;
use glib_ffi;
use gobject_ffi;
use std::mem;
use std::ptr;
glib_wrapper! {
pub struct DiscovererAudioInfo(Object<ffi::GstDiscovererAudioInfo>): DiscovererStreamInfo;
match fn {
get_type => || ffi::gst_discoverer_audio_info_get_type(),
}
}
impl DiscovererAudioInfo {
pub fn get_bitrate(&self) -> u32 {
unsafe {
ffi::gst_discoverer_audio_info_get_bitrate(self.to_glib_none().0)
}
}
pub fn get_channels(&self) -> u32 {
unsafe {
ffi::gst_discoverer_audio_info_get_channels(self.to_glib_none().0)
}
}
pub fn get_depth(&self) -> u32 {
unsafe {
ffi::gst_discoverer_audio_info_get_depth(self.to_glib_none().0)
}
}
pub fn get_language(&self) -> Option<String> {
unsafe {
from_glib_none(ffi::gst_discoverer_audio_info_get_language(self.to_glib_none().0))
}
}
pub fn get_max_bitrate(&self) -> u32 {
unsafe {
ffi::gst_discoverer_audio_info_get_max_bitrate(self.to_glib_none().0)
}
}
pub fn get_sample_rate(&self) -> u32 {
unsafe {
ffi::gst_discoverer_audio_info_get_sample_rate(self.to_glib_none().0)
}
}
}
unsafe impl Send for DiscovererAudioInfo {}
unsafe impl Sync for DiscovererAudioInfo {}
// This file was generated by gir (https://github.com/gtk-rs/gir @ bd67955)
// from gir-files (https://github.com/gtk-rs/gir-files @ ???)
// DO NOT EDIT
use DiscovererStreamInfo;
use ffi;
use glib::translate::*;
use glib_ffi;
use gobject_ffi;
use std::mem;
use std::ptr;
glib_wrapper! {
pub struct DiscovererContainerInfo(Object<ffi::GstDiscovererContainerInfo>): DiscovererStreamInfo;
match fn {
get_type => || ffi::gst_discoverer_container_info_get_type(),
}
}
impl DiscovererContainerInfo {
pub fn get_streams(&self) -> Vec<DiscovererStreamInfo> {
unsafe {
FromGlibPtrContainer::from_glib_full(ffi::gst_discoverer_container_info_get_streams(self.to_glib_none().0))
}
}
}
unsafe impl Send for DiscovererContainerInfo {}
unsafe impl Sync for DiscovererContainerInfo {}
// This file was generated by gir (https://github.com/gtk-rs/gir @ bd67955)
// from gir-files (https://github.com/gtk-rs/gir-files @ ???)
// DO NOT EDIT
use DiscovererResult;
use DiscovererSerializeFlags;
use DiscovererStreamInfo;
use ffi;
use glib;
use glib::object::IsA;
use glib::translate::*;
use glib_ffi;
use gobject_ffi;
use gst;
use std::mem;
use std::ptr;
glib_wrapper! {
pub struct DiscovererInfo(Object<ffi::GstDiscovererInfo>);
match fn {
get_type => || ffi::gst_discoverer_info_get_type(),
}
}
impl DiscovererInfo {
pub fn from_variant(variant: &glib::Variant) -> Option<DiscovererInfo> {
assert_initialized_main_thread!();
unsafe {
from_glib_full(ffi::gst_discoverer_info_from_variant(variant.to_glib_none().0))
}
}
}
unsafe impl Send for DiscovererInfo {}
unsafe impl Sync for DiscovererInfo {}
pub trait DiscovererInfoExt {
fn copy(&self) -> DiscovererInfo;
fn get_audio_streams(&self) -> Vec<DiscovererStreamInfo>;
fn get_container_streams(&self) -> Vec<DiscovererStreamInfo>;
fn get_duration(&self) -> gst::ClockTime;
fn get_misc(&self) -> Option<gst::Structure>;
fn get_missing_elements_installer_details(&self) -> Vec<String>;
fn get_result(&self) -> DiscovererResult;
fn get_seekable(&self) -> bool;
fn get_stream_info(&self) -> Option<DiscovererStreamInfo>;
fn get_stream_list(&self) -> Vec<DiscovererStreamInfo>;
fn get_streams(&self, streamtype: glib::types::Type) -> Vec<DiscovererStreamInfo>;
fn get_subtitle_streams(&self) -> Vec<DiscovererStreamInfo>;
fn get_tags(&self) -> Option<gst::TagList>;
fn get_toc(&self) -> Option<gst::Toc>;
fn get_uri(&self) -> Option<String>;
fn get_video_streams(&self) -> Vec<DiscovererStreamInfo>;
fn to_variant(&self, flags: DiscovererSerializeFlags) -> Option<glib::Variant>;
}
impl<O: IsA<DiscovererInfo>> DiscovererInfoExt for O {
fn copy(&self) -> DiscovererInfo {
unsafe {
from_glib_full(ffi::gst_discoverer_info_copy(self.to_glib_none().0))
}
}
fn get_audio_streams(&self) -> Vec<DiscovererStreamInfo> {
unsafe {
FromGlibPtrContainer::from_glib_full(ffi::gst_discoverer_info_get_audio_streams(self.to_glib_none().0))