diff --git a/src/lib.rs b/src/lib.rs index fc5981ef..3a222962 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,8 @@ pub mod utils; pub mod error; pub mod buffer; pub mod adapter; +#[macro_use] +pub mod plugin; pub mod rssource; pub mod rssink; pub mod rsfilesrc; @@ -41,241 +43,76 @@ pub mod rsfilesink; pub mod rsdemuxer; pub mod flvdemux; -use utils::*; +use plugin::*; +use rssource::*; use rsfilesrc::FileSrc; use rshttpsrc::HttpSrc; +use rssink::*; use rsfilesink::FileSink; +use rsdemuxer::*; use flvdemux::FlvDemux; -use std::os::raw::c_void; -use libc::c_char; -use std::ffi::CString; - -unsafe fn source_register(plugin: *const c_void, - name: &str, - long_name: &str, - description: &str, - classification: &str, - author: &str, - rank: i32, - create_instance: *const c_void, - protocols: &str, - push_only: bool) { - - extern "C" { - fn gst_rs_source_register(plugin: *const c_void, - name: *const c_char, - long_name: *const c_char, - description: *const c_char, - classification: *const c_char, - author: *const c_char, - rank: i32, - create_instance: *const c_void, - protocols: *const c_char, - push_only: GBoolean) - -> GBoolean; - } - - let cname = CString::new(name).unwrap(); - let clong_name = CString::new(long_name).unwrap(); - let cdescription = CString::new(description).unwrap(); - let cclassification = CString::new(classification).unwrap(); - let cauthor = CString::new(author).unwrap(); - let cprotocols = CString::new(protocols).unwrap(); - - gst_rs_source_register(plugin, - cname.as_ptr(), - clong_name.as_ptr(), - cdescription.as_ptr(), - cclassification.as_ptr(), - cauthor.as_ptr(), - rank, - create_instance, - cprotocols.as_ptr(), - GBoolean::from_bool(push_only)); - -} - -unsafe fn sources_register(plugin: *const c_void) -> GBoolean { +fn plugin_init(plugin: &Plugin) -> bool { source_register(plugin, - "rsfilesrc", - "File Source", - "Reads local files", - "Source/File", - "Sebastian Dröge ", - 256 + 100, - FileSrc::new_boxed as *const c_void, - "file", - false); + &SourceInfo { + name: "rsfilesrc", + long_name: "File Source", + description: "Reads local files", + classification: "Source/File", + author: "Sebastian Dröge ", + rank: 256 + 100, + create_instance: FileSrc::new_boxed, + protocols: "file", + push_only: false, + }); source_register(plugin, - "rshttpsrc", - "HTTP Source", - "Read HTTP/HTTPS files", - "Source/Network/HTTP", - "Sebastian Dröge ", - 256 + 100, - HttpSrc::new_boxed as *const c_void, - "http:https", - true); + &SourceInfo { + name: "rshttpsrc", + long_name: "HTTP Source", + description: "Reads HTTP/HTTPS streams", + classification: "Source/Network/HTTP", + author: "Sebastian Dröge ", + rank: 256 + 100, + create_instance: HttpSrc::new_boxed, + protocols: "http:https", + push_only: true, + }); - GBoolean::True -} - -unsafe fn sink_register(plugin: *const c_void, - name: &str, - long_name: &str, - description: &str, - classification: &str, - author: &str, - rank: i32, - create_instance: *const c_void, - protocols: &str) { - extern "C" { - fn gst_rs_sink_register(plugin: *const c_void, - name: *const c_char, - long_name: *const c_char, - description: *const c_char, - classification: *const c_char, - author: *const c_char, - rank: i32, - create_instance: *const c_void, - protocols: *const c_char) - -> GBoolean; - } - - let cname = CString::new(name).unwrap(); - let clong_name = CString::new(long_name).unwrap(); - let cdescription = CString::new(description).unwrap(); - let cclassification = CString::new(classification).unwrap(); - let cauthor = CString::new(author).unwrap(); - let cprotocols = CString::new(protocols).unwrap(); - - gst_rs_sink_register(plugin, - cname.as_ptr(), - clong_name.as_ptr(), - cdescription.as_ptr(), - cclassification.as_ptr(), - cauthor.as_ptr(), - rank, - create_instance, - cprotocols.as_ptr()); -} - -unsafe fn sinks_register(plugin: *const c_void) -> GBoolean { sink_register(plugin, - "rsfilesink", - "File Sink", - "Writes to local files", - "Sink/File", - "Luis de Bethencourt ", - 256 + 100, - FileSink::new_boxed as *const c_void, - "file"); + &SinkInfo { + name: "rsfilesink", + long_name: "File Sink", + description: "Writes to local files", + classification: "Sink/File", + author: "Luis de Bethencourt ", + rank: 256 + 100, + create_instance: FileSink::new_boxed, + protocols: "file", + }); - GBoolean::True -} - -unsafe fn demuxer_register(plugin: *const c_void, - name: &str, - long_name: &str, - description: &str, - classification: &str, - author: &str, - rank: i32, - create_instance: *const c_void, - input_format: &str, - output_formats: &str) { - extern "C" { - fn gst_rs_demuxer_register(plugin: *const c_void, - name: *const c_char, - long_name: *const c_char, - description: *const c_char, - classification: *const c_char, - author: *const c_char, - rank: i32, - create_instance: *const c_void, - input_format: *const c_char, - output_formats: *const c_char) - -> GBoolean; - } - - let cname = CString::new(name).unwrap(); - let clong_name = CString::new(long_name).unwrap(); - let cdescription = CString::new(description).unwrap(); - let cclassification = CString::new(classification).unwrap(); - let cauthor = CString::new(author).unwrap(); - let cinput_format = CString::new(input_format).unwrap(); - let coutput_formats = CString::new(output_formats).unwrap(); - - gst_rs_demuxer_register(plugin, - cname.as_ptr(), - clong_name.as_ptr(), - cdescription.as_ptr(), - cclassification.as_ptr(), - cauthor.as_ptr(), - rank, - create_instance, - cinput_format.as_ptr(), - coutput_formats.as_ptr()); -} - -unsafe fn demuxers_register(plugin: *const c_void) -> GBoolean { demuxer_register(plugin, - "rsflvdemux", - "FLV Demuxer", - "Demuxes FLV Streams", - "Codec/Demuxer", - "Sebastian Dröge ", - 256 + 100, - FlvDemux::new_boxed as *const c_void, - "video/x-flv", - "ANY"); + &DemuxerInfo { + name: "rsflvdemux", + long_name: "FLV Demuxer", + description: "Demuxes FLV Streams", + classification: "Codec/Demuxer", + author: "Sebastian Dröge ", + rank: 256 + 100, + create_instance: FlvDemux::new_boxed, + input_formats: "video/x-flv", + output_formats: "ANY", + }); - GBoolean::True + true } -#[repr(C)] -pub struct GstPluginDesc { - major_version: i32, - minor_version: i32, - name: *const u8, - description: *const u8, - plugin_init: extern "C" fn(plugin: *const c_void) -> GBoolean, - version: *const u8, - license: *const u8, - source: *const u8, - package: *const u8, - origin: *const u8, - release_datetime: *const u8, - _gst_reserved: [usize; 4], -} - -unsafe impl Sync for GstPluginDesc {} - -extern "C" fn plugin_init(plugin: *const c_void) -> GBoolean { - unsafe { - sources_register(plugin); - sinks_register(plugin); - demuxers_register(plugin); - } - - GBoolean::True -} - -#[no_mangle] -#[allow(non_upper_case_globals)] -pub static gst_plugin_desc: GstPluginDesc = GstPluginDesc { - major_version: 1, - minor_version: 10, - name: b"rsplugin\0" as *const u8, - description: b"Rust Plugin\0" as *const u8, - plugin_init: plugin_init, - version: b"1.0\0" as *const u8, - license: b"LGPL\0" as *const u8, - source: b"rsplugin\0" as *const u8, - package: b"rsplugin\0" as *const u8, - origin: b"https://github.com/sdroege/rsplugin\0" as *const u8, - release_datetime: b"2016-12-08\0" as *const u8, - _gst_reserved: [0, 0, 0, 0], -}; +plugin_define!(b"rsplugin\0", + b"Rust Plugin\0", + plugin_init, + b"1.0\0", + b"LGPL\0", + b"rsplugin\0", + b"rsplugin\0", + b"https://github.com/sdroege/rsplugin\0", + b"2016-12-08\0"); diff --git a/src/plugin.rs b/src/plugin.rs new file mode 100644 index 00000000..fd536dac --- /dev/null +++ b/src/plugin.rs @@ -0,0 +1,82 @@ +// Copyright (C) 2016 Sebastian Dröge +// 2016 Luis de Bethencourt +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the +// Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301, USA. + +use std::os::raw::c_void; + +pub struct Plugin(*const c_void); + +impl Plugin { + pub unsafe fn new(plugin: *const c_void) -> Plugin { + Plugin(plugin) + } + + pub unsafe fn to_raw(&self) -> *const c_void { + self.0 + } +} + +macro_rules! plugin_define( + ($name:expr, $description:expr, $plugin_init:ident, + $version:expr, $license:expr, $source:expr, + $package:expr, $origin:expr, $release_datetime:expr) => { + pub mod plugin_desc { + use std::os::raw::c_void; + use utils::GBoolean; + use plugin::Plugin; + + #[repr(C)] + pub struct GstPluginDesc { + major_version: i32, + minor_version: i32, + name: *const u8, + description: *const u8, + plugin_init: unsafe extern "C" fn(plugin: *const c_void) -> GBoolean, + version: *const u8, + license: *const u8, + source: *const u8, + package: *const u8, + origin: *const u8, + release_datetime: *const u8, + _gst_reserved: [usize; 4], + } + + unsafe impl Sync for GstPluginDesc {} + + #[no_mangle] + #[allow(non_upper_case_globals)] + pub static gst_plugin_desc: GstPluginDesc = GstPluginDesc { + major_version: 1, + minor_version: 10, + name: $name as *const u8, + description: $description as *const u8, + plugin_init: plugin_init_trampoline, + version: $version as *const u8, + license: $license as *const u8, + source: $source as *const u8, + package: $package as *const u8, + origin: $origin as *const u8, + release_datetime: $release_datetime as *const u8, + _gst_reserved: [0, 0, 0, 0], + }; + + unsafe extern "C" fn plugin_init_trampoline(plugin: *const c_void) -> GBoolean { + GBoolean::from_bool(super::$plugin_init(&Plugin::new(plugin))) + } + } + }; +); diff --git a/src/rsdemuxer.rs b/src/rsdemuxer.rs index e0b18294..6ab9da9a 100644 --- a/src/rsdemuxer.rs +++ b/src/rsdemuxer.rs @@ -30,6 +30,7 @@ use std::u64; use utils::*; use error::*; use buffer::*; +use plugin::Plugin; pub type StreamIndex = u32; @@ -442,3 +443,52 @@ pub unsafe extern "C" fn demuxer_end_of_stream(ptr: *mut DemuxerWrapper) { wrap.end_of_stream(); }) } + +pub struct DemuxerInfo<'a> { + pub name: &'a str, + pub long_name: &'a str, + pub description: &'a str, + pub classification: &'a str, + pub author: &'a str, + pub rank: i32, + pub create_instance: fn() -> Box, + pub input_formats: &'a str, + pub output_formats: &'a str, +} + +pub fn demuxer_register(plugin: &Plugin, demuxer_info: &DemuxerInfo) { + extern "C" { + fn gst_rs_demuxer_register(plugin: *const c_void, + name: *const c_char, + long_name: *const c_char, + description: *const c_char, + classification: *const c_char, + author: *const c_char, + rank: i32, + create_instance: *const c_void, + input_format: *const c_char, + output_formats: *const c_char) + -> GBoolean; + } + + let cname = CString::new(demuxer_info.name).unwrap(); + let clong_name = CString::new(demuxer_info.long_name).unwrap(); + let cdescription = CString::new(demuxer_info.description).unwrap(); + let cclassification = CString::new(demuxer_info.classification).unwrap(); + let cauthor = CString::new(demuxer_info.author).unwrap(); + let cinput_format = CString::new(demuxer_info.input_formats).unwrap(); + let coutput_formats = CString::new(demuxer_info.output_formats).unwrap(); + + unsafe { + gst_rs_demuxer_register(plugin.to_raw(), + cname.as_ptr(), + clong_name.as_ptr(), + cdescription.as_ptr(), + cclassification.as_ptr(), + cauthor.as_ptr(), + demuxer_info.rank, + demuxer_info.create_instance as *const c_void, + cinput_format.as_ptr(), + coutput_formats.as_ptr()); + } +} diff --git a/src/rssink.rs b/src/rssink.rs index 4b872bde..909d5e40 100644 --- a/src/rssink.rs +++ b/src/rssink.rs @@ -31,6 +31,7 @@ use url::Url; use utils::*; use error::*; use buffer::*; +use plugin::Plugin; #[derive(Debug)] pub enum SinkError { @@ -249,3 +250,48 @@ pub unsafe extern "C" fn sink_render(ptr: *const SinkWrapper, wrap.render(&*buffer) }) } + +pub struct SinkInfo<'a> { + pub name: &'a str, + pub long_name: &'a str, + pub description: &'a str, + pub classification: &'a str, + pub author: &'a str, + pub rank: i32, + pub create_instance: fn() -> Box, + pub protocols: &'a str, +} + +pub fn sink_register(plugin: &Plugin, sink_info: &SinkInfo) { + extern "C" { + fn gst_rs_sink_register(plugin: *const c_void, + name: *const c_char, + long_name: *const c_char, + description: *const c_char, + classification: *const c_char, + author: *const c_char, + rank: i32, + create_instance: *const c_void, + protocols: *const c_char) + -> GBoolean; + } + + let cname = CString::new(sink_info.name).unwrap(); + let clong_name = CString::new(sink_info.long_name).unwrap(); + let cdescription = CString::new(sink_info.description).unwrap(); + let cclassification = CString::new(sink_info.classification).unwrap(); + let cauthor = CString::new(sink_info.author).unwrap(); + let cprotocols = CString::new(sink_info.protocols).unwrap(); + + unsafe { + gst_rs_sink_register(plugin.to_raw(), + cname.as_ptr(), + clong_name.as_ptr(), + cdescription.as_ptr(), + cclassification.as_ptr(), + cauthor.as_ptr(), + sink_info.rank, + sink_info.create_instance as *const c_void, + cprotocols.as_ptr()); + } +} diff --git a/src/rssource.rs b/src/rssource.rs index 88781869..d25f7e8b 100644 --- a/src/rssource.rs +++ b/src/rssource.rs @@ -28,6 +28,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use url::Url; +use plugin::Plugin; use utils::*; use error::*; use buffer::*; @@ -302,3 +303,52 @@ pub unsafe extern "C" fn source_seek(ptr: *const SourceWrapper, start: u64, stop GBoolean::from_bool(wrap.seek(start, if stop == u64::MAX { None } else { Some(stop) })) }) } + +pub struct SourceInfo<'a> { + pub name: &'a str, + pub long_name: &'a str, + pub description: &'a str, + pub classification: &'a str, + pub author: &'a str, + pub rank: i32, + pub create_instance: fn() -> Box, + pub protocols: &'a str, + pub push_only: bool, +} + +pub fn source_register(plugin: &Plugin, source_info: &SourceInfo) { + + extern "C" { + fn gst_rs_source_register(plugin: *const c_void, + name: *const c_char, + long_name: *const c_char, + description: *const c_char, + classification: *const c_char, + author: *const c_char, + rank: i32, + create_instance: *const c_void, + protocols: *const c_char, + push_only: GBoolean) + -> GBoolean; + } + + let cname = CString::new(source_info.name).unwrap(); + let clong_name = CString::new(source_info.long_name).unwrap(); + let cdescription = CString::new(source_info.description).unwrap(); + let cclassification = CString::new(source_info.classification).unwrap(); + let cauthor = CString::new(source_info.author).unwrap(); + let cprotocols = CString::new(source_info.protocols).unwrap(); + + unsafe { + gst_rs_source_register(plugin.to_raw(), + cname.as_ptr(), + clong_name.as_ptr(), + cdescription.as_ptr(), + cclassification.as_ptr(), + cauthor.as_ptr(), + source_info.rank, + source_info.create_instance as *const c_void, + cprotocols.as_ptr(), + GBoolean::from_bool(source_info.push_only)); + } +}