From 7e7433037d94e3cd4fae9ad6ca846e23e94042f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 16 Sep 2017 20:35:01 +0300 Subject: [PATCH] Port everything over to gstreamer-rs And remove all unneeded code and unused external crates. --- gst-plugin-file/Cargo.toml | 2 +- gst-plugin-file/src/filesink.rs | 73 +-- gst-plugin-file/src/filesrc.rs | 87 +-- gst-plugin-file/src/lib.rs | 5 +- gst-plugin-flv/Cargo.toml | 3 +- gst-plugin-flv/src/flvdemux.rs | 279 ++++++---- gst-plugin-flv/src/lib.rs | 15 +- gst-plugin-http/Cargo.toml | 2 +- gst-plugin-http/src/httpsrc.rs | 89 +-- gst-plugin-http/src/lib.rs | 7 +- gst-plugin/Cargo.toml | 5 +- gst-plugin/src/adapter.rs | 112 ++-- gst-plugin/src/buffer.rs | 583 ------------------- gst-plugin/src/caps.rs | 184 ------ gst-plugin/src/demuxer.rs | 302 ++++++---- gst-plugin/src/error.rs | 200 +++---- gst-plugin/src/lib.rs | 28 +- gst-plugin/src/log.rs | 131 ----- gst-plugin/src/miniobject.rs | 158 ------ gst-plugin/src/plugin.rs | 30 +- gst-plugin/src/sink.rs | 453 ++++++++------- gst-plugin/src/source.rs | 573 ++++++++++--------- gst-plugin/src/streams.rs | 272 --------- gst-plugin/src/structure.rs | 414 -------------- gst-plugin/src/tags.rs | 290 ---------- gst-plugin/src/utils.rs | 151 ----- gst-plugin/src/value.rs | 960 -------------------------------- 27 files changed, 1194 insertions(+), 4214 deletions(-) delete mode 100644 gst-plugin/src/buffer.rs delete mode 100644 gst-plugin/src/caps.rs delete mode 100644 gst-plugin/src/log.rs delete mode 100644 gst-plugin/src/miniobject.rs delete mode 100644 gst-plugin/src/streams.rs delete mode 100644 gst-plugin/src/structure.rs delete mode 100644 gst-plugin/src/tags.rs delete mode 100644 gst-plugin/src/value.rs diff --git a/gst-plugin-file/Cargo.toml b/gst-plugin-file/Cargo.toml index f8bf0756..878aec85 100644 --- a/gst-plugin-file/Cargo.toml +++ b/gst-plugin-file/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT/Apache-2.0" [dependencies] url = "1.1" gst-plugin = { path="../gst-plugin" } -slog = "2.0" +gstreamer = { git = "https://github.com/sdroege/gstreamer-rs", features = ["v1_10"] } [lib] name = "gstrsfile" diff --git a/gst-plugin-file/src/filesink.rs b/gst-plugin-file/src/filesink.rs index b1330808..63e20e79 100644 --- a/gst-plugin-file/src/filesink.rs +++ b/gst-plugin-file/src/filesink.rs @@ -15,11 +15,9 @@ use std::convert::From; use gst_plugin::error::*; use gst_plugin::sink::*; -use gst_plugin::buffer::*; -use gst_plugin::utils::*; -use gst_plugin::log::*; -use slog::Logger; +use gst; +use gst::prelude::*; #[derive(Debug)] enum StreamingState { @@ -30,30 +28,31 @@ enum StreamingState { #[derive(Debug)] pub struct FileSink { streaming_state: StreamingState, - logger: Logger, + cat: gst::DebugCategory, } impl FileSink { - pub fn new(element: Element) -> FileSink { + pub fn new(_sink: &RsSinkWrapper) -> FileSink { FileSink { streaming_state: StreamingState::Stopped, - logger: Logger::root( - GstDebugDrain::new(Some(&element), "rsfilesink", 0, "Rust file sink"), - o!(), + cat: gst::DebugCategory::new( + "rsfilesink", + gst::DebugColorFlags::empty(), + "Rust file source", ), } } - pub fn new_boxed(element: Element) -> Box { - Box::new(FileSink::new(element)) + pub fn new_boxed(sink: &RsSinkWrapper) -> Box { + Box::new(FileSink::new(sink)) } } fn validate_uri(uri: &Url) -> Result<(), UriError> { let _ = try!(uri.to_file_path().or_else(|_| { Err(UriError::new( - UriErrorKind::UnsupportedProtocol, - Some(format!("Unsupported file URI '{}'", uri.as_str())), + gst::URIError::UnsupportedProtocol, + format!("Unsupported file URI '{}'", uri.as_str()), )) })); Ok(()) @@ -64,28 +63,37 @@ impl Sink for FileSink { Box::new(validate_uri) } - fn start(&mut self, uri: Url) -> Result<(), ErrorMessage> { + fn start(&mut self, sink: &RsSinkWrapper, uri: Url) -> Result<(), ErrorMessage> { if let StreamingState::Started { .. } = self.streaming_state { - return Err(error_msg!(SinkError::Failure, ["Sink already started"])); + return Err(error_msg!( + gst::LibraryError::Failed, + ["Sink already started"] + )); } let location = try!(uri.to_file_path().or_else(|_| { - error!(self.logger, "Unsupported file URI '{}'", uri.as_str()); + gst_error!( + self.cat, + obj: sink, + "Unsupported file URI '{}'", + uri.as_str() + ); Err(error_msg!( - SinkError::Failure, + gst::LibraryError::Failed, ["Unsupported file URI '{}'", uri.as_str()] )) })); let file = try!(File::create(location.as_path()).or_else(|err| { - error!( - self.logger, + gst_error!( + self.cat, + obj: sink, "Could not open file for writing: {}", err.to_string() ); Err(error_msg!( - SinkError::OpenFailed, + gst::ResourceError::OpenWrite, [ "Could not open file for writing '{}': {}", location.to_str().unwrap_or("Non-UTF8 path"), @@ -94,7 +102,7 @@ impl Sink for FileSink { )) })); - debug!(self.logger, "Opened file {:?}", file); + gst_debug!(self.cat, obj: sink, "Opened file {:?}", file); self.streaming_state = StreamingState::Started { file: file, @@ -104,17 +112,17 @@ impl Sink for FileSink { Ok(()) } - fn stop(&mut self) -> Result<(), ErrorMessage> { + fn stop(&mut self, _sink: &RsSinkWrapper) -> Result<(), ErrorMessage> { self.streaming_state = StreamingState::Stopped; Ok(()) } - fn render(&mut self, buffer: &Buffer) -> Result<(), FlowError> { - let logger = &self.logger; + fn render(&mut self, sink: &RsSinkWrapper, buffer: &gst::BufferRef) -> Result<(), FlowError> { + let cat = self.cat; let streaming_state = &mut self.streaming_state; - trace!(logger, "Rendering {:?}", buffer); + gst_trace!(cat, obj: sink, "Rendering {:?}", buffer); let (file, position) = match *streaming_state { StreamingState::Started { @@ -123,25 +131,26 @@ impl Sink for FileSink { } => (file, position), StreamingState::Stopped => { return Err(FlowError::Error( - error_msg!(SinkError::Failure, ["Not started yet"]), + error_msg!(gst::LibraryError::Failed, ["Not started yet"]), )); } }; - let map = match buffer.map_read() { + let map = match buffer.map_readable() { None => { - return Err(FlowError::Error( - error_msg!(SinkError::Failure, ["Failed to map buffer"]), - )); + return Err(FlowError::Error(error_msg!( + gst::LibraryError::Failed, + ["Failed to map buffer"] + ))); } Some(map) => map, }; let data = map.as_slice(); try!(file.write_all(data).or_else(|err| { - error!(logger, "Failed to write: {}", err); + gst_error!(cat, obj: sink, "Failed to write: {}", err); Err(FlowError::Error(error_msg!( - SinkError::WriteFailed, + gst::ResourceError::Write, ["Failed to write: {}", err] ))) })); diff --git a/gst-plugin-file/src/filesrc.rs b/gst-plugin-file/src/filesrc.rs index 01f3dfa5..fd07b13b 100644 --- a/gst-plugin-file/src/filesrc.rs +++ b/gst-plugin-file/src/filesrc.rs @@ -13,11 +13,9 @@ use url::Url; use gst_plugin::error::*; use gst_plugin::source::*; -use gst_plugin::buffer::*; -use gst_plugin::log::*; -use gst_plugin::utils::*; -use slog::Logger; +use gst; +use gst::prelude::*; #[derive(Debug)] enum StreamingState { @@ -28,30 +26,31 @@ enum StreamingState { #[derive(Debug)] pub struct FileSrc { streaming_state: StreamingState, - logger: Logger, + cat: gst::DebugCategory, } impl FileSrc { - pub fn new(element: Element) -> FileSrc { + pub fn new(_src: &RsSrcWrapper) -> FileSrc { FileSrc { streaming_state: StreamingState::Stopped, - logger: Logger::root( - GstDebugDrain::new(Some(&element), "rsfilesrc", 0, "Rust file source"), - o!(), + cat: gst::DebugCategory::new( + "rsfilesrc", + gst::DebugColorFlags::empty(), + "Rust file source", ), } } - pub fn new_boxed(element: Element) -> Box { - Box::new(FileSrc::new(element)) + pub fn new_boxed(src: &RsSrcWrapper) -> Box { + Box::new(FileSrc::new(src)) } } fn validate_uri(uri: &Url) -> Result<(), UriError> { let _ = try!(uri.to_file_path().or_else(|_| { Err(UriError::new( - UriErrorKind::UnsupportedProtocol, - Some(format!("Unsupported file URI '{}'", uri.as_str())), + gst::URIError::UnsupportedProtocol, + format!("Unsupported file URI '{}'", uri.as_str()), )) })); Ok(()) @@ -62,11 +61,11 @@ impl Source for FileSrc { Box::new(validate_uri) } - fn is_seekable(&self) -> bool { + fn is_seekable(&self, _src: &RsSrcWrapper) -> bool { true } - fn get_size(&self) -> Option { + fn get_size(&self, _src: &RsSrcWrapper) -> Option { if let StreamingState::Started { ref file, .. } = self.streaming_state { file.metadata().ok().map(|m| m.len()) } else { @@ -74,27 +73,36 @@ impl Source for FileSrc { } } - fn start(&mut self, uri: Url) -> Result<(), ErrorMessage> { + fn start(&mut self, src: &RsSrcWrapper, uri: Url) -> Result<(), ErrorMessage> { if let StreamingState::Started { .. } = self.streaming_state { - return Err(error_msg!(SourceError::Failure, ["Source already started"])); + return Err(error_msg!( + gst::LibraryError::Failed, + ["Source already started"] + )); } let location = try!(uri.to_file_path().or_else(|_| { - error!(self.logger, "Unsupported file URI '{}'", uri.as_str()); + gst_error!( + self.cat, + obj: src, + "Unsupported file URI '{}'", + uri.as_str() + ); Err(error_msg!( - SourceError::Failure, + gst::LibraryError::Failed, ["Unsupported file URI '{}'", uri.as_str()] )) })); let file = try!(File::open(location.as_path()).or_else(|err| { - error!( - self.logger, + gst_error!( + self.cat, + obj: src, "Could not open file for reading: {}", err.to_string() ); Err(error_msg!( - SourceError::OpenFailed, + gst::ResourceError::OpenRead, [ "Could not open file for reading '{}': {}", location.to_str().unwrap_or("Non-UTF8 path"), @@ -103,7 +111,7 @@ impl Source for FileSrc { )) })); - debug!(self.logger, "Opened file {:?}", file); + gst_debug!(self.cat, obj: src, "Opened file {:?}", file); self.streaming_state = StreamingState::Started { file: file, @@ -113,14 +121,20 @@ impl Source for FileSrc { Ok(()) } - fn stop(&mut self) -> Result<(), ErrorMessage> { + fn stop(&mut self, _src: &RsSrcWrapper) -> Result<(), ErrorMessage> { self.streaming_state = StreamingState::Stopped; Ok(()) } - fn fill(&mut self, offset: u64, _: u32, buffer: &mut Buffer) -> Result<(), FlowError> { - let logger = &self.logger; + fn fill( + &mut self, + src: &RsSrcWrapper, + offset: u64, + _: u32, + buffer: &mut gst::BufferRef, + ) -> Result<(), FlowError> { + let cat = self.cat; let streaming_state = &mut self.streaming_state; let (file, position) = match *streaming_state { @@ -130,16 +144,16 @@ impl Source for FileSrc { } => (file, position), StreamingState::Stopped => { return Err(FlowError::Error( - error_msg!(SourceError::Failure, ["Not started yet"]), + error_msg!(gst::LibraryError::Failed, ["Not started yet"]), )); } }; if *position != offset { try!(file.seek(SeekFrom::Start(offset)).or_else(|err| { - error!(logger, "Failed to seek to {}: {:?}", offset, err); + gst_error!(cat, obj: src, "Failed to seek to {}: {:?}", offset, err); Err(FlowError::Error(error_msg!( - SourceError::SeekFailed, + gst::ResourceError::Seek, ["Failed to seek to {}: {}", offset, err.to_string()] ))) })); @@ -147,11 +161,12 @@ impl Source for FileSrc { } let size = { - let mut map = match buffer.map_readwrite() { + let mut map = match buffer.map_writable() { None => { - return Err(FlowError::Error( - error_msg!(SourceError::Failure, ["Failed to map buffer"]), - )); + return Err(FlowError::Error(error_msg!( + gst::LibraryError::Failed, + ["Failed to map buffer"] + ))); } Some(map) => map, }; @@ -159,9 +174,9 @@ impl Source for FileSrc { let data = map.as_mut_slice(); try!(file.read(data).or_else(|err| { - error!(logger, "Failed to read: {:?}", err); + gst_error!(cat, obj: src, "Failed to read: {:?}", err); Err(FlowError::Error(error_msg!( - SourceError::ReadFailed, + gst::ResourceError::Read, ["Failed to read at {}: {}", offset, err.to_string()] ))) })) @@ -174,7 +189,7 @@ impl Source for FileSrc { Ok(()) } - fn seek(&mut self, _: u64, _: Option) -> Result<(), ErrorMessage> { + fn seek(&mut self, _src: &RsSrcWrapper, _: u64, _: Option) -> Result<(), ErrorMessage> { Ok(()) } } diff --git a/gst-plugin-file/src/lib.rs b/gst-plugin-file/src/lib.rs index 169137d6..a91ec7cb 100644 --- a/gst-plugin-file/src/lib.rs +++ b/gst-plugin-file/src/lib.rs @@ -11,10 +11,9 @@ #[macro_use] extern crate gst_plugin; #[macro_use] -extern crate slog; +extern crate gstreamer as gst; extern crate url; -use gst_plugin::plugin::*; use gst_plugin::source::*; use gst_plugin::sink::*; @@ -24,7 +23,7 @@ mod filesink; use filesrc::FileSrc; use filesink::FileSink; -fn plugin_init(plugin: &Plugin) -> bool { +fn plugin_init(plugin: &gst::Plugin) -> bool { source_register( plugin, SourceInfo { diff --git a/gst-plugin-flv/Cargo.toml b/gst-plugin-flv/Cargo.toml index 71100c6e..cb8f7088 100644 --- a/gst-plugin-flv/Cargo.toml +++ b/gst-plugin-flv/Cargo.toml @@ -8,7 +8,8 @@ license = "MIT/Apache-2.0" [dependencies] url = "1.1" gst-plugin = { path="../gst-plugin" } -slog = "2.0" +gstreamer = { git = "https://github.com/sdroege/gstreamer-rs", features = ["v1_10"] } +num-rational = { version = "0.1", default-features = false, features = [] } nom = "3.0" flavors = {git = "https://github.com/rust-av/flavors.git"} muldiv = "0.1" diff --git a/gst-plugin-flv/src/flvdemux.rs b/gst-plugin-flv/src/flvdemux.rs index f6c43390..ea8b7617 100644 --- a/gst-plugin-flv/src/flvdemux.rs +++ b/gst-plugin-flv/src/flvdemux.rs @@ -16,20 +16,16 @@ use flavors::parser as flavors; use gst_plugin::error::*; use gst_plugin::demuxer::*; -use gst_plugin::buffer::*; use gst_plugin::adapter::*; -use gst_plugin::utils; -use gst_plugin::utils::Element; -use gst_plugin::log::*; -use gst_plugin::caps::Caps; -use gst_plugin::miniobject::*; -use gst_plugin::value::Rational32; use gst_plugin::bytes::*; -use slog::Logger; - use muldiv::*; +use gst; +use gst::prelude::*; + +use num_rational::Rational32; + const AUDIO_STREAM_ID: u32 = 0; const VIDEO_STREAM_ID: u32 = 1; @@ -56,8 +52,8 @@ struct StreamingState { metadata: Option, - aac_sequence_header: Option>, - avc_sequence_header: Option>, + aac_sequence_header: Option, + avc_sequence_header: Option, } impl StreamingState { @@ -83,7 +79,7 @@ struct AudioFormat { width: u8, channels: u8, bitrate: Option, - aac_sequence_header: Option>, + aac_sequence_header: Option, } // Ignores bitrate @@ -99,7 +95,7 @@ impl AudioFormat { fn new( data_header: &flavors::AudioDataHeader, metadata: &Option, - aac_sequence_header: &Option>, + aac_sequence_header: &Option, ) -> AudioFormat { let numeric_rate = match (data_header.sound_format, data_header.sound_rate) { (flavors::SoundFormat::NELLYMOSER_16KHZ_MONO, _) => 16000, @@ -143,55 +139,45 @@ impl AudioFormat { changed } - fn to_string(&self) -> Option { - self.to_caps().map(|c| c.to_string()) - } - - fn to_caps(&self) -> Option> { + fn to_caps(&self) -> Option { let mut caps = match self.format { - flavors::SoundFormat::MP3 | flavors::SoundFormat::MP3_8KHZ => Some(Caps::new_simple( - "audio/mpeg", - &[("mpegversion", 1i32.into()), ("layer", 3i32.into())], - )), + flavors::SoundFormat::MP3 | flavors::SoundFormat::MP3_8KHZ => Some( + gst::Caps::new_simple("audio/mpeg", &[("mpegversion", &1i32), ("layer", &3i32)]), + ), flavors::SoundFormat::PCM_NE | flavors::SoundFormat::PCM_LE => { if self.rate != 0 && self.channels != 0 { // Assume little-endian for "PCM_NE", it's probably more common and we have no // way to know what the endianness of the system creating the stream was - Some(Caps::new_simple( + Some(gst::Caps::new_simple( "audio/x-raw", &[ - ("layout", "interleaved".into()), - ( - "format", - if self.width == 8 { - "U8".into() - } else { - "S16LE".into() - }, - ), + ("layout", &"interleaved"), + ("format", &if self.width == 8 { "U8" } else { "S16LE" }), ], )) } else { None } } - flavors::SoundFormat::ADPCM => Some(Caps::new_simple( + flavors::SoundFormat::ADPCM => Some(gst::Caps::new_simple( "audio/x-adpcm", - &[("layout", "swf".into())], + &[("layout", &"swf")], )), flavors::SoundFormat::NELLYMOSER_16KHZ_MONO | flavors::SoundFormat::NELLYMOSER_8KHZ_MONO | - flavors::SoundFormat::NELLYMOSER => Some(Caps::new_simple("audio/x-nellymoser", &[])), - flavors::SoundFormat::PCM_ALAW => Some(Caps::new_simple("audio/x-alaw", &[])), - flavors::SoundFormat::PCM_ULAW => Some(Caps::new_simple("audio/x-mulaw", &[])), + flavors::SoundFormat::NELLYMOSER => { + Some(gst::Caps::new_simple("audio/x-nellymoser", &[])) + } + flavors::SoundFormat::PCM_ALAW => Some(gst::Caps::new_simple("audio/x-alaw", &[])), + flavors::SoundFormat::PCM_ULAW => Some(gst::Caps::new_simple("audio/x-mulaw", &[])), flavors::SoundFormat::AAC => self.aac_sequence_header.as_ref().map(|header| { - Caps::new_simple( + gst::Caps::new_simple( "audio/mpeg", &[ - ("mpegversion", 4i32.into()), - ("framed", true.into()), - ("stream-format", "raw".into()), - ("codec_data", header.as_ref().into()), + ("mpegversion", &4i32), + ("framed", &true), + ("stream-format", &"raw"), + ("codec_data", &header), ], ) }), @@ -219,7 +205,7 @@ impl AudioFormat { data.into_inner() }; - let header = Buffer::from_vec(header).unwrap(); + let header = gst::Buffer::from_vec(header).unwrap(); let comment = { let comment_size = 4 + 7 /* nothing */ + 4 + 1; @@ -233,11 +219,11 @@ impl AudioFormat { data.into_inner() }; - let comment = Buffer::from_vec(comment).unwrap(); + let comment = gst::Buffer::from_vec(comment).unwrap(); - Some(Caps::new_simple( + Some(gst::Caps::new_simple( "audio/x-speex", - &[("streamheader", vec![header.into(), comment.into()].into())], + &[("streamheader", &gst::Array::new(&[&header, &comment]))], )) } flavors::SoundFormat::DEVICE_SPECIFIC => { @@ -250,14 +236,14 @@ impl AudioFormat { caps.as_mut().map(|c| { c.get_mut() .unwrap() - .set_simple(&[("rate", (self.rate as i32).into())]) + .set_simple(&[("rate", &(self.rate as i32))]) }); } if self.channels != 0 { caps.as_mut().map(|c| { c.get_mut() .unwrap() - .set_simple(&[("channels", (self.channels as i32).into())]) + .set_simple(&[("channels", &(self.channels as i32))]) }); } @@ -273,14 +259,14 @@ struct VideoFormat { pixel_aspect_ratio: Option, framerate: Option, bitrate: Option, - avc_sequence_header: Option>, + avc_sequence_header: Option, } impl VideoFormat { fn new( data_header: &flavors::VideoDataHeader, metadata: &Option, - avc_sequence_header: &Option>, + avc_sequence_header: &Option, ) -> VideoFormat { VideoFormat { format: data_header.codec_id, @@ -324,33 +310,26 @@ impl VideoFormat { changed } - fn to_string(&self) -> Option { - self.to_caps().map(|caps| caps.to_string()) - } - - fn to_caps(&self) -> Option> { + fn to_caps(&self) -> Option { let mut caps = match self.format { - flavors::CodecId::SORENSON_H263 => Some(Caps::new_simple( + flavors::CodecId::SORENSON_H263 => Some(gst::Caps::new_simple( "video/x-flash-video", - &[("flvversion", 1i32.into())], + &[("flvversion", &1i32)], )), - flavors::CodecId::SCREEN => Some(Caps::new_simple("video/x-flash-screen", &[])), - flavors::CodecId::VP6 => Some(Caps::new_simple("video/x-vp6-flash", &[])), - flavors::CodecId::VP6A => Some(Caps::new_simple("video/x-vp6-flash-alpha", &[])), - flavors::CodecId::SCREEN2 => Some(Caps::new_simple("video/x-flash-screen2", &[])), + flavors::CodecId::SCREEN => Some(gst::Caps::new_simple("video/x-flash-screen", &[])), + flavors::CodecId::VP6 => Some(gst::Caps::new_simple("video/x-vp6-flash", &[])), + flavors::CodecId::VP6A => Some(gst::Caps::new_simple("video/x-vp6-flash-alpha", &[])), + flavors::CodecId::SCREEN2 => Some(gst::Caps::new_simple("video/x-flash-screen2", &[])), flavors::CodecId::H264 => self.avc_sequence_header.as_ref().map(|header| { - Caps::new_simple( + gst::Caps::new_simple( "video/x-h264", - &[ - ("stream-format", "avc".into()), - ("codec_data", header.as_ref().into()), - ], + &[("stream-format", &"avc"), ("codec_data", &header)], ) }), - flavors::CodecId::H263 => Some(Caps::new_simple("video/x-h263", &[])), - flavors::CodecId::MPEG4Part2 => Some(Caps::new_simple( + flavors::CodecId::H263 => Some(gst::Caps::new_simple("video/x-h263", &[])), + flavors::CodecId::MPEG4Part2 => Some(gst::Caps::new_simple( "video/x-h263", - &[("mpegversion", 4i32.into()), ("systemstream", false.into())], + &[("mpegversion", &4i32), ("systemstream", &false)], )), flavors::CodecId::JPEG => { // Unused according to spec @@ -360,19 +339,21 @@ impl VideoFormat { if let (Some(width), Some(height)) = (self.width, self.height) { caps.as_mut().map(|c| { - c.get_mut().unwrap().set_simple(&[ - ("width", (width as i32).into()), - ("height", (height as i32).into()), - ]) + c.get_mut() + .unwrap() + .set_simple(&[("width", &(width as i32)), ("height", &(height as i32))]) }); } if let Some(par) = self.pixel_aspect_ratio { if *par.numer() != 0 && par.numer() != par.denom() { caps.as_mut().map(|c| { - c.get_mut() - .unwrap() - .set_simple(&[("pixel-aspect-ratio", par.into())]) + c.get_mut().unwrap().set_simple(&[ + ( + "pixel-aspect-ratio", + &gst::Fraction::new(*par.numer(), *par.denom()), + ), + ]) }); } } @@ -380,9 +361,9 @@ impl VideoFormat { if let Some(fps) = self.framerate { if *fps.numer() != 0 { caps.as_mut().map(|c| { - c.get_mut() - .unwrap() - .set_simple(&[("framerate", fps.into())]) + c.get_mut().unwrap().set_simple(&[ + ("framerate", &gst::Fraction::new(*fps.numer(), *fps.denom())), + ]) }); } } @@ -475,7 +456,7 @@ impl Metadata { metadata.video_height = Some(height as u32); } ("framerate", &flavors::ScriptDataValue::Number(framerate)) if framerate >= 0.0 => { - if let Some(framerate) = utils::f64_to_fraction(framerate) { + if let Some(framerate) = Rational32::approximate_float(framerate) { metadata.video_framerate = Some(framerate); } } @@ -500,9 +481,8 @@ impl Metadata { } } -#[derive(Debug)] pub struct FlvDemux { - logger: Logger, + cat: gst::DebugCategory, state: State, adapter: Adapter, // Only in >= State::Streaming @@ -510,11 +490,12 @@ pub struct FlvDemux { } impl FlvDemux { - pub fn new(element: Element) -> FlvDemux { + pub fn new(_element: &gst::Element) -> FlvDemux { FlvDemux { - logger: Logger::root( - GstDebugDrain::new(Some(&element), "rsflvdemux", 0, "Rust FLV demuxer"), - o!(), + cat: gst::DebugCategory::new( + "rsflvdemux", + gst::DebugColorFlags::empty(), + "Rust FLV demuxer", ), state: State::Stopped, adapter: Adapter::new(), @@ -522,7 +503,7 @@ impl FlvDemux { } } - pub fn new_boxed(element: Element) -> Box { + pub fn new_boxed(element: &gst::Element) -> Box { Box::new(FlvDemux::new(element)) } @@ -539,15 +520,23 @@ impl FlvDemux { let buffer = self.adapter .get_buffer(tag_header.data_size as usize) .unwrap(); - let map = buffer.map_read().unwrap(); + let map = buffer.map_readable().unwrap(); let data = map.as_slice(); match flavors::script_data(data) { IResult::Done(_, ref script_data) if script_data.name == "onMetaData" => { - trace!(self.logger, "Got script tag: {:?}", script_data); + gst_trace!( + self.cat, + /* TODO: obj: demuxer, */ "Got script tag: {:?}", + script_data + ); let metadata = Metadata::new(script_data); - debug!(self.logger, "Got metadata: {:?}", metadata); + gst_debug!( + self.cat, + /* TODO: obj: demuxer, */ "Got metadata: {:?}", + metadata + ); let streaming_state = self.streaming_state.as_mut().unwrap(); @@ -583,7 +572,11 @@ impl FlvDemux { } } IResult::Done(_, ref script_data) => { - trace!(self.logger, "Got script tag: {:?}", script_data); + gst_trace!( + self.cat, + /* TODO: obj: demuxer, */ "Got script tag: {:?}", + script_data + ); } IResult::Error(_) | IResult::Incomplete(_) => { // ignore @@ -597,8 +590,11 @@ impl FlvDemux { &mut self, data_header: &flavors::AudioDataHeader, ) -> Result { - let logger = self.logger.clone(); - trace!(logger, "Got audio data header: {:?}", data_header); + gst_trace!( + self.cat, + /* TODO: obj: demuxer, */ "Got audio data header: {:?}", + data_header + ); let streaming_state = self.streaming_state.as_mut().unwrap(); @@ -609,7 +605,11 @@ impl FlvDemux { ); if streaming_state.audio.as_ref() != Some(&new_audio_format) { - debug!(logger, "Got new audio format: {:?}", new_audio_format); + gst_debug!( + self.cat, + /* TODO: obj: demuxer, */ "Got new audio format: {:?}", + new_audio_format + ); let new_stream = streaming_state.audio == None; let caps = new_audio_format.to_caps(); @@ -659,8 +659,8 @@ impl FlvDemux { self.adapter .flush(15 + tag_header.data_size as usize) .unwrap(); - warn!( - self.logger, + gst_warning!( + self.cat, /* TODO: obj: demuxer, */ "Too small packet for AAC packet header {}", 15 + tag_header.data_size ); @@ -674,15 +674,19 @@ impl FlvDemux { unimplemented!(); } IResult::Done(_, header) => { - trace!(self.logger, "Got AAC packet header {:?}", header); + gst_trace!( + self.cat, + /* TODO: obj: demuxer, */ "Got AAC packet header {:?}", + header + ); match header.packet_type { flavors::AACPacketType::SequenceHeader => { self.adapter.flush(15 + 1 + 1).unwrap(); let buffer = self.adapter .get_buffer((tag_header.data_size - 1 - 1) as usize) .unwrap(); - debug!( - self.logger, + gst_debug!( + self.cat, /* TODO: obj: demuxer, */ "Got AAC sequence header {:?} of size {}", buffer, tag_header.data_size - 1 - 1 @@ -738,11 +742,15 @@ impl FlvDemux { { let buffer = buffer.get_mut().unwrap(); - buffer.set_pts((tag_header.timestamp as u64).mul_div_floor(1000_000, 1)); + buffer.set_pts( + (tag_header.timestamp as u64) + .mul_div_floor(1000_000, 1) + .unwrap(), + ); } - trace!( - self.logger, + gst_trace!( + self.cat, /* TODO: obj: demuxer, */ "Outputting audio buffer {:?} for tag {:?} of size {}", buffer, tag_header, @@ -756,8 +764,11 @@ impl FlvDemux { &mut self, data_header: &flavors::VideoDataHeader, ) -> Result { - let logger = self.logger.clone(); - trace!(logger, "Got video data header: {:?}", data_header); + gst_trace!( + self.cat, + /* TODO: obj: demuxer, */ "Got video data header: {:?}", + data_header + ); let streaming_state = self.streaming_state.as_mut().unwrap(); @@ -768,7 +779,11 @@ impl FlvDemux { ); if streaming_state.video.as_ref() != Some(&new_video_format) { - debug!(logger, "Got new video format: {:?}", new_video_format); + gst_debug!( + self.cat, + /* TODO: obj: demuxer, */ "Got new video format: {:?}", + new_video_format + ); let new_stream = streaming_state.video == None; @@ -821,8 +836,8 @@ impl FlvDemux { self.adapter .flush(15 + tag_header.data_size as usize) .unwrap(); - warn!( - self.logger, + gst_warning!( + self.cat, /* TODO: obj: demuxer, */ "Too small packet for AVC packet header {}", 15 + tag_header.data_size ); @@ -836,15 +851,19 @@ impl FlvDemux { unimplemented!(); } IResult::Done(_, header) => { - trace!(self.logger, "Got AVC packet header {:?}", header); + gst_trace!( + self.cat, + /* TODO: obj: demuxer, */ "Got AVC packet header {:?}", + header + ); match header.packet_type { flavors::AVCPacketType::SequenceHeader => { self.adapter.flush(15 + 1 + 4).unwrap(); let buffer = self.adapter .get_buffer((tag_header.data_size - 1 - 4) as usize) .unwrap(); - debug!( - self.logger, + gst_debug!( + self.cat, /* TODO: obj: demuxer, */ "Got AVC sequence header {:?} of size {}", buffer, tag_header.data_size - 1 - 4 @@ -911,9 +930,13 @@ impl FlvDemux { { let buffer = buffer.get_mut().unwrap(); if !is_keyframe { - buffer.set_flags(BUFFER_FLAG_DELTA_UNIT); + buffer.set_flags(gst::BUFFER_FLAG_DELTA_UNIT); } - buffer.set_dts((tag_header.timestamp as u64).mul_div_floor(1000_000, 1)); + buffer.set_dts( + (tag_header.timestamp as u64) + .mul_div_floor(1000_000, 1) + .unwrap(), + ); // Prevent negative numbers let pts = if cts < 0 && tag_header.timestamp < (-cts) as u32 { @@ -921,11 +944,11 @@ impl FlvDemux { } else { ((tag_header.timestamp as i64) + (cts as i64)) as u64 }; - buffer.set_pts(pts.mul_div_floor(1000_000, 1)); + buffer.set_pts(pts.mul_div_floor(1000_000, 1).unwrap()); } - trace!( - self.logger, + gst_trace!( + self.cat, /* TODO: obj: demuxer, */ "Outputting video buffer {:?} for tag {:?} of size {}, keyframe: {}", buffer, tag_header, @@ -949,7 +972,11 @@ impl FlvDemux { // fall through } IResult::Done(_, ref header) => { - debug!(self.logger, "Found FLV header: {:?}", header); + gst_debug!( + self.cat, + /* TODO: obj: demuxer, */ "Found FLV header: {:?}", + header + ); let skip = if header.offset < 9 { 0 @@ -1006,7 +1033,11 @@ impl FlvDemux { unimplemented!(); } IResult::Done(_, previous_size) => { - trace!(self.logger, "Previous tag size {}", previous_size); + gst_trace!( + self.cat, + /* TODO: obj: demuxer, */ "Previous tag size {}", + previous_size + ); // Nothing to do here, we just consume it for now } } @@ -1020,12 +1051,12 @@ impl FlvDemux { let res = match tag_header.tag_type { flavors::TagType::Script => { - trace!(self.logger, "Found script tag"); + gst_trace!(self.cat, /* TODO: obj: demuxer, */ "Found script tag"); self.handle_script_tag(&tag_header) } flavors::TagType::Audio => { - trace!(self.logger, "Found audio tag"); + gst_trace!(self.cat, /* TODO: obj: demuxer, */ "Found audio tag"); let data_header = match flavors::audio_data_header(&data[15..]) { IResult::Error(_) | IResult::Incomplete(_) => { @@ -1037,7 +1068,7 @@ impl FlvDemux { self.handle_audio_tag(&tag_header, &data_header) } flavors::TagType::Video => { - trace!(self.logger, "Found video tag"); + gst_trace!(self.cat, /* TODO: obj: demuxer, */ "Found video tag"); let data_header = match flavors::video_data_header(&data[15..]) { IResult::Error(_) | IResult::Incomplete(_) => { @@ -1053,12 +1084,14 @@ impl FlvDemux { if let Ok(HandleBufferResult::BufferForStream(_, ref buffer)) = res { let streaming_state = self.streaming_state.as_mut().unwrap(); - if let Some(pts) = buffer.get_pts() { + if buffer.get_pts() != gst::CLOCK_TIME_NONE { + let pts = buffer.get_pts(); streaming_state.last_position = streaming_state .last_position .map(|last| cmp::max(last, pts)) .or_else(|| Some(pts)); - } else if let Some(dts) = buffer.get_dts() { + } else if buffer.get_dts() != gst::CLOCK_TIME_NONE { + let dts = buffer.get_dts(); streaming_state.last_position = streaming_state .last_position .map(|last| cmp::max(last, dts)) @@ -1097,7 +1130,7 @@ impl Demuxer for FlvDemux { fn handle_buffer( &mut self, - buffer: Option>, + buffer: Option, ) -> Result { if let Some(buffer) = buffer { self.adapter.push(buffer); diff --git a/gst-plugin-flv/src/lib.rs b/gst-plugin-flv/src/lib.rs index cc72efbb..0a78854d 100644 --- a/gst-plugin-flv/src/lib.rs +++ b/gst-plugin-flv/src/lib.rs @@ -11,22 +11,21 @@ extern crate flavors; #[macro_use] extern crate gst_plugin; +#[macro_use] +extern crate gstreamer as gst; extern crate muldiv; -#[macro_use] extern crate nom; -#[macro_use] -extern crate slog; +extern crate num_rational; extern crate url; -use gst_plugin::plugin::*; use gst_plugin::demuxer::*; -use gst_plugin::caps::*; +use gst::prelude::*; mod flvdemux; use flvdemux::FlvDemux; -fn plugin_init(plugin: &Plugin) -> bool { +fn plugin_init(plugin: &gst::Plugin) -> bool { demuxer_register( plugin, &DemuxerInfo { @@ -37,8 +36,8 @@ fn plugin_init(plugin: &Plugin) -> bool { author: "Sebastian Dröge ", rank: 256 + 100, create_instance: FlvDemux::new_boxed, - input_caps: &Caps::new_simple("video/x-flv", &[]), - output_caps: &Caps::new_any(), + input_caps: &gst::Caps::new_simple("video/x-flv", &[]), + output_caps: &gst::Caps::new_any(), }, ); diff --git a/gst-plugin-http/Cargo.toml b/gst-plugin-http/Cargo.toml index 277ad8b8..0e340a55 100644 --- a/gst-plugin-http/Cargo.toml +++ b/gst-plugin-http/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT/Apache-2.0" url = "1.1" gst-plugin = { path="../gst-plugin" } reqwest = "0.7" -slog = "2.0" +gstreamer = { git = "https://github.com/sdroege/gstreamer-rs", features = ["v1_10"] } [lib] name = "gstrshttp" diff --git a/gst-plugin-http/src/httpsrc.rs b/gst-plugin-http/src/httpsrc.rs index 08abe937..383bf140 100644 --- a/gst-plugin-http/src/httpsrc.rs +++ b/gst-plugin-http/src/httpsrc.rs @@ -15,11 +15,9 @@ use reqwest::header::{AcceptRanges, ByteRangeSpec, ContentLength, ContentRange, use gst_plugin::error::*; use gst_plugin::source::*; -use gst_plugin::buffer::*; -use gst_plugin::utils::*; -use gst_plugin::log::*; -use slog::Logger; +use gst; +use gst::prelude::*; #[derive(Debug)] enum StreamingState { @@ -38,32 +36,35 @@ enum StreamingState { #[derive(Debug)] pub struct HttpSrc { streaming_state: StreamingState, - logger: Logger, + cat: gst::DebugCategory, client: Client, } impl HttpSrc { - pub fn new(element: Element) -> HttpSrc { + pub fn new(_src: &RsSrcWrapper) -> HttpSrc { HttpSrc { streaming_state: StreamingState::Stopped, - logger: Logger::root( - GstDebugDrain::new(Some(&element), "rshttpsink", 0, "Rust http sink"), - o!(), + cat: gst::DebugCategory::new( + "rshttpsrc", + gst::DebugColorFlags::empty(), + "Rust HTTP source", ), client: Client::new().unwrap(), } } - pub fn new_boxed(element: Element) -> Box { - Box::new(HttpSrc::new(element)) + pub fn new_boxed(src: &RsSrcWrapper) -> Box { + Box::new(HttpSrc::new(src)) } fn do_request( &self, + src: &RsSrcWrapper, uri: Url, start: u64, stop: Option, ) -> Result { + let cat = self.cat; let mut req = self.client.get(uri.clone()).unwrap(); match (start != 0, stop) { @@ -76,20 +77,20 @@ impl HttpSrc { } } - debug!(self.logger, "Doing new request {:?}", req); + gst_debug!(cat, obj: src, "Doing new request {:?}", req); let response = try!(req.send().or_else(|err| { - error!(self.logger, "Request failed: {:?}", err); + gst_error!(cat, obj: src, "Request failed: {:?}", err); Err(error_msg!( - SourceError::ReadFailed, + gst::ResourceError::Read, ["Failed to fetch {}: {}", uri, err.to_string()] )) })); if !response.status().is_success() { - error!(self.logger, "Request status failed: {:?}", response); + gst_error!(cat, obj: src, "Request status failed: {:?}", response); return Err(error_msg!( - SourceError::ReadFailed, + gst::ResourceError::Read, ["Failed to fetch {}: {}", uri, response.status()] )); } @@ -121,12 +122,12 @@ impl HttpSrc { if position != start { return Err(error_msg!( - SourceError::SeekFailed, + gst::ResourceError::Seek, ["Failed to seek to {}: Got {}", start, position] )); } - debug!(self.logger, "Request successful: {:?}", response); + gst_debug!(cat, obj: src, "Request successful: {:?}", response); Ok(StreamingState::Started { uri: uri, @@ -143,8 +144,8 @@ impl HttpSrc { fn validate_uri(uri: &Url) -> Result<(), UriError> { if uri.scheme() != "http" && uri.scheme() != "https" { return Err(UriError::new( - UriErrorKind::UnsupportedProtocol, - Some(format!("Unsupported URI '{}'", uri.as_str())), + gst::URIError::UnsupportedProtocol, + format!("Unsupported URI '{}'", uri.as_str()), )); } @@ -156,34 +157,39 @@ impl Source for HttpSrc { Box::new(validate_uri) } - fn is_seekable(&self) -> bool { + fn is_seekable(&self, _src: &RsSrcWrapper) -> bool { match self.streaming_state { StreamingState::Started { seekable, .. } => seekable, _ => false, } } - fn get_size(&self) -> Option { + fn get_size(&self, _src: &RsSrcWrapper) -> Option { match self.streaming_state { StreamingState::Started { size, .. } => size, _ => None, } } - fn start(&mut self, uri: Url) -> Result<(), ErrorMessage> { + fn start(&mut self, src: &RsSrcWrapper, uri: Url) -> Result<(), ErrorMessage> { self.streaming_state = StreamingState::Stopped; - self.streaming_state = try!(self.do_request(uri, 0, None)); + self.streaming_state = try!(self.do_request(src, uri, 0, None)); Ok(()) } - fn stop(&mut self) -> Result<(), ErrorMessage> { + fn stop(&mut self, _src: &RsSrcWrapper) -> Result<(), ErrorMessage> { self.streaming_state = StreamingState::Stopped; Ok(()) } - fn seek(&mut self, start: u64, stop: Option) -> Result<(), ErrorMessage> { + fn seek( + &mut self, + src: &RsSrcWrapper, + start: u64, + stop: Option, + ) -> Result<(), ErrorMessage> { let (position, old_stop, uri) = match self.streaming_state { StreamingState::Started { position, @@ -192,7 +198,7 @@ impl Source for HttpSrc { .. } => (position, stop, uri.clone()), StreamingState::Stopped => { - return Err(error_msg!(SourceError::Failure, ["Not started yet"])); + return Err(error_msg!(gst::LibraryError::Failed, ["Not started yet"])); } }; @@ -201,13 +207,19 @@ impl Source for HttpSrc { } self.streaming_state = StreamingState::Stopped; - self.streaming_state = try!(self.do_request(uri, start, stop)); + self.streaming_state = try!(self.do_request(src, uri, start, stop)); Ok(()) } - fn fill(&mut self, offset: u64, _: u32, buffer: &mut Buffer) -> Result<(), FlowError> { - let logger = self.logger.clone(); + fn fill( + &mut self, + src: &RsSrcWrapper, + offset: u64, + _: u32, + buffer: &mut gst::BufferRef, + ) -> Result<(), FlowError> { + let cat = self.cat; let (response, position) = match self.streaming_state { StreamingState::Started { @@ -217,24 +229,25 @@ impl Source for HttpSrc { } => (response, position), StreamingState::Stopped => { return Err(FlowError::Error( - error_msg!(SourceError::Failure, ["Not started yet"]), + error_msg!(gst::LibraryError::Failed, ["Not started yet"]), )); } }; if *position != offset { return Err(FlowError::Error(error_msg!( - SourceError::SeekFailed, + gst::ResourceError::Seek, ["Got unexpected offset {}, expected {}", offset, position] ))); } let size = { - let mut map = match buffer.map_readwrite() { + let mut map = match buffer.map_writable() { None => { - return Err(FlowError::Error( - error_msg!(SourceError::Failure, ["Failed to map buffer"]), - )); + return Err(FlowError::Error(error_msg!( + gst::LibraryError::Failed, + ["Failed to map buffer"] + ))); } Some(map) => map, }; @@ -242,9 +255,9 @@ impl Source for HttpSrc { let data = map.as_mut_slice(); try!(response.read(data).or_else(|err| { - error!(logger, "Failed to read: {:?}", err); + gst_error!(cat, obj: src, "Failed to read: {:?}", err); Err(FlowError::Error(error_msg!( - SourceError::ReadFailed, + gst::ResourceError::Read, ["Failed to read at {}: {}", offset, err.to_string()] ))) })) diff --git a/gst-plugin-http/src/lib.rs b/gst-plugin-http/src/lib.rs index 731e3dab..3ae9ca93 100644 --- a/gst-plugin-http/src/lib.rs +++ b/gst-plugin-http/src/lib.rs @@ -10,19 +10,18 @@ #[macro_use] extern crate gst_plugin; -extern crate reqwest; #[macro_use] -extern crate slog; +extern crate gstreamer as gst; +extern crate reqwest; extern crate url; -use gst_plugin::plugin::*; use gst_plugin::source::*; mod httpsrc; use httpsrc::HttpSrc; -fn plugin_init(plugin: &Plugin) -> bool { +fn plugin_init(plugin: &gst::Plugin) -> bool { source_register( plugin, SourceInfo { diff --git a/gst-plugin/Cargo.toml b/gst-plugin/Cargo.toml index e52f548e..064b6736 100644 --- a/gst-plugin/Cargo.toml +++ b/gst-plugin/Cargo.toml @@ -9,18 +9,15 @@ license = "MIT/Apache-2.0" [dependencies] libc = "0.2" url = "1.1" -bitflags = "0.9" -slog = { version = "2.0", features = ["max_level_trace"] } lazy_static = "0.2" byteorder = "1.0" -num-rational = { version = "0.1", default-features = false, features = [] } -derivative = "1.0" 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_10"] } gstreamer-base-sys = { git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_10"] } glib = { git = "https://github.com/gtk-rs/glib" } gstreamer = { git = "https://github.com/sdroege/gstreamer-rs", features = ["v1_10"] } +gstreamer-base = { git = "https://github.com/sdroege/gstreamer-rs" } [build-dependencies] gcc = "0.3" diff --git a/gst-plugin/src/adapter.rs b/gst-plugin/src/adapter.rs index 8e6c509f..a6aef5c5 100644 --- a/gst-plugin/src/adapter.rs +++ b/gst-plugin/src/adapter.rs @@ -6,26 +6,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use buffer::*; -use miniobject::*; -use log::*; use std::collections::VecDeque; use std::cmp; -use slog::Logger; + +use gst; +use gst::prelude::*; lazy_static! { - static ref LOGGER: Logger = { - Logger::root(GstDebugDrain::new(None, - "rsadapter", - 0, - "Rust buffer adapter"), - o!()) + static ref CAT: gst::DebugCategory = { + gst::DebugCategory::new( + "rsadapter", + gst::DebugColorFlags::empty(), + "Rust buffer adapter", + ) }; } -#[derive(Debug)] pub struct Adapter { - deque: VecDeque, + deque: VecDeque>, size: usize, skip: usize, scratch: Vec, @@ -46,19 +44,19 @@ impl Adapter { } } - pub fn push(&mut self, buffer: GstRc) { + pub fn push(&mut self, buffer: gst::Buffer) { let size = buffer.get_size(); self.size += size; - trace!( - LOGGER, + gst_trace!( + CAT, "Storing {:?} of size {}, now have size {}", buffer, size, self.size ); self.deque - .push_back(Buffer::into_read_mapped_buffer(buffer).unwrap()); + .push_back(buffer.into_mapped_buffer_readable().unwrap()); } pub fn clear(&mut self) { @@ -66,29 +64,34 @@ impl Adapter { self.size = 0; self.skip = 0; self.scratch.clear(); - trace!(LOGGER, "Cleared adapter"); + gst_trace!(CAT, "Cleared adapter"); } pub fn get_available(&self) -> usize { self.size } - fn copy_data(deque: &VecDeque, skip: usize, data: &mut [u8], size: usize) { + fn copy_data( + deque: &VecDeque>, + skip: usize, + data: &mut [u8], + size: usize, + ) { let mut skip = skip; let mut left = size; let mut idx = 0; - trace!(LOGGER, "Copying {} bytes", size); + gst_trace!(CAT, "Copying {} bytes", size); for item in deque { let data_item = item.as_slice(); let to_copy = cmp::min(left, data_item.len() - skip); - trace!( - LOGGER, + gst_trace!( + CAT, "Copying {} bytes from {:?}, {} more to go", to_copy, - item, + item.get_buffer(), left - to_copy ); @@ -107,8 +110,8 @@ impl Adapter { let size = data.len(); if self.size < size { - debug!( - LOGGER, + gst_debug!( + CAT, "Peeking {} bytes into, not enough data: have {}", size, self.size @@ -116,7 +119,7 @@ impl Adapter { return Err(AdapterError::NotEnoughData); } - trace!(LOGGER, "Peeking {} bytes into", size); + gst_trace!(CAT, "Peeking {} bytes into", size); if size == 0 { return Ok(()); } @@ -127,8 +130,8 @@ impl Adapter { pub fn peek(&mut self, size: usize) -> Result<&[u8], AdapterError> { if self.size < size { - debug!( - LOGGER, + gst_debug!( + CAT, "Peeking {} bytes, not enough data: have {}", size, self.size @@ -141,13 +144,13 @@ impl Adapter { } if let Some(front) = self.deque.front() { - trace!(LOGGER, "Peeking {} bytes, subbuffer of first", size); + gst_trace!(CAT, "Peeking {} bytes, subbuffer of first", size); if front.get_size() - self.skip >= size { return Ok(&front.as_slice()[self.skip..self.skip + size]); } } - trace!(LOGGER, "Peeking {} bytes, copy to scratch", size); + gst_trace!(CAT, "Peeking {} bytes, copy to scratch", size); self.scratch.truncate(0); self.scratch.reserve(size); @@ -159,10 +162,10 @@ impl Adapter { Ok(self.scratch.as_slice()) } - pub fn get_buffer(&mut self, size: usize) -> Result, AdapterError> { + pub fn get_buffer(&mut self, size: usize) -> Result { if self.size < size { - debug!( - LOGGER, + gst_debug!( + CAT, "Get buffer of {} bytes, not enough data: have {}", size, self.size @@ -171,13 +174,13 @@ impl Adapter { } if size == 0 { - return Ok(Buffer::new()); + return Ok(gst::Buffer::new()); } let sub = self.deque .front() .and_then(|front| if front.get_size() - self.skip >= size { - trace!(LOGGER, "Get buffer of {} bytes, subbuffer of first", size); + gst_trace!(CAT, "Get buffer of {} bytes, subbuffer of first", size); let new = front .get_buffer() .copy_region(self.skip, Some(size)) @@ -192,10 +195,10 @@ impl Adapter { return Ok(s); } - trace!(LOGGER, "Get buffer of {} bytes, copy into new buffer", size); - let mut new = Buffer::new_with_size(size).unwrap(); + gst_trace!(CAT, "Get buffer of {} bytes, copy into new buffer", size); + let mut new = gst::Buffer::with_size(size).unwrap(); { - let mut map = new.get_mut().unwrap().map_readwrite().unwrap(); + let mut map = new.get_mut().unwrap().map_writable().unwrap(); let data = map.as_mut_slice(); Self::copy_data(&self.deque, self.skip, data, size); } @@ -205,8 +208,8 @@ impl Adapter { pub fn flush(&mut self, size: usize) -> Result<(), AdapterError> { if self.size < size { - debug!( - LOGGER, + gst_debug!( + CAT, "Flush {} bytes, not enough data: have {}", size, self.size @@ -218,17 +221,17 @@ impl Adapter { return Ok(()); } - trace!(LOGGER, "Flushing {} bytes, have {}", size, self.size); + gst_trace!(CAT, "Flushing {} bytes, have {}", size, self.size); let mut left = size; while left > 0 { let front_size = self.deque.front().unwrap().get_size() - self.skip; if front_size <= left { - trace!( - LOGGER, + gst_trace!( + CAT, "Flushing whole {:?}, {} more to go", - self.deque.front(), + self.deque.front().map(|b| b.get_buffer()), left - front_size ); self.deque.pop_front(); @@ -236,10 +239,10 @@ impl Adapter { self.skip = 0; left -= front_size; } else { - trace!( - LOGGER, + gst_trace!( + CAT, "Flushing partial {:?}, {} more left", - self.deque.front(), + self.deque.front().map(|b| b.get_buffer()), front_size - left ); self.skip += left; @@ -255,24 +258,17 @@ impl Adapter { #[cfg(test)] mod tests { use super::*; - use std::ptr; - use gst_ffi; - - fn init() { - unsafe { - gst_ffi::gst_init(ptr::null_mut(), ptr::null_mut()); - } - } + use gst; #[test] fn test_push_get() { - init(); + gst::init().unwrap(); let mut a = Adapter::new(); - a.push(Buffer::new_with_size(100).unwrap()); + a.push(gst::Buffer::with_size(100).unwrap()); assert_eq!(a.get_available(), 100); - a.push(Buffer::new_with_size(20).unwrap()); + a.push(gst::Buffer::with_size(20).unwrap()); assert_eq!(a.get_available(), 120); let b = a.get_buffer(20).unwrap(); @@ -282,7 +278,7 @@ mod tests { assert_eq!(a.get_available(), 10); assert_eq!(b.get_size(), 90); - a.push(Buffer::new_with_size(20).unwrap()); + a.push(gst::Buffer::with_size(20).unwrap()); assert_eq!(a.get_available(), 30); let b = a.get_buffer(20).unwrap(); diff --git a/gst-plugin/src/buffer.rs b/gst-plugin/src/buffer.rs deleted file mode 100644 index 64a52535..00000000 --- a/gst-plugin/src/buffer.rs +++ /dev/null @@ -1,583 +0,0 @@ -// Copyright (C) 2016-2017 Sebastian Dröge -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::ptr; -use std::mem; -use std::fmt; -use std::slice; -use std::u64; -use std::usize; - -use miniobject::*; - -use glib_ffi; -use gst_ffi; - -pub struct Buffer(gst_ffi::GstBuffer); - -#[derive(Derivative)] -#[derivative(Debug)] -pub struct ReadBufferMap<'a> { - buffer: &'a Buffer, - #[derivative(Debug = "ignore")] map_info: gst_ffi::GstMapInfo, -} - -#[derive(Derivative)] -#[derivative(Debug)] -pub struct ReadWriteBufferMap<'a> { - buffer: &'a Buffer, - #[derivative(Debug = "ignore")] map_info: gst_ffi::GstMapInfo, -} - -#[derive(Derivative)] -#[derivative(Debug)] -pub struct ReadMappedBuffer { - buffer: GstRc, - #[derivative(Debug = "ignore")] map_info: gst_ffi::GstMapInfo, -} - -#[derive(Derivative)] -#[derivative(Debug)] -pub struct ReadWriteMappedBuffer { - buffer: GstRc, - #[derivative(Debug = "ignore")] map_info: gst_ffi::GstMapInfo, -} - -unsafe impl MiniObject for Buffer { - type PtrType = gst_ffi::GstBuffer; -} - -impl Buffer { - pub fn new() -> GstRc { - unsafe { GstRc::from_owned_ptr(gst_ffi::gst_buffer_new()) } - } - - pub fn new_with_size(size: usize) -> Option> { - let raw = - unsafe { gst_ffi::gst_buffer_new_allocate(ptr::null_mut(), size, ptr::null_mut()) }; - if raw.is_null() { - None - } else { - Some(unsafe { GstRc::from_owned_ptr(raw) }) - } - } - - unsafe extern "C" fn vec_drop(vec: glib_ffi::gpointer) { - let vec: Box> = Box::from_raw(vec as *mut Vec); - drop(vec); - } - - pub fn from_vec(vec: Vec) -> Option> { - let raw = unsafe { - let mut vec = Box::new(vec); - let maxsize = vec.capacity(); - let size = vec.len(); - let data = vec.as_mut_ptr(); - let user_data = Box::into_raw(vec); - gst_ffi::gst_buffer_new_wrapped_full( - gst_ffi::GstMemoryFlags::empty(), - data as glib_ffi::gpointer, - maxsize, - 0, - size, - user_data as glib_ffi::gpointer, - Some(Buffer::vec_drop), - ) - }; - - if raw.is_null() { - None - } else { - Some(unsafe { GstRc::from_owned_ptr(raw) }) - } - } - - pub fn map_read(&self) -> Option { - let mut map_info: gst_ffi::GstMapInfo = unsafe { mem::zeroed() }; - let res = unsafe { - gst_ffi::gst_buffer_map( - self.as_mut_ptr() as *mut gst_ffi::GstBuffer, - &mut map_info, - gst_ffi::GST_MAP_READ, - ) - }; - if res == glib_ffi::GTRUE { - Some(ReadBufferMap { - buffer: self, - map_info: map_info, - }) - } else { - None - } - } - - pub fn map_readwrite(&mut self) -> Option { - let mut map_info: gst_ffi::GstMapInfo = unsafe { mem::zeroed() }; - let res = unsafe { - gst_ffi::gst_buffer_map(self.as_mut_ptr(), &mut map_info, gst_ffi::GST_MAP_READWRITE) - }; - if res == glib_ffi::GTRUE { - Some(ReadWriteBufferMap { - buffer: self, - map_info: map_info, - }) - } else { - None - } - } - - pub fn into_read_mapped_buffer(buffer: GstRc) -> Option { - let mut map_info: gst_ffi::GstMapInfo = unsafe { mem::zeroed() }; - let res = unsafe { - gst_ffi::gst_buffer_map(buffer.as_mut_ptr(), &mut map_info, gst_ffi::GST_MAP_READ) - }; - if res == glib_ffi::GTRUE { - Some(ReadMappedBuffer { - buffer: buffer, - map_info: map_info, - }) - } else { - None - } - } - - pub fn into_readwrite_mapped_buffer(buffer: GstRc) -> Option { - let mut map_info: gst_ffi::GstMapInfo = unsafe { mem::zeroed() }; - let res = unsafe { - gst_ffi::gst_buffer_map( - buffer.as_mut_ptr(), - &mut map_info, - gst_ffi::GST_MAP_READWRITE, - ) - }; - if res == glib_ffi::GTRUE { - Some(ReadWriteMappedBuffer { - buffer: buffer, - map_info: map_info, - }) - } else { - None - } - } - - pub fn append(buffer: GstRc, other: GstRc) -> GstRc { - unsafe { - GstRc::from_owned_ptr(gst_ffi::gst_buffer_append( - buffer.into_ptr() as *mut gst_ffi::GstBuffer, - other.into_ptr() as *mut gst_ffi::GstBuffer, - )) - } - } - - pub fn copy_region(&self, offset: usize, size: Option) -> Option> { - let size_real = size.unwrap_or(usize::MAX); - - let raw = unsafe { - gst_ffi::gst_buffer_copy_region( - self.as_mut_ptr(), - gst_ffi::GST_BUFFER_COPY_ALL, - offset, - size_real, - ) - }; - - if raw.is_null() { - None - } else { - Some(unsafe { GstRc::from_owned_ptr(raw) }) - } - } - - pub fn copy_from_slice(&mut self, offset: usize, slice: &[u8]) -> Result<(), usize> { - let maxsize = self.get_maxsize(); - let size = slice.len(); - - assert!(maxsize >= offset && maxsize - offset >= size); - - let copied = unsafe { - let src = slice.as_ptr(); - gst_ffi::gst_buffer_fill( - self.as_mut_ptr(), - offset, - src as glib_ffi::gconstpointer, - size, - ) - }; - - if copied == size { - Ok(()) - } else { - Err(copied) - } - } - - pub fn copy_to_slice(&self, offset: usize, slice: &mut [u8]) -> Result<(), usize> { - let maxsize = self.get_size(); - let size = slice.len(); - - assert!(maxsize >= offset && maxsize - offset >= size); - - let copied = unsafe { - let dest = slice.as_mut_ptr(); - gst_ffi::gst_buffer_extract(self.as_mut_ptr(), offset, dest as glib_ffi::gpointer, size) - }; - - if copied == size { - Ok(()) - } else { - Err(copied) - } - } - - pub fn get_size(&self) -> usize { - unsafe { gst_ffi::gst_buffer_get_size(self.as_mut_ptr()) } - } - - pub fn get_maxsize(&self) -> usize { - let mut maxsize: usize = 0; - - unsafe { - gst_ffi::gst_buffer_get_sizes_range( - self.as_mut_ptr(), - 0, - -1, - ptr::null_mut(), - &mut maxsize as *mut usize, - ); - }; - - maxsize - } - - pub fn set_size(&mut self, size: usize) { - assert!(self.get_maxsize() >= size); - - unsafe { - gst_ffi::gst_buffer_set_size(self.as_mut_ptr(), size as isize); - } - } - - pub fn get_offset(&self) -> Option { - let offset = self.0.offset; - - if offset == u64::MAX { - None - } else { - Some(offset) - } - } - - pub fn set_offset(&mut self, offset: Option) { - let offset = offset.unwrap_or(u64::MAX); - self.0.offset = offset; - } - - pub fn get_offset_end(&self) -> Option { - let offset_end = self.0.offset_end; - - if offset_end == u64::MAX { - None - } else { - Some(offset_end) - } - } - - pub fn set_offset_end(&mut self, offset_end: Option) { - let offset_end = offset_end.unwrap_or(u64::MAX); - self.0.offset_end = offset_end; - } - - pub fn get_pts(&self) -> Option { - let pts = self.0.pts; - - if pts == u64::MAX { - None - } else { - Some(pts) - } - } - - pub fn set_pts(&mut self, pts: Option) { - let pts = pts.unwrap_or(u64::MAX); - self.0.pts = pts; - } - - pub fn get_dts(&self) -> Option { - let dts = self.0.dts; - - if dts == u64::MAX { - None - } else { - Some(dts) - } - } - - pub fn set_dts(&mut self, dts: Option) { - let dts = dts.unwrap_or(u64::MAX); - self.0.dts = dts; - } - - pub fn get_duration(&self) -> Option { - let duration = self.0.duration; - - if duration == u64::MAX { - None - } else { - Some(duration) - } - } - - pub fn set_duration(&mut self, duration: Option) { - let duration = duration.unwrap_or(u64::MAX); - self.0.duration = duration; - } - - pub fn get_flags(&self) -> BufferFlags { - BufferFlags::from_bits_truncate(self.0.mini_object.flags) - } - - pub fn set_flags(&mut self, flags: BufferFlags) { - self.0.mini_object.flags = flags.bits(); - } -} - -unsafe impl Sync for Buffer {} -unsafe impl Send for Buffer {} - -impl fmt::Debug for Buffer { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", unsafe { self.as_ptr() }) - } -} - -impl PartialEq for Buffer { - fn eq(&self, other: &Buffer) -> bool { - if self.get_size() != other.get_size() { - return false; - } - - let self_map = self.map_read(); - let other_map = other.map_read(); - - match (self_map, other_map) { - (Some(self_map), Some(other_map)) => self_map.as_slice().eq(other_map.as_slice()), - _ => false, - } - } -} - -impl Eq for Buffer {} - -impl ToOwned for Buffer { - type Owned = GstRc; - - fn to_owned(&self) -> GstRc { - unsafe { GstRc::from_unowned_ptr(self.as_ptr()) } - } -} - -impl<'a> ReadBufferMap<'a> { - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.map_info.data as *const u8, self.map_info.size) } - } - - pub fn get_size(&self) -> usize { - self.map_info.size - } - - pub fn get_buffer(&self) -> &Buffer { - self.buffer - } -} - -impl<'a> Drop for ReadBufferMap<'a> { - fn drop(&mut self) { - unsafe { - gst_ffi::gst_buffer_unmap(self.buffer.as_mut_ptr(), &mut self.map_info); - } - } -} - -impl<'a> ReadWriteBufferMap<'a> { - pub fn as_mut_slice(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.map_info.data as *mut u8, self.map_info.size) } - } - - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.map_info.data as *const u8, self.map_info.size) } - } - - pub fn get_size(&self) -> usize { - self.map_info.size - } - - pub fn get_buffer(&self) -> &Buffer { - self.buffer - } -} - -impl<'a> Drop for ReadWriteBufferMap<'a> { - fn drop(&mut self) { - unsafe { - gst_ffi::gst_buffer_unmap(self.buffer.as_mut_ptr(), &mut self.map_info); - } - } -} - -impl ReadMappedBuffer { - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.map_info.data as *const u8, self.map_info.size) } - } - - pub fn get_size(&self) -> usize { - self.map_info.size - } - - pub fn get_buffer(&self) -> &Buffer { - self.buffer.as_ref() - } -} - -impl Drop for ReadMappedBuffer { - fn drop(&mut self) { - unsafe { - gst_ffi::gst_buffer_unmap(self.buffer.as_mut_ptr(), &mut self.map_info); - } - } -} - -unsafe impl Sync for ReadMappedBuffer {} -unsafe impl Send for ReadMappedBuffer {} - -impl ReadWriteMappedBuffer { - pub fn as_mut_slice(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.map_info.data as *mut u8, self.map_info.size) } - } - - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.map_info.data as *const u8, self.map_info.size) } - } - - pub fn get_size(&self) -> usize { - self.map_info.size - } - - pub fn get_buffer(&self) -> &Buffer { - self.buffer.as_ref() - } -} - -impl Drop for ReadWriteMappedBuffer { - fn drop(&mut self) { - unsafe { - gst_ffi::gst_buffer_unmap(self.buffer.as_mut_ptr(), &mut self.map_info); - } - } -} - -unsafe impl Sync for ReadWriteMappedBuffer {} -unsafe impl Send for ReadWriteMappedBuffer {} - -// FIXME: Duplicate of gst_ffi::GstBufferFlags with nicer naming -bitflags! { - #[repr(C)] - pub struct BufferFlags: u32 { - const BUFFER_FLAG_LIVE = 0b0000000000010000; - const BUFFER_FLAG_DECODE_ONLY = 0b0000000000100000; - const BUFFER_FLAG_DISCONT = 0b0000000001000000; - const BUFFER_FLAG_RESYNC = 0b0000000010000000; - const BUFFER_FLAG_CORRUPTED = 0b0000000100000000; - const BUFFER_FLAG_MARKER = 0b0000001000000000; - const BUFFER_FLAG_HEADER = 0b0000010000000000; - const BUFFER_FLAG_GAP = 0b0000100000000000; - const BUFFER_FLAG_DROPPABLE = 0b0001000000000000; - const BUFFER_FLAG_DELTA_UNIT = 0b0010000000000000; - const BUFFER_FLAG_TAG_MEMORY = 0b0100000000000000; - const BUFFER_FLAG_SYNC_AFTER = 0b1000000000000000; - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::ptr; - - fn init() { - unsafe { - gst_ffi::gst_init(ptr::null_mut(), ptr::null_mut()); - } - } - - #[test] - fn test_fields() { - init(); - - let mut buffer = Buffer::new(); - - { - let buffer = buffer.get_mut().unwrap(); - buffer.set_pts(Some(1)); - buffer.set_dts(Some(2)); - buffer.set_offset(Some(3)); - buffer.set_offset_end(Some(4)); - buffer.set_duration(Some(5)); - } - assert_eq!(buffer.get_pts(), Some(1)); - assert_eq!(buffer.get_dts(), Some(2)); - assert_eq!(buffer.get_offset(), Some(3)); - assert_eq!(buffer.get_offset_end(), Some(4)); - assert_eq!(buffer.get_duration(), Some(5)); - } - - #[test] - fn test_writability() { - init(); - - let mut buffer = Buffer::from_vec(vec![1, 2, 3, 4]).unwrap(); - { - let data = buffer.map_read().unwrap(); - assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); - } - assert_ne!(buffer.get_mut(), None); - { - let buffer = buffer.get_mut().unwrap(); - buffer.set_pts(Some(1)); - } - - let mut buffer2 = buffer.clone(); - assert_eq!(buffer.get_mut(), None); - - unsafe { - assert_eq!(buffer2.as_ptr(), buffer.as_ptr()); - } - - { - let buffer2 = buffer2.make_mut(); - unsafe { - assert_ne!(buffer2.as_ptr(), buffer.as_ptr()); - } - - buffer2.set_pts(Some(2)); - - let mut data = buffer2.map_readwrite().unwrap(); - assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); - data.as_mut_slice()[0] = 0; - } - - assert_eq!(buffer.get_pts(), Some(1)); - assert_eq!(buffer2.get_pts(), Some(2)); - - { - let data = buffer.map_read().unwrap(); - assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); - - let data = buffer2.map_read().unwrap(); - assert_eq!(data.as_slice(), vec![0, 2, 3, 4].as_slice()); - } - } -} diff --git a/gst-plugin/src/caps.rs b/gst-plugin/src/caps.rs deleted file mode 100644 index eae49bab..00000000 --- a/gst-plugin/src/caps.rs +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (C) 2016-2017 Sebastian Dröge -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::ffi::CString; -use std::ffi::CStr; -use std::fmt; -use value::*; -use miniobject::*; -use structure::*; - -use glib_ffi; -use gst_ffi; - -#[repr(C)] -pub struct Caps(gst_ffi::GstCaps); - -unsafe impl MiniObject for Caps { - type PtrType = gst_ffi::GstCaps; -} - -impl Caps { - pub fn new_empty() -> GstRc { - unsafe { GstRc::from_owned_ptr(gst_ffi::gst_caps_new_empty()) } - } - - pub fn new_any() -> GstRc { - unsafe { GstRc::from_owned_ptr(gst_ffi::gst_caps_new_any()) } - } - - pub fn new_simple(name: &str, values: &[(&str, Value)]) -> GstRc { - let mut caps = Caps::new_empty(); - - let name_cstr = CString::new(name).unwrap(); - let structure = unsafe { gst_ffi::gst_structure_new_empty(name_cstr.as_ptr()) }; - - unsafe { - gst_ffi::gst_caps_append_structure(caps.as_mut_ptr(), structure); - } - - caps.get_mut().unwrap().set_simple(values); - - caps - } - - pub fn from_string(value: &str) -> Option> { - let value_cstr = CString::new(value).unwrap(); - - unsafe { - let caps_ptr = gst_ffi::gst_caps_from_string(value_cstr.as_ptr()); - - if caps_ptr.is_null() { - None - } else { - Some(GstRc::from_owned_ptr(caps_ptr)) - } - } - } - - pub fn set_simple(&mut self, values: &[(&str, Value)]) { - for value in values { - let name_cstr = CString::new(value.0).unwrap(); - unsafe { - let gvalue = value.1.as_ptr(); - gst_ffi::gst_caps_set_value(self.as_mut_ptr(), name_cstr.as_ptr(), gvalue); - } - } - } - - pub fn to_string(&self) -> String { - unsafe { - let ptr = gst_ffi::gst_caps_to_string(self.as_ptr()); - let s = CStr::from_ptr(ptr).to_str().unwrap().into(); - glib_ffi::g_free(ptr as glib_ffi::gpointer); - - s - } - } - - pub fn get_structure(&self, idx: u32) -> Option<&Structure> { - unsafe { - let structure = gst_ffi::gst_caps_get_structure(self.as_ptr(), idx); - if structure.is_null() { - return None; - } - - Some(Structure::from_borrowed_ptr( - structure as *const gst_ffi::GstStructure, - )) - } - } - - pub fn get_mut_structure(&mut self, idx: u32) -> Option<&mut Structure> { - unsafe { - let structure = gst_ffi::gst_caps_get_structure(self.as_ptr(), idx); - if structure.is_null() { - return None; - } - - Some(Structure::from_borrowed_mut_ptr( - structure as *mut gst_ffi::GstStructure, - )) - } - } - - // TODO: All kinds of caps operations -} - -impl fmt::Debug for Caps { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl PartialEq for Caps { - fn eq(&self, other: &Caps) -> bool { - (unsafe { gst_ffi::gst_caps_is_equal(self.as_ptr(), other.as_ptr()) } == glib_ffi::GTRUE) - } -} - -impl Eq for Caps {} - -impl ToOwned for Caps { - type Owned = GstRc; - - fn to_owned(&self) -> GstRc { - unsafe { GstRc::from_unowned_ptr(self.as_ptr()) } - } -} - -unsafe impl Sync for Caps {} -unsafe impl Send for Caps {} - -#[cfg(test)] -mod tests { - use super::*; - use std::ptr; - - fn init() { - unsafe { - gst_ffi::gst_init(ptr::null_mut(), ptr::null_mut()); - } - } - - #[test] - fn test_simple() { - init(); - - let caps = Caps::new_simple( - "foo/bar", - &[ - ("int", 12.into()), - ("bool", true.into()), - ("string", "bla".into()), - ("fraction", (1, 2).into()), - ("array", vec![1.into(), 2.into()].into()), - ], - ); - assert_eq!( - caps.to_string(), - "foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, \ - fraction=(fraction)1/2, array=(int)< 1, 2 >" - ); - - let s = caps.get_structure(0).unwrap(); - assert_eq!( - s, - OwnedStructure::new( - "foo/bar", - &[ - ("int", 12.into()), - ("bool", true.into()), - ("string", "bla".into()), - ("fraction", (1, 2).into()), - ("array", vec![1.into(), 2.into()].into()) - ] - ).as_ref() - ); - } -} diff --git a/gst-plugin/src/demuxer.rs b/gst-plugin/src/demuxer.rs index 3213e73d..e4420c70 100644 --- a/gst-plugin/src/demuxer.rs +++ b/gst-plugin/src/demuxer.rs @@ -18,19 +18,15 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::u32; use std::u64; -use slog::Logger; - -use utils::*; use error::*; -use buffer::*; -use miniobject::*; -use log::*; -use caps::Caps; -use plugin::Plugin; use glib_ffi; use gst_ffi; +use glib; +use glib::translate::*; +use gst; + pub type StreamIndex = u32; #[derive(Debug)] @@ -52,7 +48,7 @@ pub enum HandleBufferResult { StreamsChanged(Vec), // TODO need something to replace/add new streams // TODO should probably directly implement the GstStreams new world order - BufferForStream(StreamIndex, GstRc), + BufferForStream(StreamIndex, gst::Buffer), Eos(Option), } @@ -67,7 +63,7 @@ pub trait Demuxer { fn seek(&mut self, start: u64, stop: Option) -> Result; fn handle_buffer( &mut self, - buffer: Option>, + buffer: Option, ) -> Result; fn end_of_stream(&mut self) -> Result<(), ErrorMessage>; @@ -79,12 +75,12 @@ pub trait Demuxer { #[derive(Debug)] pub struct Stream { pub index: StreamIndex, - pub caps: GstRc, + pub caps: gst::Caps, pub stream_id: String, } impl Stream { - pub fn new(index: StreamIndex, caps: GstRc, stream_id: String) -> Stream { + pub fn new(index: StreamIndex, caps: gst::Caps, stream_id: String) -> Stream { Stream { index: index, caps: caps, @@ -95,7 +91,7 @@ impl Stream { pub struct DemuxerWrapper { raw: *mut gst_ffi::GstElement, - logger: Logger, + cat: gst::DebugCategory, demuxer: Mutex>, panicked: AtomicBool, } @@ -104,14 +100,10 @@ impl DemuxerWrapper { fn new(raw: *mut gst_ffi::GstElement, demuxer: Box) -> DemuxerWrapper { DemuxerWrapper { raw: raw, - logger: Logger::root( - GstDebugDrain::new( - Some(unsafe { &Element::new(raw) }), - "rsdemux", - 0, - "Rust demuxer base class", - ), - o!(), + cat: gst::DebugCategory::new( + "rsdemux", + gst::DebugColorFlags::empty(), + "Rust demuxer base class", ), demuxer: Mutex::new(demuxer), panicked: AtomicBool::new(false), @@ -121,8 +113,9 @@ impl DemuxerWrapper { fn start(&self, upstream_size: u64, random_access: bool) -> bool { let demuxer = &mut self.demuxer.lock().unwrap(); - debug!( - self.logger, + gst_debug!( + self.cat, + // TODO obj: demuxer "Starting with upstream size {} and random access {}", upstream_size, random_access @@ -136,11 +129,18 @@ impl DemuxerWrapper { match demuxer.start(upstream_size, random_access) { Ok(..) => { - trace!(self.logger, "Successfully started"); + gst_trace!( + self.cat, + /* TODO obj: demuxer,*/ "Successfully started" + ); true } Err(ref msg) => { - error!(self.logger, "Failed to start: {:?}", msg); + gst_error!( + self.cat, + /* TODO obj: demuxer,*/ "Failed to start: {:?}", + msg + ); self.post_message(msg); false } @@ -149,15 +149,19 @@ impl DemuxerWrapper { fn stop(&self) -> bool { let demuxer = &mut self.demuxer.lock().unwrap(); - debug!(self.logger, "Stopping"); + gst_debug!(self.cat, /* TODO obj: demuxer,*/ "Stopping"); match demuxer.stop() { Ok(..) => { - trace!(self.logger, "Successfully stop"); + gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Successfully stop"); true } Err(ref msg) => { - error!(self.logger, "Failed to stop: {:?}", msg); + gst_error!( + self.cat, + /* TODO obj: demuxer,*/ "Failed to stop: {:?}", + msg + ); self.post_message(msg); false } @@ -168,7 +172,11 @@ impl DemuxerWrapper { let demuxer = &self.demuxer.lock().unwrap(); let seekable = demuxer.is_seekable(); - debug!(self.logger, "Seekable {}", seekable); + gst_debug!( + self.cat, + /* TODO obj: demuxer,*/ "Seekable {}", + seekable + ); seekable } @@ -179,12 +187,16 @@ impl DemuxerWrapper { match demuxer.get_position() { None => { - trace!(self.logger, "Got no position"); + gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Got no position"); *position = u64::MAX; glib_ffi::GFALSE } Some(pos) => { - trace!(self.logger, "Returning position {}", pos); + gst_trace!( + self.cat, + /* TODO obj: demuxer,*/ "Returning position {}", + pos + ); *position = pos; glib_ffi::GTRUE } @@ -196,12 +208,16 @@ impl DemuxerWrapper { match demuxer.get_duration() { None => { - trace!(self.logger, "Got no duration"); + gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Got no duration"); *duration = u64::MAX; glib_ffi::GFALSE } Some(dur) => { - trace!(self.logger, "Returning duration {}", dur); + gst_trace!( + self.cat, + /* TODO obj: demuxer,*/ "Returning duration {}", + dur + ); *duration = dur; glib_ffi::GTRUE } @@ -215,7 +231,12 @@ impl DemuxerWrapper { let stop = if stop == u64::MAX { None } else { Some(stop) }; - debug!(self.logger, "Seeking to {:?}-{:?}", start, stop); + gst_debug!( + self.cat, + /* TODO obj: demuxer,*/ "Seeking to {:?}-{:?}", + start, + stop + ); let res = { let mut demuxer = &mut self.demuxer.lock().unwrap(); @@ -223,7 +244,11 @@ impl DemuxerWrapper { match demuxer.seek(start, stop) { Ok(res) => res, Err(ref msg) => { - error!(self.logger, "Failed to seek: {:?}", msg); + gst_error!( + self.cat, + /* TODO obj: demuxer,*/ "Failed to seek: {:?}", + msg + ); self.post_message(msg); return false; } @@ -232,16 +257,16 @@ impl DemuxerWrapper { match res { SeekResult::TooEarly => { - debug!(self.logger, "Seeked too early"); + gst_debug!(self.cat, /* TODO obj: demuxer,*/ "Seeked too early"); false } SeekResult::Ok(off) => { - trace!(self.logger, "Seeked successfully"); + gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Seeked successfully"); *offset = off; true } SeekResult::Eos => { - debug!(self.logger, "Seeked after EOS"); + gst_debug!(self.cat, /* TODO obj: demuxer,*/ "Seeked after EOS"); *offset = u64::MAX; unsafe { @@ -253,7 +278,7 @@ impl DemuxerWrapper { } } - fn handle_buffer(&self, buffer: GstRc) -> gst_ffi::GstFlowReturn { + fn handle_buffer(&self, buffer: gst::Buffer) -> gst::FlowReturn { extern "C" { fn gst_rs_demuxer_stream_eos(raw: *mut gst_ffi::GstElement, index: u32); fn gst_rs_demuxer_add_stream( @@ -279,12 +304,20 @@ impl DemuxerWrapper { let mut res = { let mut demuxer = &mut self.demuxer.lock().unwrap(); - trace!(self.logger, "Handling buffer {:?}", buffer); + gst_trace!( + self.cat, + /* TODO obj: demuxer,*/ "Handling buffer {:?}", + buffer + ); match demuxer.handle_buffer(Some(buffer)) { Ok(res) => res, Err(flow_error) => { - error!(self.logger, "Failed handling buffer: {:?}", flow_error); + gst_error!( + self.cat, + /* TODO obj: demuxer,*/ "Failed handling buffer: {:?}", + flow_error + ); match flow_error { FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => { self.post_message(msg) @@ -298,24 +331,20 @@ impl DemuxerWrapper { // Loop until AllEos, NeedMoreData or error when pushing downstream loop { - trace!(self.logger, "Handled {:?}", res); + gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Handled {:?}", res); match res { HandleBufferResult::NeedMoreData => { - return gst_ffi::GST_FLOW_OK; - } - HandleBufferResult::StreamAdded(stream) => { - let stream_id_cstr = CString::new(stream.stream_id.as_bytes()).unwrap(); - - unsafe { - gst_rs_demuxer_add_stream( - self.raw, - stream.index, - stream.caps.as_ptr(), - stream_id_cstr.as_ptr(), - ); - } + return gst::FlowReturn::Ok; } + HandleBufferResult::StreamAdded(stream) => unsafe { + gst_rs_demuxer_add_stream( + self.raw, + stream.index, + stream.caps.to_glib_none().0, + stream.stream_id.to_glib_none().0, + ); + }, HandleBufferResult::HaveAllStreams => unsafe { gst_rs_demuxer_added_all_streams(self.raw); }, @@ -323,7 +352,7 @@ impl DemuxerWrapper { gst_rs_demuxer_stream_format_changed( self.raw, stream.index, - stream.caps.as_ptr(), + stream.caps.to_glib_none().0, ); }, HandleBufferResult::StreamsChanged(streams) => for stream in streams { @@ -331,20 +360,16 @@ impl DemuxerWrapper { gst_rs_demuxer_stream_format_changed( self.raw, stream.index, - stream.caps.as_ptr(), + stream.caps.to_glib_none().0, ); } }, HandleBufferResult::BufferForStream(index, buffer) => { let flow_ret = unsafe { - gst_rs_demuxer_stream_push_buffer( - self.raw, - index, - buffer.into_ptr() as *mut gst_ffi::GstBuffer, - ) + gst_rs_demuxer_stream_push_buffer(self.raw, index, buffer.into_ptr()) }; if flow_ret != gst_ffi::GST_FLOW_OK { - return flow_ret; + return from_glib(flow_ret); } } HandleBufferResult::Eos(index) => { @@ -354,21 +379,25 @@ impl DemuxerWrapper { gst_rs_demuxer_stream_eos(self.raw, index); } - return gst_ffi::GST_FLOW_EOS; + return gst::FlowReturn::Eos; } HandleBufferResult::Again => { // nothing, just call again } }; - trace!(self.logger, "Calling again"); + gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Calling again"); res = { let mut demuxer = &mut self.demuxer.lock().unwrap(); match demuxer.handle_buffer(None) { Ok(res) => res, Err(flow_error) => { - error!(self.logger, "Failed calling again: {:?}", flow_error); + gst_error!( + self.cat, + /* TODO obj: demuxer,*/ "Failed calling again: {:?}", + flow_error + ); match flow_error { FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => { self.post_message(msg) @@ -385,11 +414,15 @@ impl DemuxerWrapper { fn end_of_stream(&self) { let mut demuxer = &mut self.demuxer.lock().unwrap(); - debug!(self.logger, "End of stream"); + gst_debug!(self.cat, /* TODO obj: demuxer,*/ "End of stream"); match demuxer.end_of_stream() { Ok(_) => (), Err(ref msg) => { - error!(self.logger, "Failed end of stream: {:?}", msg); + gst_error!( + self.cat, + /* TODO obj: demuxer,*/ "Failed end of stream: {:?}", + msg + ); self.post_message(msg); } } @@ -397,7 +430,7 @@ impl DemuxerWrapper { fn post_message(&self, msg: &ErrorMessage) { unsafe { - msg.post(self.raw); + msg.post(&gst::Element::from_glib_borrow(self.raw)); } } } @@ -405,9 +438,9 @@ impl DemuxerWrapper { #[no_mangle] pub unsafe extern "C" fn demuxer_new( demuxer: *mut gst_ffi::GstElement, - create_instance: fn(Element) -> Box, + create_instance: fn(&gst::Element) -> Box, ) -> *mut DemuxerWrapper { - let instance = create_instance(Element::new(demuxer)); + let instance = create_instance(&from_glib_borrow(demuxer)); Box::into_raw(Box::new(DemuxerWrapper::new(demuxer, instance))) } @@ -424,39 +457,48 @@ pub unsafe extern "C" fn demuxer_start( ) -> glib_ffi::gboolean { let wrap: &DemuxerWrapper = &*ptr; - panic_to_error!(wrap, glib_ffi::GFALSE, { - if wrap.start(upstream_size, random_access != glib_ffi::GFALSE) { - glib_ffi::GTRUE - } else { - glib_ffi::GFALSE - } - }) + panic_to_error!( + wrap, + &gst::Element::from_glib_borrow(wrap.raw as *mut _), + false, + { wrap.start(upstream_size, random_access != glib_ffi::GFALSE) } + ).to_glib() } #[no_mangle] pub unsafe extern "C" fn demuxer_stop(ptr: *const DemuxerWrapper) -> glib_ffi::gboolean { let wrap: &DemuxerWrapper = &*ptr; - panic_to_error!(wrap, glib_ffi::GTRUE, { - if wrap.stop() { - glib_ffi::GTRUE - } else { - glib_ffi::GFALSE + panic_to_error!( + wrap, + &gst::Element::from_glib_borrow(wrap.raw as *mut _), + glib_ffi::GTRUE, + { + if wrap.stop() { + glib_ffi::GTRUE + } else { + glib_ffi::GFALSE + } } - }) + ) } #[no_mangle] pub unsafe extern "C" fn demuxer_is_seekable(ptr: *const DemuxerWrapper) -> glib_ffi::gboolean { let wrap: &DemuxerWrapper = &*ptr; - panic_to_error!(wrap, glib_ffi::GFALSE, { - if wrap.is_seekable() { - glib_ffi::GTRUE - } else { - glib_ffi::GFALSE + panic_to_error!( + wrap, + &gst::Element::from_glib_borrow(wrap.raw as *mut _), + glib_ffi::GFALSE, + { + if wrap.is_seekable() { + glib_ffi::GTRUE + } else { + glib_ffi::GFALSE + } } - }) + ) } #[no_mangle] @@ -466,10 +508,15 @@ pub unsafe extern "C" fn demuxer_get_position( ) -> glib_ffi::gboolean { let wrap: &DemuxerWrapper = &*ptr; - panic_to_error!(wrap, glib_ffi::GFALSE, { - let position = &mut *position; - wrap.get_position(position) - }) + panic_to_error!( + wrap, + &gst::Element::from_glib_borrow(wrap.raw as *mut _), + glib_ffi::GFALSE, + { + let position = &mut *position; + wrap.get_position(position) + } + ) } #[no_mangle] @@ -479,10 +526,15 @@ pub unsafe extern "C" fn demuxer_get_duration( ) -> glib_ffi::gboolean { let wrap: &DemuxerWrapper = &*ptr; - panic_to_error!(wrap, glib_ffi::GFALSE, { - let duration = &mut *duration; - wrap.get_duration(duration) - }) + panic_to_error!( + wrap, + &gst::Element::from_glib_borrow(wrap.raw as *mut _), + glib_ffi::GFALSE, + { + let duration = &mut *duration; + wrap.get_duration(duration) + } + ) } #[no_mangle] @@ -494,15 +546,20 @@ pub unsafe extern "C" fn demuxer_seek( ) -> glib_ffi::gboolean { let wrap: &mut DemuxerWrapper = &mut *ptr; - panic_to_error!(wrap, glib_ffi::GFALSE, { - let offset = &mut *offset; + panic_to_error!( + wrap, + &gst::Element::from_glib_borrow(wrap.raw as *mut _), + glib_ffi::GFALSE, + { + let offset = &mut *offset; - if wrap.seek(start, stop, offset) { - glib_ffi::GTRUE - } else { - glib_ffi::GFALSE + if wrap.seek(start, stop, offset) { + glib_ffi::GTRUE + } else { + glib_ffi::GFALSE + } } - }) + ) } #[no_mangle] @@ -512,19 +569,26 @@ pub unsafe extern "C" fn demuxer_handle_buffer( ) -> gst_ffi::GstFlowReturn { let wrap: &mut DemuxerWrapper = &mut *ptr; - panic_to_error!(wrap, gst_ffi::GST_FLOW_ERROR, { - let buffer = GstRc::from_owned_ptr(buffer); - wrap.handle_buffer(buffer) - }) + panic_to_error!( + wrap, + &gst::Element::from_glib_borrow(wrap.raw as *mut _), + gst::FlowReturn::Error, + { wrap.handle_buffer(from_glib_full(buffer)) } + ).to_glib() } #[no_mangle] pub unsafe extern "C" fn demuxer_end_of_stream(ptr: *mut DemuxerWrapper) { let wrap: &mut DemuxerWrapper = &mut *ptr; - panic_to_error!(wrap, (), { - wrap.end_of_stream(); - }) + panic_to_error!( + wrap, + &gst::Element::from_glib_borrow(wrap.raw as *mut _), + (), + { + wrap.end_of_stream(); + } + ) } pub struct DemuxerInfo<'a> { @@ -534,12 +598,12 @@ pub struct DemuxerInfo<'a> { pub classification: &'a str, pub author: &'a str, pub rank: i32, - pub create_instance: fn(Element) -> Box, - pub input_caps: &'a Caps, - pub output_caps: &'a Caps, + pub create_instance: fn(&gst::Element) -> Box, + pub input_caps: &'a gst::Caps, + pub output_caps: &'a gst::Caps, } -pub fn demuxer_register(plugin: &Plugin, demuxer_info: &DemuxerInfo) { +pub fn demuxer_register(plugin: &gst::Plugin, demuxer_info: &DemuxerInfo) { extern "C" { fn gst_rs_demuxer_register( plugin: *const gst_ffi::GstPlugin, @@ -563,7 +627,7 @@ pub fn demuxer_register(plugin: &Plugin, demuxer_info: &DemuxerInfo) { unsafe { gst_rs_demuxer_register( - plugin.as_ptr(), + plugin.to_glib_none().0, cname.as_ptr(), clong_name.as_ptr(), cdescription.as_ptr(), @@ -571,8 +635,8 @@ pub fn demuxer_register(plugin: &Plugin, demuxer_info: &DemuxerInfo) { cauthor.as_ptr(), demuxer_info.rank, demuxer_info.create_instance as *const c_void, - demuxer_info.input_caps.as_ptr(), - demuxer_info.output_caps.as_ptr(), + demuxer_info.input_caps.to_glib_none().0, + demuxer_info.output_caps.to_glib_none().0, ); } } diff --git a/gst-plugin/src/error.rs b/gst-plugin/src/error.rs index 0fb5b9ec..053359b2 100644 --- a/gst-plugin/src/error.rs +++ b/gst-plugin/src/error.rs @@ -6,9 +6,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::ffi::CString; -use std::ptr; -use libc::c_char; use std::error::Error; use std::fmt::{Display, Formatter}; use std::fmt::Error as FmtError; @@ -19,6 +16,11 @@ use url::Url; use glib_ffi; use gst_ffi; +use glib; +use glib::translate::ToGlibPtr; +use gst; +use gst::prelude::*; + #[macro_export] macro_rules! error_msg( // Plain strings @@ -57,31 +59,19 @@ macro_rules! error_msg( }}; ); -pub trait ToGError { - fn to_gerror(&self) -> (u32, i32); -} - -pub fn gst_library_error_domain() -> glib_ffi::GQuark { - unsafe { gst_ffi::gst_library_error_quark() } -} - -pub fn gst_resource_error_domain() -> glib_ffi::GQuark { - unsafe { gst_ffi::gst_resource_error_quark() } -} - -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub struct ErrorMessage { - pub error_domain: u32, - pub error_code: i32, - pub message: Option, - pub debug: Option, - pub filename: &'static str, - pub function: &'static str, - pub line: u32, + error_domain: glib_ffi::GQuark, + error_code: i32, + message: Option, + debug: Option, + filename: &'static str, + function: &'static str, + line: u32, } impl ErrorMessage { - pub fn new( + pub fn new( error: &T, message: Option>, debug: Option>, @@ -89,11 +79,12 @@ impl ErrorMessage { function: &'static str, line: u32, ) -> ErrorMessage { - let (gdomain, gcode) = error.to_gerror(); + let domain = T::domain(); + let code = error.code(); ErrorMessage { - error_domain: gdomain, - error_code: gcode, + error_domain: domain, + error_code: code, message: message.map(|m| m.into_owned()), debug: debug.map(|d| d.into_owned()), filename: filename, @@ -102,8 +93,7 @@ impl ErrorMessage { } } - - pub unsafe fn post(&self, element: *mut gst_ffi::GstElement) { + pub fn post>(&self, element: &E) { let ErrorMessage { error_domain, error_code, @@ -114,33 +104,23 @@ impl ErrorMessage { line, } = *self; - let message_ptr = message.as_ref().map_or(ptr::null(), |m| m.as_ptr()) as *const c_char; - let message_len = message.as_ref().map_or(0, |m| m.len()); - - let debug_ptr = debug.as_ref().map_or(ptr::null(), |m| m.as_ptr()) as *const c_char; - let debug_len = debug.as_ref().map_or(0, |m| m.len()); - - let file_cstr = CString::new(filename.as_bytes()).unwrap(); - let file_ptr = file_cstr.as_ptr(); - - let function_cstr = CString::new(function.as_bytes()).unwrap(); - let function_ptr = function_cstr.as_ptr(); - - gst_ffi::gst_element_message_full( - element, - gst_ffi::GST_MESSAGE_ERROR, - error_domain, - error_code, - glib_ffi::g_strndup(message_ptr, message_len), - glib_ffi::g_strndup(debug_ptr, debug_len), - file_ptr, - function_ptr, - line as i32, - ); + unsafe { + gst_ffi::gst_element_message_full( + element.to_glib_none().0, + gst_ffi::GST_MESSAGE_ERROR, + error_domain, + error_code, + message.to_glib_none().0, + debug.to_glib_none().0, + filename.to_glib_none().0, + function.to_glib_none().0, + line as i32, + ); + } } } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub enum FlowError { Flushing, Eos, @@ -149,12 +129,12 @@ pub enum FlowError { } impl FlowError { - pub fn to_native(&self) -> gst_ffi::GstFlowReturn { + pub fn to_native(&self) -> gst::FlowReturn { match *self { - FlowError::Flushing => gst_ffi::GST_FLOW_FLUSHING, - FlowError::Eos => gst_ffi::GST_FLOW_EOS, - FlowError::NotNegotiated(..) => gst_ffi::GST_FLOW_NOT_NEGOTIATED, - FlowError::Error(..) => gst_ffi::GST_FLOW_ERROR, + FlowError::Flushing => gst::FlowReturn::Flushing, + FlowError::Eos => gst::FlowReturn::Eos, + FlowError::NotNegotiated(..) => gst::FlowReturn::NotNegotiated, + FlowError::Error(..) => gst::FlowReturn::Error, } } } @@ -190,110 +170,76 @@ impl Error for FlowError { } } -#[derive(Debug)] -pub enum UriErrorKind { - UnsupportedProtocol = 0, - BadUri, - BadState, - BadReference, -} - -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub struct UriError { - error_kind: UriErrorKind, - message: Option, + error: gst::URIError, + message: String, } impl UriError { - pub fn new(error_kind: UriErrorKind, message: Option) -> UriError { + pub fn new(error: gst::URIError, message: String) -> UriError { UriError { - error_kind: error_kind, + error: error, message: message, } } - pub fn message(&self) -> &Option { + pub fn message(&self) -> &str { &self.message } - pub fn kind(&self) -> &UriErrorKind { - &self.error_kind + pub fn error(&self) -> gst::URIError { + self.error } - pub unsafe fn into_gerror(self, err: *mut *mut glib_ffi::GError) { - if let Some(msg) = self.message { - let cmsg = CString::new(msg.as_str()).unwrap(); - glib_ffi::g_set_error_literal( - err, - gst_ffi::gst_uri_error_quark(), - self.error_kind as i32, - cmsg.as_ptr(), - ); - } else { - glib_ffi::g_set_error_literal( - err, - gst_ffi::gst_uri_error_quark(), - self.error_kind as i32, - ptr::null(), - ); - } + pub fn into_error(self) -> glib::Error { + glib::Error::new(self.error, &self.message) } } impl Display for UriError { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - match self.message { - None => f.write_str(self.description()), - Some(ref message) => f.write_fmt(format_args!("{}: {}", self.description(), message)), - } + f.write_fmt(format_args!("{}: {}", self.description(), self.message)) } } impl Error for UriError { fn description(&self) -> &str { - match self.error_kind { - UriErrorKind::UnsupportedProtocol => "Unsupported protocol", - UriErrorKind::BadUri => "Bad URI", - UriErrorKind::BadState => "Bad State", - UriErrorKind::BadReference => "Bad Reference", + match self.error { + gst::URIError::UnsupportedProtocol => "Unsupported protocol", + gst::URIError::BadUri => "Bad URI", + gst::URIError::BadState => "Bad State", + gst::URIError::BadReference => "Bad Reference", + _ => "Unknown", } } } pub type UriValidator = Fn(&Url) -> Result<(), UriError>; -#[derive(Debug)] -pub struct PanicError; - -impl ToGError for PanicError { - fn to_gerror(&self) -> (u32, i32) { - (gst_library_error_domain(), 1) - } -} - #[macro_export] macro_rules! panic_to_error( - ($wrap:expr, $ret:expr, $code:block) => {{ + ($wrap:expr, $element:expr, $ret:expr, $code:block) => {{ if $wrap.panicked.load(Ordering::Relaxed) { - error_msg!(PanicError, ["Panicked"]).post($wrap.raw); - return $ret; - } + error_msg!(gst::LibraryError::Failed, ["Panicked"]).post($element); + $ret + } else { + let result = panic::catch_unwind(AssertUnwindSafe(|| $code)); - let result = panic::catch_unwind(AssertUnwindSafe(|| $code)); - - match result { - Ok(result) => result, - Err(err) => { - $wrap.panicked.store(true, Ordering::Relaxed); - if let Some(cause) = err.downcast_ref::<&str>() { - error_msg!(PanicError, ["Panicked: {}", cause]).post($wrap.raw); - } else if let Some(cause) = err.downcast_ref::() { - error_msg!(PanicError, ["Panicked: {}", cause]).post($wrap.raw); - } else { - error_msg!(PanicError, ["Panicked"]).post($wrap.raw); + match result { + Ok(result) => result, + Err(err) => { + $wrap.panicked.store(true, Ordering::Relaxed); + if let Some(cause) = err.downcast_ref::<&str>() { + error_msg!(gst::LibraryError::Failed, ["Panicked: {}", cause]).post($element); + } else if let Some(cause) = err.downcast_ref::() { + error_msg!(gst::LibraryError::Failed, ["Panicked: {}", cause]).post($element); + } else { + error_msg!(gst::LibraryError::Failed, ["Panicked"]).post($element); + } + $ret } - $ret } } - }} + }}; ); diff --git a/gst-plugin/src/lib.rs b/gst-plugin/src/lib.rs index b55c5851..847d66da 100644 --- a/gst-plugin/src/lib.rs +++ b/gst-plugin/src/lib.rs @@ -7,48 +7,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[macro_use] -extern crate bitflags; extern crate byteorder; -#[macro_use] -extern crate derivative; +extern crate gstreamer_base_sys as gst_base_ffi; #[macro_use] extern crate lazy_static; extern crate libc; -extern crate num_rational; -#[macro_use] -extern crate slog; extern crate url; pub extern crate glib_sys as glib_ffi; pub extern crate gobject_sys as gobject_ffi; -pub extern crate gstreamer_base_sys as gst_base_ffi; pub extern crate gstreamer_sys as gst_ffi; -pub extern crate glib as glib; +extern crate gstreamer_base as gst_base; +#[macro_use] +pub extern crate glib; +#[macro_use] pub extern crate gstreamer as gst; #[macro_use] pub mod utils; #[macro_use] pub mod error; -pub mod buffer; pub mod adapter; #[macro_use] pub mod plugin; pub mod source; pub mod sink; pub mod demuxer; -pub mod log; -pub mod value; -pub mod caps; pub mod bytes; -pub mod tags; -pub mod streams; -pub mod miniobject; -pub mod structure; - -pub mod ffi { - pub use glib_ffi as glib; - pub use gobject_ffi as gobject; - pub use gst_ffi as gst; -} diff --git a/gst-plugin/src/log.rs b/gst-plugin/src/log.rs deleted file mode 100644 index f7762cbc..00000000 --- a/gst-plugin/src/log.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) 2016-2017 Sebastian Dröge -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use libc::c_char; -use std::ffi::CString; -use slog::{Drain, Level, Never, OwnedKVList, Record}; -use std::fmt; -use std::ptr; -use std::mem; - -use utils::Element; - -use gobject_ffi; -use gst_ffi; - -pub struct GstDebugDrain { - category: *mut gst_ffi::GstDebugCategory, - element: Box, -} - -impl GstDebugDrain { - pub fn new( - element: Option<&Element>, - name: &str, - color: u32, - description: &str, - ) -> GstDebugDrain { - extern "C" { - fn _gst_debug_category_new( - name: *const c_char, - color: u32, - description: *const c_char, - ) -> *mut gst_ffi::GstDebugCategory; - } - - let name_cstr = CString::new(name.as_bytes()).unwrap(); - let description_cstr = CString::new(description.as_bytes()).unwrap(); - - // Gets the category if it exists already - let category = unsafe { - _gst_debug_category_new(name_cstr.as_ptr(), color, description_cstr.as_ptr()) - }; - - let element = match element { - Some(element) => unsafe { element.as_ptr() }, - None => ptr::null(), - }; - - let mut drain = GstDebugDrain { - category: category, - element: Box::new(unsafe { mem::zeroed() }), - }; - - if !element.is_null() { - unsafe { - gobject_ffi::g_weak_ref_set( - &mut *drain.element, - element as *mut gobject_ffi::GObject, - ); - } - } - - drain - } -} - -impl Drop for GstDebugDrain { - fn drop(&mut self) { - unsafe { - gobject_ffi::g_weak_ref_clear(&mut *self.element); - } - } -} - -impl Drain for GstDebugDrain { - type Ok = (); - type Err = Never; - - fn log(&self, record: &Record, _: &OwnedKVList) -> Result<(), Never> { - let level = match record.level() { - Level::Critical | Level::Error => gst_ffi::GST_LEVEL_ERROR, - Level::Warning => gst_ffi::GST_LEVEL_WARNING, - Level::Info => gst_ffi::GST_LEVEL_INFO, - Level::Debug => gst_ffi::GST_LEVEL_DEBUG, - Level::Trace => gst_ffi::GST_LEVEL_TRACE, - }; - - let threshold = unsafe { gst_ffi::gst_debug_category_get_threshold(self.category) }; - - if level as u32 > threshold as u32 { - return Ok(()); - } - - let file_cstr = CString::new(record.file().as_bytes()).unwrap(); - - // TODO: Probably want to include module? - let function_cstr = CString::new(record.function().as_bytes()).unwrap(); - - let message_cstr = CString::new(fmt::format(*record.msg()).as_bytes()).unwrap(); - - unsafe { - let element = gobject_ffi::g_weak_ref_get( - &*self.element as *const gobject_ffi::GWeakRef as *mut gobject_ffi::GWeakRef, - ); - - gst_ffi::gst_debug_log( - self.category, - level, - file_cstr.as_ptr(), - function_cstr.as_ptr(), - record.line() as i32, - element as *mut gobject_ffi::GObject, - message_cstr.as_ptr(), - ); - - if !element.is_null() { - gst_ffi::gst_object_unref(element as *mut gst_ffi::GstObject); - } - } - - Ok(()) - } -} - -unsafe impl Sync for GstDebugDrain {} -unsafe impl Send for GstDebugDrain {} diff --git a/gst-plugin/src/miniobject.rs b/gst-plugin/src/miniobject.rs deleted file mode 100644 index a791aab1..00000000 --- a/gst-plugin/src/miniobject.rs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (C) 2016-2017 Sebastian Dröge -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::{borrow, fmt, ops}; -use std::mem; -use std::marker::PhantomData; - -use glib_ffi; -use gst_ffi; - -#[derive(Hash, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct GstRc(*mut T, PhantomData); - -impl GstRc { - unsafe fn new(obj: *const T, owned: bool) -> Self { - assert!(!obj.is_null()); - - if !owned { - gst_ffi::gst_mini_object_ref((&*obj).as_ptr() as *mut gst_ffi::GstMiniObject); - } - - GstRc(obj as *mut T, PhantomData) - } - - pub unsafe fn from_owned_ptr(ptr: *const T::PtrType) -> Self { - Self::new(T::from_ptr(ptr), true) - } - - pub unsafe fn from_unowned_ptr(ptr: *const T::PtrType) -> Self { - Self::new(T::from_ptr(ptr), false) - } - - pub fn make_mut(&mut self) -> &mut T { - unsafe { - if self.is_writable() { - return &mut *self.0; - } - - self.0 = T::from_mut_ptr(gst_ffi::gst_mini_object_make_writable( - self.as_mut_ptr() as *mut gst_ffi::GstMiniObject, - ) as *mut T::PtrType); - assert!(self.is_writable()); - - &mut *self.0 - } - } - - pub fn get_mut(&mut self) -> Option<&mut T> { - if self.is_writable() { - Some(unsafe { &mut *self.0 }) - } else { - None - } - } - - pub fn copy(&self) -> Self { - unsafe { - GstRc::from_owned_ptr( - gst_ffi::gst_mini_object_copy(self.as_ptr() as *const gst_ffi::GstMiniObject) as - *const T::PtrType, - ) - } - } - - fn is_writable(&self) -> bool { - (unsafe { - gst_ffi::gst_mini_object_is_writable(self.as_ptr() as *const gst_ffi::GstMiniObject) - } == glib_ffi::GTRUE) - } - - pub unsafe fn into_ptr(self) -> *mut T::PtrType { - let ptr = self.as_mut_ptr(); - mem::forget(self); - - ptr - } -} - -impl ops::Deref for GstRc { - type Target = T; - fn deref(&self) -> &T { - self.as_ref() - } -} - -impl AsRef for GstRc { - fn as_ref(&self) -> &T { - unsafe { &*self.0 } - } -} - -impl borrow::Borrow for GstRc { - fn borrow(&self) -> &T { - self.as_ref() - } -} - -// FIXME: Not generally possible because neither T nor ToOwned are defined here... -//impl ToOwned for T { -// type Owned = GstRc; -// -// fn to_owned(&self) -> GstRc { -// unsafe { GstRc::from_unowned_ptr(self.as_ptr()) } -// } -//} - -impl Clone for GstRc { - fn clone(&self) -> GstRc { - unsafe { GstRc::from_unowned_ptr(self.as_ptr()) } - } -} - -impl Drop for GstRc { - fn drop(&mut self) { - unsafe { - gst_ffi::gst_mini_object_unref(self.as_ptr() as *mut gst_ffi::GstMiniObject); - } - } -} - -unsafe impl Sync for GstRc {} -unsafe impl Send for GstRc {} - -impl fmt::Display for GstRc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (unsafe { &*self.0 }).fmt(f) - } -} - -pub unsafe trait MiniObject -where - Self: Sized, -{ - type PtrType; - - unsafe fn as_ptr(&self) -> *const Self::PtrType { - self as *const Self as *const Self::PtrType - } - - unsafe fn as_mut_ptr(&self) -> *mut Self::PtrType { - self as *const Self as *mut Self::PtrType - } - - unsafe fn from_ptr<'a>(ptr: *const Self::PtrType) -> &'a Self { - assert!(!ptr.is_null()); - &*(ptr as *const Self) - } - - unsafe fn from_mut_ptr<'a>(ptr: *mut Self::PtrType) -> &'a mut Self { - assert!(!ptr.is_null()); - &mut *(ptr as *mut Self) - } -} diff --git a/gst-plugin/src/plugin.rs b/gst-plugin/src/plugin.rs index 8a7fe59a..c3bb7c2d 100644 --- a/gst-plugin/src/plugin.rs +++ b/gst-plugin/src/plugin.rs @@ -6,39 +6,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use gst_ffi; - -pub struct Plugin(*mut gst_ffi::GstPlugin); - -impl Plugin { - pub unsafe fn new(plugin: *mut gst_ffi::GstPlugin) -> Plugin { - Plugin(plugin) - } - - pub unsafe fn as_ptr(&self) -> *mut gst_ffi::GstPlugin { - self.0 - } -} - #[macro_export] 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 $crate::plugin::Plugin; + use $crate::glib::translate::{from_glib_borrow, ToGlib}; // Not using c_char here because it requires the libc crate #[allow(non_camel_case_types)] type c_char = i8; #[repr(C)] - pub struct GstPluginDesc($crate::ffi::gst::GstPluginDesc); + pub struct GstPluginDesc($crate::gst_ffi::GstPluginDesc); unsafe impl Sync for GstPluginDesc {} #[no_mangle] #[allow(non_upper_case_globals)] - pub static gst_plugin_desc: GstPluginDesc = GstPluginDesc($crate::ffi::gst::GstPluginDesc { + pub static gst_plugin_desc: GstPluginDesc = GstPluginDesc($crate::gst_ffi::GstPluginDesc { major_version: 1, minor_version: 10, name: $name as *const u8 as *const c_char, @@ -50,15 +36,11 @@ macro_rules! plugin_define( package: $package as *const u8 as *const c_char, origin: $origin as *const u8 as *const c_char, release_datetime: $release_datetime as *const u8 as *const c_char, - _gst_reserved: [0 as $crate::ffi::glib::gpointer; 4], + _gst_reserved: [0 as $crate::glib_ffi::gpointer; 4], }); - unsafe extern "C" fn plugin_init_trampoline(plugin: *mut $crate::ffi::gst::GstPlugin) -> $crate::ffi::glib::gboolean { - if super::$plugin_init(&Plugin::new(plugin)) { - $crate::ffi::glib::GTRUE - } else { - $crate::ffi::glib::GFALSE - } + unsafe extern "C" fn plugin_init_trampoline(plugin: *mut $crate::gst_ffi::GstPlugin) -> $crate::glib_ffi::gboolean { + super::$plugin_init(&from_glib_borrow(plugin)).to_glib() } } }; diff --git a/gst-plugin/src/sink.rs b/gst-plugin/src/sink.rs index baef922f..b52bd41e 100644 --- a/gst-plugin/src/sink.rs +++ b/gst-plugin/src/sink.rs @@ -19,45 +19,21 @@ use std::sync::atomic::{AtomicBool, Ordering}; use url::Url; -use slog::Logger; - -use utils::*; use error::*; -use buffer::*; -use miniobject::*; -use log::*; -use plugin::Plugin; -use caps::*; use glib_ffi; use gobject_ffi; use gst_ffi; use gst_base_ffi; -#[derive(Debug)] -pub enum SinkError { - Failure, - OpenFailed, - NotFound, - WriteFailed, - SeekFailed, -} - -impl ToGError for SinkError { - fn to_gerror(&self) -> (u32, i32) { - match *self { - SinkError::Failure => (gst_library_error_domain(), 1), - SinkError::OpenFailed => (gst_resource_error_domain(), 6), - SinkError::NotFound => (gst_resource_error_domain(), 3), - SinkError::WriteFailed => (gst_resource_error_domain(), 10), - SinkError::SeekFailed => (gst_resource_error_domain(), 11), - } - } -} +use glib::translate::*; +use gst; +use gst::prelude::*; +use gst_base; +use gst_base::prelude::*; pub struct SinkWrapper { - raw: *mut gst_ffi::GstElement, - logger: Logger, + cat: gst::DebugCategory, uri: Mutex<(Option, bool)>, uri_validator: Box, sink: Mutex>, @@ -67,24 +43,19 @@ pub struct SinkWrapper { pub trait Sink { fn uri_validator(&self) -> Box; - fn start(&mut self, uri: Url) -> Result<(), ErrorMessage>; - fn stop(&mut self) -> Result<(), ErrorMessage>; + fn start(&mut self, sink: &RsSinkWrapper, uri: Url) -> Result<(), ErrorMessage>; + fn stop(&mut self, sink: &RsSinkWrapper) -> Result<(), ErrorMessage>; - fn render(&mut self, buffer: &Buffer) -> Result<(), FlowError>; + fn render(&mut self, sink: &RsSinkWrapper, buffer: &gst::BufferRef) -> Result<(), FlowError>; } impl SinkWrapper { - fn new(raw: *mut gst_ffi::GstElement, sink: Box) -> SinkWrapper { + fn new(sink: Box) -> SinkWrapper { SinkWrapper { - raw: raw, - logger: Logger::root( - GstDebugDrain::new( - Some(unsafe { &Element::new(raw) }), - "rssink", - 0, - "Rust sink base class", - ), - o!(), + cat: gst::DebugCategory::new( + "rssink", + gst::DebugColorFlags::empty(), + "Rust sink base class", ), uri: Mutex::new((None, false)), uri_validator: sink.uri_validator(), @@ -93,15 +64,15 @@ impl SinkWrapper { } } - fn set_uri(&self, uri_str: Option<&str>) -> Result<(), UriError> { + fn set_uri(&self, sink: &RsSinkWrapper, uri_str: Option<&str>) -> Result<(), UriError> { let uri_storage = &mut self.uri.lock().unwrap(); - debug!(self.logger, "Setting URI {:?}", uri_str); + gst_debug!(self.cat, obj: sink, "Setting URI {:?}", uri_str); if uri_storage.1 { return Err(UriError::new( - UriErrorKind::BadState, - Some("Already started".to_string()), + gst::URIError::BadState, + "Already started".to_string(), )); } @@ -115,8 +86,8 @@ impl SinkWrapper { Ok(()) } Err(err) => Err(UriError::new( - UriErrorKind::BadUri, - Some(format!("Failed to parse URI '{}': {}", uri_str, err)), + gst::URIError::BadUri, + format!("Failed to parse URI '{}': {}", uri_str, err), )), } } else { @@ -124,13 +95,13 @@ impl SinkWrapper { } } - fn get_uri(&self) -> Option { + fn get_uri(&self, _sink: &RsSinkWrapper) -> Option { let uri_storage = &self.uri.lock().unwrap(); uri_storage.0.as_ref().map(|uri| String::from(uri.as_str())) } - fn start(&self) -> bool { - debug!(self.logger, "Starting"); + fn start(&self, sink: &RsSinkWrapper) -> bool { + gst_debug!(self.cat, obj: sink, "Starting"); // Don't keep the URI locked while we call start later let uri = match *self.uri.lock().unwrap() { @@ -139,60 +110,63 @@ impl SinkWrapper { uri.clone() } (None, _) => { - error!(self.logger, "No URI given"); - self.post_message(&error_msg!(SinkError::OpenFailed, ["No URI given"])); + gst_error!(self.cat, obj: sink, "No URI given"); + self.post_message( + sink, + &error_msg!(gst::ResourceError::OpenWrite, ["No URI given"]), + ); return false; } }; - let sink = &mut self.sink.lock().unwrap(); - match sink.start(uri) { + let sink_impl = &mut self.sink.lock().unwrap(); + match sink_impl.start(sink, uri) { Ok(..) => { - trace!(self.logger, "Started successfully"); + gst_trace!(self.cat, obj: sink, "Started successfully"); true } Err(ref msg) => { - error!(self.logger, "Failed to start: {:?}", msg); + gst_error!(self.cat, obj: sink, "Failed to start: {:?}", msg); self.uri.lock().unwrap().1 = false; - self.post_message(msg); + self.post_message(sink, msg); false } } } - fn stop(&self) -> bool { - let sink = &mut self.sink.lock().unwrap(); + fn stop(&self, sink: &RsSinkWrapper) -> bool { + let sink_impl = &mut self.sink.lock().unwrap(); - debug!(self.logger, "Stopping"); + gst_debug!(self.cat, obj: sink, "Stopping"); - match sink.stop() { + match sink_impl.stop(sink) { Ok(..) => { - trace!(self.logger, "Stopped successfully"); + gst_trace!(self.cat, obj: sink, "Stopped successfully"); self.uri.lock().unwrap().1 = false; true } Err(ref msg) => { - error!(self.logger, "Failed to stop: {:?}", msg); + gst_error!(self.cat, obj: sink, "Failed to stop: {:?}", msg); - self.post_message(msg); + self.post_message(sink, msg); false } } } - fn render(&self, buffer: &Buffer) -> gst_ffi::GstFlowReturn { - let sink = &mut self.sink.lock().unwrap(); + fn render(&self, sink: &RsSinkWrapper, buffer: &gst::BufferRef) -> gst::FlowReturn { + let sink_impl = &mut self.sink.lock().unwrap(); - trace!(self.logger, "Rendering buffer {:?}", buffer); + gst_trace!(self.cat, obj: sink, "Rendering buffer {:?}", buffer); - match sink.render(buffer) { - Ok(..) => gst_ffi::GST_FLOW_OK, + match sink_impl.render(sink, buffer) { + Ok(..) => gst::FlowReturn::Ok, Err(flow_error) => { - error!(self.logger, "Failed to render: {:?}", flow_error); + gst_error!(self.cat, obj: sink, "Failed to render: {:?}", flow_error); match flow_error { FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => { - self.post_message(msg) + self.post_message(sink, msg) } _ => (), } @@ -201,86 +175,75 @@ impl SinkWrapper { } } - fn post_message(&self, msg: &ErrorMessage) { - unsafe { - msg.post(self.raw); - } + fn post_message(&self, sink: &RsSinkWrapper, msg: &ErrorMessage) { + msg.post(sink); } } unsafe fn sink_set_uri( - ptr: *const RsSink, + ptr: *mut RsSink, uri_ptr: *const c_char, cerr: *mut *mut glib_ffi::GError, ) -> glib_ffi::gboolean { - let sink = &*(ptr as *const RsSink); - let wrap: &SinkWrapper = &*sink.wrap; + let sink: &RsSinkWrapper = &from_glib_borrow(ptr as *mut RsSink); + let wrap = sink.get_wrap(); - panic_to_error!(wrap, glib_ffi::GFALSE, { + panic_to_error!(wrap, sink, false, { let uri_str = if uri_ptr.is_null() { None } else { Some(CStr::from_ptr(uri_ptr).to_str().unwrap()) }; - match wrap.set_uri(uri_str) { + match wrap.set_uri(sink, uri_str) { Err(err) => { - error!(wrap.logger, "Failed to set URI {:?}", err); - err.into_gerror(cerr); - glib_ffi::GFALSE + gst_error!(wrap.cat, obj: sink, "Failed to set URI {:?}", err); + if !cerr.is_null() { + let err = err.into_error(); + *cerr = err.to_glib_full() as *mut _; + } + false } - Ok(_) => glib_ffi::GTRUE, + Ok(_) => true, } - }) + }).to_glib() } -unsafe fn sink_get_uri(ptr: *const RsSink) -> *mut c_char { - let sink = &*(ptr as *const RsSink); - let wrap: &SinkWrapper = &*sink.wrap; +unsafe fn sink_get_uri(ptr: *mut RsSink) -> *mut c_char { + let sink: &RsSinkWrapper = &from_glib_borrow(ptr as *mut RsSink); + let wrap = sink.get_wrap(); - panic_to_error!(wrap, ptr::null_mut(), { - match wrap.get_uri() { - Some(uri_str) => glib_ffi::g_strndup(uri_str.as_ptr() as *const c_char, uri_str.len()), - None => ptr::null_mut(), - } - }) + panic_to_error!(wrap, sink, None, { wrap.get_uri(sink) }).to_glib_full() } unsafe extern "C" fn sink_start(ptr: *mut gst_base_ffi::GstBaseSink) -> glib_ffi::gboolean { - let sink = &*(ptr as *const RsSink); - let wrap: &SinkWrapper = &*sink.wrap; + let sink: &RsSinkWrapper = &from_glib_borrow(ptr as *mut RsSink); + let wrap = sink.get_wrap(); - panic_to_error!(wrap, glib_ffi::GFALSE, { - if wrap.start() { - glib_ffi::GTRUE - } else { - glib_ffi::GFALSE - } - }) + panic_to_error!(wrap, sink, false, { wrap.start(sink) }).to_glib() } unsafe extern "C" fn sink_stop(ptr: *mut gst_base_ffi::GstBaseSink) -> glib_ffi::gboolean { - let sink = &*(ptr as *const RsSink); - let wrap: &SinkWrapper = &*sink.wrap; + let sink: &RsSinkWrapper = &from_glib_borrow(ptr as *mut RsSink); + let wrap = sink.get_wrap(); - panic_to_error!(wrap, glib_ffi::GTRUE, { - if wrap.stop() { - glib_ffi::GTRUE - } else { - glib_ffi::GFALSE - } - }) + panic_to_error!(wrap, sink, true, { wrap.stop(sink) }).to_glib() } unsafe extern "C" fn sink_render( ptr: *mut gst_base_ffi::GstBaseSink, buffer: *mut gst_ffi::GstBuffer, ) -> gst_ffi::GstFlowReturn { - let sink = &*(ptr as *const RsSink); - let wrap: &SinkWrapper = &*sink.wrap; - let buffer: &Buffer = Buffer::from_ptr(buffer); + let sink: &RsSinkWrapper = &from_glib_borrow(ptr as *mut RsSink); + let wrap = sink.get_wrap(); + let buffer = gst::BufferRef::from_ptr(buffer); - panic_to_error!(wrap, gst_ffi::GST_FLOW_ERROR, { wrap.render(buffer) }) + panic_to_error!( + wrap, + sink, + gst::FlowReturn::Error, + { wrap.render(sink, buffer) } + ).to_glib() } pub struct SinkInfo { @@ -290,31 +253,111 @@ pub struct SinkInfo { pub classification: String, pub author: String, pub rank: u32, - pub create_instance: fn(Element) -> Box, + pub create_instance: fn(&RsSinkWrapper) -> Box, pub protocols: Vec, } -#[repr(C)] -struct RsSink { - parent: gst_base_ffi::GstBaseSink, - wrap: *mut SinkWrapper, - sink_info: *const SinkInfo, +glib_wrapper! { + pub struct RsSinkWrapper(Object): [gst_base::BaseSink => gst_base_ffi::GstBaseSink, + gst::Element => gst_ffi::GstElement, + gst::Object => gst_ffi::GstObject, + gst::URIHandler => gst_ffi::GstURIHandler, + ]; + + match fn { + get_type => || rs_sink_get_type(), + } +} +impl RsSinkWrapper { + fn get_wrap(&self) -> &SinkWrapper { + let stash = self.to_glib_none(); + let sink: *mut RsSink = stash.0; + + unsafe { &*((*sink).wrap) } + } +} + +#[repr(u32)] +enum Properties { + PropURI = 1u32, } #[repr(C)] -struct RsSinkClass { +pub struct RsSink { + parent: gst_base_ffi::GstBaseSink, + wrap: *mut SinkWrapper, +} + +#[repr(C)] +pub struct RsSinkClass { parent_class: gst_base_ffi::GstBaseSinkClass, sink_info: *const SinkInfo, protocols: *const Vec<*const c_char>, parent_vtable: glib_ffi::gconstpointer, } +unsafe fn rs_sink_get_type() -> glib_ffi::GType { + use std::sync::{Once, ONCE_INIT}; + + static mut TYPE: glib_ffi::GType = gobject_ffi::G_TYPE_INVALID; + static ONCE: Once = ONCE_INIT; + + ONCE.call_once(|| { + let type_info = gobject_ffi::GTypeInfo { + class_size: mem::size_of::() as u16, + base_init: None, + base_finalize: None, + class_init: Some(sink_class_init), + class_finalize: None, + class_data: ptr::null_mut(), + instance_size: mem::size_of::() as u16, + n_preallocs: 0, + instance_init: Some(sink_init), + value_table: ptr::null(), + }; + + let type_name = { + let mut idx = 0; + + loop { + let type_name = CString::new(format!("RsSink-{}", idx)).unwrap(); + if gobject_ffi::g_type_from_name(type_name.as_ptr()) == gobject_ffi::G_TYPE_INVALID + { + break type_name; + } + idx += 1; + } + }; + + TYPE = gobject_ffi::g_type_register_static( + gst_base_ffi::gst_base_sink_get_type(), + type_name.as_ptr(), + &type_info, + gobject_ffi::GTypeFlags::empty(), + ); + + let iface_info = gobject_ffi::GInterfaceInfo { + interface_init: Some(sink_uri_handler_init), + interface_finalize: None, + interface_data: ptr::null_mut(), + }; + gobject_ffi::g_type_add_interface_static( + TYPE, + gst_ffi::gst_uri_handler_get_type(), + &iface_info, + ); + }); + + TYPE +} + unsafe extern "C" fn sink_finalize(obj: *mut gobject_ffi::GObject) { let sink = &mut *(obj as *mut RsSink); drop(Box::from_raw(sink.wrap)); + sink.wrap = ptr::null_mut(); - let sink_klass = &**(obj as *const *const RsSinkClass); + let sink_klass = &**(obj as *const *mut RsSinkClass); let parent_klass = &*(sink_klass.parent_vtable as *const gobject_ffi::GObjectClass); parent_klass.finalize.map(|f| f(obj)); } @@ -325,10 +368,10 @@ unsafe extern "C" fn sink_set_property( value: *mut gobject_ffi::GValue, _pspec: *mut gobject_ffi::GParamSpec, ) { - let sink = &*(obj as *const RsSink); + let sink = obj as *mut RsSink; - match id { - 1 => { + match mem::transmute(id) { + Properties::PropURI => { let uri_ptr = gobject_ffi::g_value_get_string(value); sink_set_uri(sink, uri_ptr, ptr::null_mut()); } @@ -342,10 +385,10 @@ unsafe extern "C" fn sink_get_property( value: *mut gobject_ffi::GValue, _pspec: *mut gobject_ffi::GParamSpec, ) { - let sink = &*(obj as *const RsSink); + let sink = obj as *mut RsSink; - match id { - 1 => { + match mem::transmute(id) { + Properties::PropURI => { let uri_ptr = sink_get_uri(sink); gobject_ffi::g_value_take_string(value, uri_ptr); } @@ -353,31 +396,62 @@ unsafe extern "C" fn sink_get_property( } } -unsafe extern "C" fn sink_class_init(klass: glib_ffi::gpointer, klass_data: glib_ffi::gpointer) { - let sink_klass = &mut *(klass as *mut RsSinkClass); +unsafe extern "C" fn sink_sub_class_init( + klass: glib_ffi::gpointer, + klass_data: glib_ffi::gpointer, +) { let sink_info = &*(klass_data as *const SinkInfo); { - let gobject_klass = &mut sink_klass - .parent_class - .parent_class - .parent_class - .parent_class; + let element_klass = &mut *(klass as *mut gst_ffi::GstElementClass); + + gst_ffi::gst_element_class_set_metadata( + element_klass, + sink_info.long_name.to_glib_none().0, + sink_info.classification.to_glib_none().0, + sink_info.description.to_glib_none().0, + sink_info.author.to_glib_none().0, + ); + + // TODO: Methods + sink_info.caps + let caps = gst::Caps::new_any(); + let pad_template = gst::PadTemplate::new( + "sink", + gst::PadDirection::Sink, + gst::PadPresence::Always, + &caps, + ); + gst_ffi::gst_element_class_add_pad_template(element_klass, pad_template.to_glib_full()); + } + + { + let sink_klass = &mut *(klass as *mut RsSinkClass); + + sink_klass.sink_info = sink_info; + let mut protocols = Box::new(Vec::with_capacity(sink_info.protocols.len())); + for p in &sink_info.protocols { + let p_cstr = CString::new(p.clone().into_bytes()).unwrap(); + protocols.push(p_cstr.into_raw() as *const c_char); + } + protocols.push(ptr::null()); + sink_klass.protocols = Box::into_raw(protocols) as *const Vec<*const c_char>; + } +} + +unsafe extern "C" fn sink_class_init(klass: glib_ffi::gpointer, _klass_data: glib_ffi::gpointer) { + { + let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass); gobject_klass.set_property = Some(sink_set_property); gobject_klass.get_property = Some(sink_get_property); gobject_klass.finalize = Some(sink_finalize); - let name_cstr = CString::new("uri").unwrap(); - let nick_cstr = CString::new("URI").unwrap(); - let blurb_cstr = CString::new("URI to read from").unwrap(); - gobject_ffi::g_object_class_install_property( klass as *mut gobject_ffi::GObjectClass, 1, gobject_ffi::g_param_spec_string( - name_cstr.as_ptr(), - nick_cstr.as_ptr(), - blurb_cstr.as_ptr(), + "uri".to_glib_none().0, + "URI".to_glib_none().0, + "URI to read from".to_glib_none().0, ptr::null_mut(), gobject_ffi::G_PARAM_READWRITE, ), @@ -385,48 +459,18 @@ unsafe extern "C" fn sink_class_init(klass: glib_ffi::gpointer, klass_data: glib } { - let element_klass = &mut sink_klass.parent_class.parent_class; + let basesink_klass = &mut *(klass as *mut gst_base_ffi::GstBaseSinkClass); - let longname_cstr = CString::new(sink_info.long_name.clone()).unwrap(); - let classification_cstr = CString::new(sink_info.description.clone()).unwrap(); - let description_cstr = CString::new(sink_info.classification.clone()).unwrap(); - let author_cstr = CString::new(sink_info.author.clone()).unwrap(); - - gst_ffi::gst_element_class_set_static_metadata( - element_klass, - longname_cstr.into_raw(), - classification_cstr.into_raw(), - description_cstr.into_raw(), - author_cstr.into_raw(), - ); - - let caps = Caps::new_any(); - let templ_name = CString::new("sink").unwrap(); - let pad_template = gst_ffi::gst_pad_template_new( - templ_name.into_raw(), - gst_ffi::GST_PAD_SINK, - gst_ffi::GST_PAD_ALWAYS, - caps.as_ptr() as *mut gst_ffi::GstCaps, - ); - gst_ffi::gst_element_class_add_pad_template(element_klass, pad_template); - } - - { - let basesink_klass = &mut sink_klass.parent_class; basesink_klass.start = Some(sink_start); basesink_klass.stop = Some(sink_stop); basesink_klass.render = Some(sink_render); } - sink_klass.sink_info = sink_info; - let mut protocols = Box::new(Vec::with_capacity(sink_info.protocols.len())); - for p in &sink_info.protocols { - let p_cstr = CString::new(p.clone().into_bytes()).unwrap(); - protocols.push(p_cstr.into_raw() as *const c_char); + { + let sink_klass = &mut *(klass as *mut RsSinkClass); + + sink_klass.parent_vtable = gobject_ffi::g_type_class_peek_parent(klass); } - protocols.push(ptr::null()); - sink_klass.protocols = Box::into_raw(protocols) as *const Vec<*const c_char>; - sink_klass.parent_vtable = gobject_ffi::g_type_class_peek_parent(klass); } unsafe extern "C" fn sink_init( @@ -437,19 +481,17 @@ unsafe extern "C" fn sink_init( let sink_klass = &*(klass as *const RsSinkClass); let sink_info = &*sink_klass.sink_info; - sink.sink_info = sink_info; - - let wrap = Box::new(SinkWrapper::new( - &mut sink.parent.element, - (sink_info.create_instance)(Element::new(&mut sink.parent.element)), - )); + let wrap = Box::new(SinkWrapper::new((sink_info.create_instance)( + &RsSinkWrapper::from_glib_borrow(instance as *mut _), + ))); sink.wrap = Box::into_raw(wrap); - gst_base_ffi::gst_base_sink_set_sync(&mut sink.parent, glib_ffi::GFALSE); + let sink = &RsSinkWrapper::from_glib_borrow(sink as *mut _); + sink.set_sync(false); } unsafe extern "C" fn sink_uri_handler_get_type(_type: glib_ffi::GType) -> gst_ffi::GstURIType { - gst_ffi::GST_URI_SINK + gst::URIType::Sink.to_glib() } unsafe extern "C" fn sink_uri_handler_get_protocols( @@ -463,7 +505,7 @@ unsafe extern "C" fn sink_uri_handler_get_protocols( unsafe extern "C" fn sink_uri_handler_get_uri( uri_handler: *mut gst_ffi::GstURIHandler, ) -> *mut c_char { - sink_get_uri(uri_handler as *const RsSink) + sink_get_uri(uri_handler as *mut RsSink) } unsafe extern "C" fn sink_uri_handler_set_uri( @@ -471,7 +513,7 @@ unsafe extern "C" fn sink_uri_handler_set_uri( uri: *const c_char, err: *mut *mut glib_ffi::GError, ) -> glib_ffi::gboolean { - sink_set_uri(uri_handler as *const RsSink, uri, err) + sink_set_uri(uri_handler as *mut RsSink, uri, err) } unsafe extern "C" fn sink_uri_handler_init( @@ -486,14 +528,12 @@ unsafe extern "C" fn sink_uri_handler_init( uri_handler_iface.set_uri = Some(sink_uri_handler_set_uri); } -pub fn sink_register(plugin: &Plugin, sink_info: SinkInfo) { +pub fn sink_register(plugin: &gst::Plugin, sink_info: SinkInfo) { unsafe { - let parent_type = gst_base_ffi::gst_base_sink_get_type(); - let mut type_name = String::from("RsSink-"); - type_name.push_str(&sink_info.name); - let type_name_cstr = CString::new(type_name.into_bytes()).unwrap(); + let parent_type = rs_sink_get_type(); + let type_name = format!("RsSink-{}", sink_info.name); - let name_cstr = CString::new(sink_info.name.clone().into_bytes()).unwrap(); + let name = sink_info.name.clone(); let rank = sink_info.rank; let sink_info = Box::new(sink_info); @@ -503,33 +543,22 @@ pub fn sink_register(plugin: &Plugin, sink_info: SinkInfo) { class_size: mem::size_of::() as u16, base_init: None, base_finalize: None, - class_init: Some(sink_class_init), + class_init: Some(sink_sub_class_init), class_finalize: None, class_data: sink_info_ptr, instance_size: mem::size_of::() as u16, n_preallocs: 0, - instance_init: Some(sink_init), + instance_init: None, value_table: ptr::null(), }; let type_ = gobject_ffi::g_type_register_static( parent_type, - type_name_cstr.as_ptr(), + type_name.to_glib_none().0, &type_info, gobject_ffi::GTypeFlags::empty(), ); - let iface_info = gobject_ffi::GInterfaceInfo { - interface_init: Some(sink_uri_handler_init), - interface_finalize: None, - interface_data: ptr::null_mut(), - }; - gobject_ffi::g_type_add_interface_static( - type_, - gst_ffi::gst_uri_handler_get_type(), - &iface_info, - ); - - gst_ffi::gst_element_register(plugin.as_ptr(), name_cstr.as_ptr(), rank, type_); + gst::Element::register(plugin, &name, rank, from_glib(type_)); } } diff --git a/gst-plugin/src/source.rs b/gst-plugin/src/source.rs index ee3440ac..1c33f8d7 100644 --- a/gst-plugin/src/source.rs +++ b/gst-plugin/src/source.rs @@ -19,45 +19,21 @@ use std::sync::atomic::{AtomicBool, Ordering}; use url::Url; -use slog::Logger; - -use plugin::Plugin; -use utils::*; use error::*; -use buffer::*; -use miniobject::*; -use log::*; -use caps::*; use glib_ffi; use gobject_ffi; use gst_ffi; use gst_base_ffi; -#[derive(Debug)] -pub enum SourceError { - Failure, - OpenFailed, - NotFound, - ReadFailed, - SeekFailed, -} - -impl ToGError for SourceError { - fn to_gerror(&self) -> (u32, i32) { - match *self { - SourceError::Failure => (gst_library_error_domain(), 1), - SourceError::OpenFailed => (gst_resource_error_domain(), 5), - SourceError::NotFound => (gst_resource_error_domain(), 3), - SourceError::ReadFailed => (gst_resource_error_domain(), 9), - SourceError::SeekFailed => (gst_resource_error_domain(), 11), - } - } -} +use glib::translate::*; +use gst; +use gst::prelude::*; +use gst_base; +use gst_base::prelude::*; pub struct SourceWrapper { - raw: *mut gst_ffi::GstElement, - logger: Logger, + cat: gst::DebugCategory, uri: Mutex<(Option, bool)>, uri_validator: Box, source: Mutex>, @@ -67,27 +43,33 @@ pub struct SourceWrapper { pub trait Source { fn uri_validator(&self) -> Box; - fn is_seekable(&self) -> bool; - fn get_size(&self) -> Option; + fn is_seekable(&self, src: &RsSrcWrapper) -> bool; + fn get_size(&self, src: &RsSrcWrapper) -> Option; - fn start(&mut self, uri: Url) -> Result<(), ErrorMessage>; - fn stop(&mut self) -> Result<(), ErrorMessage>; - fn fill(&mut self, offset: u64, length: u32, buffer: &mut Buffer) -> Result<(), FlowError>; - fn seek(&mut self, start: u64, stop: Option) -> Result<(), ErrorMessage>; + fn start(&mut self, src: &RsSrcWrapper, uri: Url) -> Result<(), ErrorMessage>; + fn stop(&mut self, src: &RsSrcWrapper) -> Result<(), ErrorMessage>; + fn fill( + &mut self, + src: &RsSrcWrapper, + offset: u64, + length: u32, + buffer: &mut gst::BufferRef, + ) -> Result<(), FlowError>; + fn seek( + &mut self, + src: &RsSrcWrapper, + start: u64, + stop: Option, + ) -> Result<(), ErrorMessage>; } impl SourceWrapper { - fn new(raw: *mut gst_ffi::GstElement, source: Box) -> SourceWrapper { + fn new(source: Box) -> SourceWrapper { SourceWrapper { - raw: raw, - logger: Logger::root( - GstDebugDrain::new( - Some(unsafe { &Element::new(raw) }), - "rssrc", - 0, - "Rust source base class", - ), - o!(), + cat: gst::DebugCategory::new( + "rssrc", + gst::DebugColorFlags::empty(), + "Rust source base class", ), uri: Mutex::new((None, false)), uri_validator: source.uri_validator(), @@ -96,15 +78,15 @@ impl SourceWrapper { } } - fn set_uri(&self, uri_str: Option<&str>) -> Result<(), UriError> { + fn set_uri(&self, src: &RsSrcWrapper, uri_str: Option<&str>) -> Result<(), UriError> { let uri_storage = &mut self.uri.lock().unwrap(); - debug!(self.logger, "Setting URI {:?}", uri_str); + gst_debug!(self.cat, obj: src, "Setting URI {:?}", uri_str); if uri_storage.1 { return Err(UriError::new( - UriErrorKind::BadState, - Some("Already started".to_string()), + gst::URIError::BadState, + "Already started".to_string(), )); } @@ -118,8 +100,8 @@ impl SourceWrapper { Ok(()) } Err(err) => Err(UriError::new( - UriErrorKind::BadUri, - Some(format!("Failed to parse URI '{}': {}", uri_str, err)), + gst::URIError::BadUri, + format!("Failed to parse URI '{}': {}", uri_str, err), )), } } else { @@ -127,23 +109,23 @@ impl SourceWrapper { } } - fn get_uri(&self) -> Option { + fn get_uri(&self, _src: &RsSrcWrapper) -> Option { let uri_storage = &self.uri.lock().unwrap(); uri_storage.0.as_ref().map(|uri| String::from(uri.as_str())) } - fn is_seekable(&self) -> bool { - let source = &self.source.lock().unwrap(); - source.is_seekable() + fn is_seekable(&self, src: &RsSrcWrapper) -> bool { + let source_impl = &self.source.lock().unwrap(); + source_impl.is_seekable(src) } - fn get_size(&self) -> u64 { - let source = &self.source.lock().unwrap(); - source.get_size().unwrap_or(u64::MAX) + fn get_size(&self, src: &RsSrcWrapper) -> u64 { + let source_impl = &self.source.lock().unwrap(); + source_impl.get_size(src).unwrap_or(u64::MAX) } - fn start(&self) -> bool { - debug!(self.logger, "Starting"); + fn start(&self, src: &RsSrcWrapper) -> bool { + gst_debug!(self.cat, obj: src, "Starting"); // Don't keep the URI locked while we call start later let uri = match *self.uri.lock().unwrap() { @@ -152,66 +134,76 @@ impl SourceWrapper { uri.clone() } (None, _) => { - error!(self.logger, "No URI given"); - self.post_message(&error_msg!(SourceError::OpenFailed, ["No URI given"])); + gst_error!(self.cat, obj: src, "No URI given"); + self.post_message( + src, + &error_msg!(gst::ResourceError::OpenRead, ["No URI given"]), + ); return false; } }; - let source = &mut self.source.lock().unwrap(); - match source.start(uri) { + let source_impl = &mut self.source.lock().unwrap(); + match source_impl.start(src, uri) { Ok(..) => { - trace!(self.logger, "Started successfully"); + gst_trace!(self.cat, obj: src, "Started successfully"); true } Err(ref msg) => { - error!(self.logger, "Failed to start: {:?}", msg); + gst_error!(self.cat, obj: src, "Failed to start: {:?}", msg); self.uri.lock().unwrap().1 = false; - self.post_message(msg); + self.post_message(src, msg); false } } } - fn stop(&self) -> bool { - let source = &mut self.source.lock().unwrap(); + fn stop(&self, src: &RsSrcWrapper) -> bool { + let source_impl = &mut self.source.lock().unwrap(); - debug!(self.logger, "Stopping"); + gst_debug!(self.cat, obj: src, "Stopping"); - match source.stop() { + match source_impl.stop(src) { Ok(..) => { - trace!(self.logger, "Stopped successfully"); + gst_trace!(self.cat, obj: src, "Stopped successfully"); self.uri.lock().unwrap().1 = false; true } Err(ref msg) => { - error!(self.logger, "Failed to stop: {:?}", msg); + gst_error!(self.cat, obj: src, "Failed to stop: {:?}", msg); - self.post_message(msg); + self.post_message(src, msg); false } } } - fn fill(&self, offset: u64, length: u32, buffer: &mut Buffer) -> gst_ffi::GstFlowReturn { - let source = &mut self.source.lock().unwrap(); + fn fill( + &self, + src: &RsSrcWrapper, + offset: u64, + length: u32, + buffer: &mut gst::BufferRef, + ) -> gst::FlowReturn { + let source_impl = &mut self.source.lock().unwrap(); - trace!( - self.logger, + gst_trace!( + self.cat, + obj: src, "Filling buffer {:?} with offset {} and length {}", buffer, offset, length ); - match source.fill(offset, length, buffer) { - Ok(()) => gst_ffi::GST_FLOW_OK, + match source_impl.fill(src, offset, length, buffer) { + Ok(()) => gst::FlowReturn::Ok, Err(flow_error) => { - error!(self.logger, "Failed to fill: {:?}", flow_error); + gst_error!(self.cat, obj: src, "Failed to fill: {:?}", flow_error); match flow_error { FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => { - self.post_message(msg) + self.post_message(src, msg) } _ => (), } @@ -220,116 +212,94 @@ impl SourceWrapper { } } - fn seek(&self, start: u64, stop: Option) -> bool { - let source = &mut self.source.lock().unwrap(); + fn seek(&self, src: &RsSrcWrapper, start: u64, stop: Option) -> bool { + let source_impl = &mut self.source.lock().unwrap(); - debug!(self.logger, "Seeking to {:?}-{:?}", start, stop); + gst_debug!(self.cat, obj: src, "Seeking to {:?}-{:?}", start, stop); - match source.seek(start, stop) { + match source_impl.seek(src, start, stop) { Ok(..) => true, Err(ref msg) => { - error!(self.logger, "Failed to seek {:?}", msg); - self.post_message(msg); + gst_error!(self.cat, obj: src, "Failed to seek {:?}", msg); + self.post_message(src, msg); false } } } - fn post_message(&self, msg: &ErrorMessage) { - unsafe { - msg.post(self.raw); - } + fn post_message(&self, src: &RsSrcWrapper, msg: &ErrorMessage) { + msg.post(src); } } unsafe fn source_set_uri( - ptr: *const RsSrc, + ptr: *mut RsSrc, uri_ptr: *const c_char, cerr: *mut *mut glib_ffi::GError, ) -> glib_ffi::gboolean { - let src = &*(ptr as *const RsSrc); - let wrap: &SourceWrapper = &*src.wrap; + let src: &RsSrcWrapper = &from_glib_borrow(ptr as *mut RsSrc); + let wrap = src.get_wrap(); - panic_to_error!(wrap, glib_ffi::GFALSE, { + panic_to_error!(wrap, src, false, { let uri_str = if uri_ptr.is_null() { None } else { Some(CStr::from_ptr(uri_ptr).to_str().unwrap()) }; - match wrap.set_uri(uri_str) { + match wrap.set_uri(src, uri_str) { Err(err) => { - error!(wrap.logger, "Failed to set URI {:?}", err); - err.into_gerror(cerr); - glib_ffi::GFALSE + gst_error!(wrap.cat, obj: src, "Failed to set URI {:?}", err); + if !cerr.is_null() { + let err = err.into_error(); + *cerr = err.to_glib_full() as *mut _; + } + false } - Ok(_) => glib_ffi::GTRUE, + Ok(_) => true, } - }) + }).to_glib() } -unsafe fn source_get_uri(ptr: *const RsSrc) -> *mut c_char { - let src = &*(ptr as *const RsSrc); - let wrap: &SourceWrapper = &*src.wrap; +unsafe fn source_get_uri(ptr: *mut RsSrc) -> *mut c_char { + let src: &RsSrcWrapper = &from_glib_borrow(ptr as *mut RsSrc); + let wrap = src.get_wrap(); - panic_to_error!(wrap, ptr::null_mut(), { - match wrap.get_uri() { - Some(uri_str) => glib_ffi::g_strndup(uri_str.as_ptr() as *const c_char, uri_str.len()), - None => ptr::null_mut(), - } - }) + panic_to_error!(wrap, src, None, { wrap.get_uri(src) }).to_glib_full() } unsafe extern "C" fn source_is_seekable(ptr: *mut gst_base_ffi::GstBaseSrc) -> glib_ffi::gboolean { - let src = &*(ptr as *const RsSrc); - let wrap: &SourceWrapper = &*src.wrap; + let src: &RsSrcWrapper = &from_glib_borrow(ptr as *mut RsSrc); + let wrap = src.get_wrap(); - panic_to_error!(wrap, glib_ffi::GFALSE, { - if wrap.is_seekable() { - glib_ffi::GTRUE - } else { - glib_ffi::GFALSE - } - }) + panic_to_error!(wrap, src, false, { wrap.is_seekable(src) }).to_glib() } unsafe extern "C" fn source_get_size( ptr: *mut gst_base_ffi::GstBaseSrc, size: *mut u64, ) -> glib_ffi::gboolean { - let src = &*(ptr as *const RsSrc); - let wrap: &SourceWrapper = &*src.wrap; + let src: &RsSrcWrapper = &from_glib_borrow(ptr as *mut RsSrc); + let wrap = src.get_wrap(); - panic_to_error!(wrap, glib_ffi::GFALSE, { - *size = wrap.get_size(); - glib_ffi::GTRUE - }) + panic_to_error!(wrap, src, false, { + *size = wrap.get_size(src); + true + }).to_glib() } unsafe extern "C" fn source_start(ptr: *mut gst_base_ffi::GstBaseSrc) -> glib_ffi::gboolean { - let src = &*(ptr as *const RsSrc); - let wrap: &SourceWrapper = &*src.wrap; + let src: &RsSrcWrapper = &from_glib_borrow(ptr as *mut RsSrc); + let wrap = src.get_wrap(); - panic_to_error!(wrap, glib_ffi::GFALSE, { - if wrap.start() { - glib_ffi::GTRUE - } else { - glib_ffi::GFALSE - } - }) + panic_to_error!(wrap, src, false, { wrap.start(src) }).to_glib() } unsafe extern "C" fn source_stop(ptr: *mut gst_base_ffi::GstBaseSrc) -> glib_ffi::gboolean { - let src = &*(ptr as *const RsSrc); - let wrap: &SourceWrapper = &*src.wrap; + let src: &RsSrcWrapper = &from_glib_borrow(ptr as *mut RsSrc); + let wrap = src.get_wrap(); - panic_to_error!(wrap, glib_ffi::GTRUE, { - if wrap.stop() { - glib_ffi::GTRUE - } else { - glib_ffi::GFALSE - } - }) + panic_to_error!(wrap, src, false, { wrap.stop(src) }).to_glib() } unsafe extern "C" fn source_fill( @@ -338,32 +308,58 @@ unsafe extern "C" fn source_fill( length: u32, buffer: *mut gst_ffi::GstBuffer, ) -> gst_ffi::GstFlowReturn { - let src = &*(ptr as *const RsSrc); - let wrap: &SourceWrapper = &*src.wrap; - let buffer: &mut Buffer = ::from_mut_ptr(buffer); + let src: &RsSrcWrapper = &from_glib_borrow(ptr as *mut RsSrc); + let wrap = src.get_wrap(); + let buffer = gst::BufferRef::from_mut_ptr(buffer); - panic_to_error!(wrap, gst_ffi::GST_FLOW_ERROR, { - wrap.fill(offset, length, buffer) - }) + panic_to_error!(wrap, src, gst::FlowReturn::Error, { + wrap.fill(src, offset, length, buffer) + }).to_glib() } unsafe extern "C" fn source_seek( ptr: *mut gst_base_ffi::GstBaseSrc, segment: *mut gst_ffi::GstSegment, ) -> glib_ffi::gboolean { - let src = &*(ptr as *const RsSrc); - let wrap: &SourceWrapper = &*src.wrap; + let src: &RsSrcWrapper = &from_glib_borrow(ptr as *mut RsSrc); + let wrap = src.get_wrap(); let start = (*segment).start; let stop = (*segment).stop; - panic_to_error!(wrap, glib_ffi::GFALSE, { - if wrap.seek(start, if stop == u64::MAX { None } else { Some(stop) }) { - glib_ffi::GTRUE - } else { - glib_ffi::GFALSE + panic_to_error!(wrap, src, false, { + wrap.seek(src, start, if stop == u64::MAX { None } else { Some(stop) }) + }).to_glib() +} + +unsafe extern "C" fn source_query( + ptr: *mut gst_base_ffi::GstBaseSrc, + query_ptr: *mut gst_ffi::GstQuery, +) -> glib_ffi::gboolean { + let src_klass = &**(ptr as *mut *mut RsSrcClass); + let source_info = &*src_klass.source_info; + let parent_klass = &*(src_klass.parent_vtable as *const gst_base_ffi::GstBaseSrcClass); + + let src: &RsSrcWrapper = &from_glib_borrow(ptr as *mut RsSrc); + let wrap = src.get_wrap(); + + let query = gst::QueryRef::from_mut_ptr(query_ptr); + + panic_to_error!(wrap, src, false, { + use gst::QueryView; + + match query.view_mut() { + QueryView::Scheduling(ref mut q) if source_info.push_only => { + q.set(gst::SCHEDULING_FLAG_SEQUENTIAL, 1, -1, 0); + q.add_scheduling_modes(&[gst::PadMode::Push]); + true + } + _ => parent_klass + .query + .map(|f| from_glib(f(ptr, query_ptr))) + .unwrap_or(false), } - }) + }).to_glib() } pub struct SourceInfo { @@ -373,30 +369,111 @@ pub struct SourceInfo { pub classification: String, pub author: String, pub rank: u32, - pub create_instance: fn(Element) -> Box, + pub create_instance: fn(&RsSrcWrapper) -> Box, pub protocols: Vec, pub push_only: bool, } -#[repr(C)] -struct RsSrc { - parent: gst_base_ffi::GstPushSrc, - wrap: *mut SourceWrapper, - source_info: *const SourceInfo, +glib_wrapper! { + pub struct RsSrcWrapper(Object): [gst_base::BaseSrc => gst_base_ffi::GstBaseSrc, + gst::Element => gst_ffi::GstElement, + gst::Object => gst_ffi::GstObject, + gst::URIHandler => gst_ffi::GstURIHandler, + ]; + + match fn { + get_type => || rs_src_get_type(), + } +} + +impl RsSrcWrapper { + fn get_wrap(&self) -> &SourceWrapper { + let stash = self.to_glib_none(); + let src: *mut RsSrc = stash.0; + + unsafe { &*((*src).wrap) } + } +} + +#[repr(u32)] +enum Properties { + PropURI = 1u32, } #[repr(C)] -struct RsSrcClass { +pub struct RsSrc { + parent: gst_base_ffi::GstPushSrc, + wrap: *mut SourceWrapper, +} + +#[repr(C)] +pub struct RsSrcClass { parent_class: gst_base_ffi::GstPushSrcClass, source_info: *const SourceInfo, protocols: *const Vec<*const c_char>, parent_vtable: glib_ffi::gconstpointer, } +unsafe fn rs_src_get_type() -> glib_ffi::GType { + use std::sync::{Once, ONCE_INIT}; + + static mut TYPE: glib_ffi::GType = gobject_ffi::G_TYPE_INVALID; + static ONCE: Once = ONCE_INIT; + + ONCE.call_once(|| { + let type_info = gobject_ffi::GTypeInfo { + class_size: mem::size_of::() as u16, + base_init: None, + base_finalize: None, + class_init: Some(source_class_init), + class_finalize: None, + class_data: ptr::null_mut(), + instance_size: mem::size_of::() as u16, + n_preallocs: 0, + instance_init: Some(source_init), + value_table: ptr::null(), + }; + + let type_name = { + let mut idx = 0; + + loop { + let type_name = CString::new(format!("RsSrc-{}", idx)).unwrap(); + if gobject_ffi::g_type_from_name(type_name.as_ptr()) == gobject_ffi::G_TYPE_INVALID + { + break type_name; + } + idx += 1; + } + }; + + TYPE = gobject_ffi::g_type_register_static( + gst_base_ffi::gst_base_src_get_type(), + type_name.as_ptr(), + &type_info, + gobject_ffi::GTypeFlags::empty(), + ); + + let iface_info = gobject_ffi::GInterfaceInfo { + interface_init: Some(source_uri_handler_init), + interface_finalize: None, + interface_data: ptr::null_mut(), + }; + gobject_ffi::g_type_add_interface_static( + TYPE, + gst_ffi::gst_uri_handler_get_type(), + &iface_info, + ); + }); + + TYPE +} + unsafe extern "C" fn source_finalize(obj: *mut gobject_ffi::GObject) { let src = &mut *(obj as *mut RsSrc); drop(Box::from_raw(src.wrap)); + src.wrap = ptr::null_mut(); let src_klass = &**(obj as *const *const RsSrcClass); let parent_klass = &*(src_klass.parent_vtable as *const gobject_ffi::GObjectClass); @@ -409,10 +486,10 @@ unsafe extern "C" fn source_set_property( value: *mut gobject_ffi::GValue, _pspec: *mut gobject_ffi::GParamSpec, ) { - let src = &*(obj as *const RsSrc); + let src = obj as *mut RsSrc; - match id { - 1 => { + match mem::transmute(id) { + Properties::PropURI => { let uri_ptr = gobject_ffi::g_value_get_string(value); source_set_uri(src, uri_ptr, ptr::null_mut()); } @@ -426,10 +503,10 @@ unsafe extern "C" fn source_get_property( value: *mut gobject_ffi::GValue, _pspec: *mut gobject_ffi::GParamSpec, ) { - let src = &*(obj as *const RsSrc); + let src = obj as *mut RsSrc; - match id { - 1 => { + match mem::transmute(id) { + Properties::PropURI => { let uri_ptr = source_get_uri(src); gobject_ffi::g_value_take_string(value, uri_ptr); } @@ -437,32 +514,62 @@ unsafe extern "C" fn source_get_property( } } -unsafe extern "C" fn source_class_init(klass: glib_ffi::gpointer, klass_data: glib_ffi::gpointer) { - let src_klass = &mut *(klass as *mut RsSrcClass); +unsafe extern "C" fn source_sub_class_init( + klass: glib_ffi::gpointer, + klass_data: glib_ffi::gpointer, +) { let source_info = &*(klass_data as *const SourceInfo); { - let gobject_klass = &mut src_klass - .parent_class - .parent_class - .parent_class - .parent_class - .parent_class; + let element_klass = &mut *(klass as *mut gst_ffi::GstElementClass); + + gst_ffi::gst_element_class_set_metadata( + element_klass, + source_info.long_name.to_glib_none().0, + source_info.classification.to_glib_none().0, + source_info.description.to_glib_none().0, + source_info.author.to_glib_none().0, + ); + + // TODO: Methods + source_info.caps + let caps = gst::Caps::new_any(); + let pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &caps, + ); + gst_ffi::gst_element_class_add_pad_template(element_klass, pad_template.to_glib_full()); + } + + { + let src_klass = &mut *(klass as *mut RsSrcClass); + + src_klass.source_info = source_info; + let mut protocols = Box::new(Vec::with_capacity(source_info.protocols.len())); + for p in &source_info.protocols { + protocols.push(p.to_glib_full()); + } + protocols.push(ptr::null()); + src_klass.protocols = Box::into_raw(protocols) as *const Vec<*const c_char>; + } +} + +unsafe extern "C" fn source_class_init(klass: glib_ffi::gpointer, _klass_data: glib_ffi::gpointer) { + { + let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass); + gobject_klass.set_property = Some(source_set_property); gobject_klass.get_property = Some(source_get_property); gobject_klass.finalize = Some(source_finalize); - let name_cstr = CString::new("uri").unwrap(); - let nick_cstr = CString::new("URI").unwrap(); - let blurb_cstr = CString::new("URI to read from").unwrap(); - gobject_ffi::g_object_class_install_property( klass as *mut gobject_ffi::GObjectClass, 1, gobject_ffi::g_param_spec_string( - name_cstr.as_ptr(), - nick_cstr.as_ptr(), - blurb_cstr.as_ptr(), + "uri".to_glib_none().0, + "URI".to_glib_none().0, + "URI to read from".to_glib_none().0, ptr::null_mut(), gobject_ffi::G_PARAM_READWRITE, ), @@ -470,51 +577,22 @@ unsafe extern "C" fn source_class_init(klass: glib_ffi::gpointer, klass_data: gl } { - let element_klass = &mut src_klass.parent_class.parent_class.parent_class; + let basesrc_klass = &mut *(klass as *mut gst_base_ffi::GstBaseSrcClass); - let longname_cstr = CString::new(source_info.long_name.clone()).unwrap(); - let classification_cstr = CString::new(source_info.description.clone()).unwrap(); - let description_cstr = CString::new(source_info.classification.clone()).unwrap(); - let author_cstr = CString::new(source_info.author.clone()).unwrap(); - - gst_ffi::gst_element_class_set_static_metadata( - element_klass, - longname_cstr.into_raw(), - classification_cstr.into_raw(), - description_cstr.into_raw(), - author_cstr.into_raw(), - ); - - let caps = Caps::new_any(); - let templ_name = CString::new("src").unwrap(); - let pad_template = gst_ffi::gst_pad_template_new( - templ_name.into_raw(), - gst_ffi::GST_PAD_SRC, - gst_ffi::GST_PAD_ALWAYS, - caps.as_ptr() as *mut gst_ffi::GstCaps, - ); - gst_ffi::gst_element_class_add_pad_template(element_klass, pad_template); - } - - { - let basesrc_klass = &mut src_klass.parent_class.parent_class; basesrc_klass.start = Some(source_start); basesrc_klass.stop = Some(source_stop); basesrc_klass.is_seekable = Some(source_is_seekable); basesrc_klass.get_size = Some(source_get_size); basesrc_klass.fill = Some(source_fill); basesrc_klass.do_seek = Some(source_seek); + basesrc_klass.query = Some(source_query); } - src_klass.source_info = source_info; - let mut protocols = Box::new(Vec::with_capacity(source_info.protocols.len())); - for p in &source_info.protocols { - let p_cstr = CString::new(p.clone().into_bytes()).unwrap(); - protocols.push(p_cstr.into_raw() as *const c_char); + { + let src_klass = &mut *(klass as *mut RsSrcClass); + + src_klass.parent_vtable = gobject_ffi::g_type_class_peek_parent(klass); } - protocols.push(ptr::null()); - src_klass.protocols = Box::into_raw(protocols) as *const Vec<*const c_char>; - src_klass.parent_vtable = gobject_ffi::g_type_class_peek_parent(klass); } unsafe extern "C" fn source_init( @@ -525,19 +603,17 @@ unsafe extern "C" fn source_init( let src_klass = &*(klass as *const RsSrcClass); let source_info = &*src_klass.source_info; - src.source_info = source_info; - - let wrap = Box::new(SourceWrapper::new( - &mut src.parent.parent.element, - (source_info.create_instance)(Element::new(&mut src.parent.parent.element)), - )); + let wrap = Box::new(SourceWrapper::new((source_info.create_instance)( + &RsSrcWrapper::from_glib_borrow(instance as *mut _), + ))); src.wrap = Box::into_raw(wrap); - gst_base_ffi::gst_base_src_set_blocksize(&mut src.parent.parent, 4096); + let src = &RsSrcWrapper::from_glib_borrow(src as *mut _); + src.set_blocksize(4096); } unsafe extern "C" fn source_uri_handler_get_type(_type: glib_ffi::GType) -> gst_ffi::GstURIType { - gst_ffi::GST_URI_SRC + gst::URIType::Src.to_glib() } unsafe extern "C" fn source_uri_handler_get_protocols( @@ -551,7 +627,7 @@ unsafe extern "C" fn source_uri_handler_get_protocols( unsafe extern "C" fn source_uri_handler_get_uri( uri_handler: *mut gst_ffi::GstURIHandler, ) -> *mut c_char { - source_get_uri(uri_handler as *const RsSrc) + source_get_uri(uri_handler as *mut RsSrc) } unsafe extern "C" fn source_uri_handler_set_uri( @@ -559,7 +635,7 @@ unsafe extern "C" fn source_uri_handler_set_uri( uri: *const c_char, err: *mut *mut glib_ffi::GError, ) -> glib_ffi::gboolean { - source_set_uri(uri_handler as *const RsSrc, uri, err) + source_set_uri(uri_handler as *mut RsSrc, uri, err) } unsafe extern "C" fn source_uri_handler_init( @@ -574,18 +650,12 @@ unsafe extern "C" fn source_uri_handler_init( uri_handler_iface.set_uri = Some(source_uri_handler_set_uri); } -pub fn source_register(plugin: &Plugin, source_info: SourceInfo) { +pub fn source_register(plugin: &gst::Plugin, source_info: SourceInfo) { unsafe { - let parent_type = if source_info.push_only { - gst_base_ffi::gst_push_src_get_type() - } else { - gst_base_ffi::gst_base_src_get_type() - }; - let mut type_name = String::from("RsSrc-"); - type_name.push_str(&source_info.name); - let type_name_cstr = CString::new(type_name.into_bytes()).unwrap(); + let parent_type = rs_src_get_type(); + let type_name = format!("RsSrc-{}", source_info.name); - let name_cstr = CString::new(source_info.name.clone().into_bytes()).unwrap(); + let name = source_info.name.clone(); let rank = source_info.rank; let source_info = Box::new(source_info); @@ -595,33 +665,22 @@ pub fn source_register(plugin: &Plugin, source_info: SourceInfo) { class_size: mem::size_of::() as u16, base_init: None, base_finalize: None, - class_init: Some(source_class_init), + class_init: Some(source_sub_class_init), class_finalize: None, class_data: source_info_ptr, instance_size: mem::size_of::() as u16, n_preallocs: 0, - instance_init: Some(source_init), + instance_init: None, value_table: ptr::null(), }; let type_ = gobject_ffi::g_type_register_static( parent_type, - type_name_cstr.as_ptr(), + type_name.to_glib_none().0, &type_info, gobject_ffi::GTypeFlags::empty(), ); - let iface_info = gobject_ffi::GInterfaceInfo { - interface_init: Some(source_uri_handler_init), - interface_finalize: None, - interface_data: ptr::null_mut(), - }; - gobject_ffi::g_type_add_interface_static( - type_, - gst_ffi::gst_uri_handler_get_type(), - &iface_info, - ); - - gst_ffi::gst_element_register(plugin.as_ptr(), name_cstr.as_ptr(), rank, type_); + gst::Element::register(plugin, &name, rank, from_glib(type_)); } } diff --git a/gst-plugin/src/streams.rs b/gst-plugin/src/streams.rs deleted file mode 100644 index 288eb4da..00000000 --- a/gst-plugin/src/streams.rs +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright (C) 2016-2017 Sebastian Dröge -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::ptr; -use std::mem; -use std::ffi::{CStr, CString}; -use caps::Caps; -use miniobject::*; -use tags::TagList; - -use gst_ffi; - -pub struct Stream(*mut gst_ffi::GstStream); -pub struct StreamCollection(*mut gst_ffi::GstStreamCollection); - -bitflags! { - #[repr(C)] - pub struct StreamType: u32 { - const TYPE_UNKNOWN = 0b00000001; - const TYPE_AUDIO = 0b00000010; - const TYPE_VIDEO = 0b00000100; - const TYPE_CONTAINER = 0b00001000; - const TYPE_TEXT = 0b00010000; - } -} - -bitflags! { - #[repr(C)] - pub struct StreamFlags: u32 { - const FLAG_SPARSE = 0b00000001; - const FLAG_SELECT = 0b00000010; - const FLAG_UNSELECT = 0b00000100; - } -} - -impl Stream { - pub fn new( - stream_id: &str, - caps: Option>, - t: StreamType, - flags: StreamFlags, - ) -> Self { - let stream_id_cstr = CString::new(stream_id).unwrap(); - let caps = caps.map(|caps| unsafe { caps.as_mut_ptr() }) - .unwrap_or(ptr::null_mut()); - - Stream(unsafe { - gst_ffi::gst_stream_new( - stream_id_cstr.as_ptr(), - caps, - mem::transmute(t.bits()), - mem::transmute(flags.bits()), - ) - }) - } - - pub unsafe fn as_ptr(&self) -> *const gst_ffi::GstStream { - self.0 - } - - pub fn get_caps(&self) -> Option<&Caps> { - let ptr = unsafe { gst_ffi::gst_stream_get_caps(self.0) }; - - if ptr.is_null() { - return None; - } - - Some(unsafe { ::from_ptr(ptr) }) - } - - pub fn get_stream_flags(&self) -> StreamFlags { - StreamFlags::from_bits_truncate(unsafe { - gst_ffi::gst_stream_get_stream_flags(self.0).bits() - }) - } - - pub fn get_stream_type(&self) -> StreamType { - StreamType::from_bits_truncate(unsafe { - gst_ffi::gst_stream_get_stream_type(self.0).bits() - }) - } - - pub fn get_stream_id(&self) -> &str { - let cstr = unsafe { CStr::from_ptr(gst_ffi::gst_stream_get_stream_id(self.0)) }; - cstr.to_str().unwrap() - } - - pub fn get_tags(&self) -> Option<&TagList> { - let ptr = unsafe { gst_ffi::gst_stream_get_tags(self.0) }; - - if ptr.is_null() { - return None; - } - - Some(unsafe { ::from_ptr(ptr) }) - } - - pub fn set_caps(&self, caps: Option>) { - let ptr = caps.map(|caps| unsafe { caps.as_mut_ptr() }) - .unwrap_or(ptr::null_mut()); - - unsafe { gst_ffi::gst_stream_set_caps(self.0, ptr) } - } - - pub fn set_stream_flags(&self, flags: StreamFlags) { - unsafe { gst_ffi::gst_stream_set_stream_flags(self.0, mem::transmute(flags.bits())) } - } - - pub fn set_stream_type(&self, t: StreamType) { - unsafe { gst_ffi::gst_stream_set_stream_type(self.0, mem::transmute(t.bits())) } - } - - pub fn set_tags(&self, tags: Option) { - let ptr = tags.map(|tags| unsafe { tags.as_mut_ptr() }) - .unwrap_or(ptr::null_mut()); - - unsafe { gst_ffi::gst_stream_set_tags(self.0, ptr) } - } -} - -impl Clone for Stream { - fn clone(&self) -> Self { - unsafe { - Stream( - gst_ffi::gst_object_ref(self.0 as *mut gst_ffi::GstObject) as - *mut gst_ffi::GstStream, - ) - } - } -} - -impl Drop for Stream { - fn drop(&mut self) { - unsafe { gst_ffi::gst_object_unref(self.0 as *mut gst_ffi::GstObject) } - } -} - -impl StreamCollection { - pub fn new(upstream_id: &str, streams: &[Stream]) -> Self { - let upstream_id_cstr = CString::new(upstream_id).unwrap(); - let collection = StreamCollection(unsafe { - gst_ffi::gst_stream_collection_new(upstream_id_cstr.as_ptr()) - }); - - for stream in streams { - unsafe { gst_ffi::gst_stream_collection_add_stream(collection.0, stream.clone().0) }; - } - - collection - } - - pub fn streams(&self) -> StreamCollectionIterator { - StreamCollectionIterator::new(self) - } - - pub fn len(&self) -> u32 { - unsafe { gst_ffi::gst_stream_collection_get_size(self.0) } - } - - pub fn empty(&self) -> bool { - self.len() == 0 - } - - pub fn get_upstream_id(&self) -> &str { - let cstr = - unsafe { CStr::from_ptr(gst_ffi::gst_stream_collection_get_upstream_id(self.0)) }; - cstr.to_str().unwrap() - } - - pub unsafe fn as_ptr(&self) -> *const gst_ffi::GstStreamCollection { - self.0 - } -} - -pub struct StreamCollectionIterator<'a> { - position: u32, - length: u32, - collection: &'a StreamCollection, -} - -impl<'a> StreamCollectionIterator<'a> { - fn new(collection: &'a StreamCollection) -> Self { - StreamCollectionIterator { - position: 0, - length: collection.len(), - collection: collection, - } - } -} - -impl<'a> Iterator for StreamCollectionIterator<'a> { - type Item = Stream; - - fn next(&mut self) -> Option { - if self.position == self.length { - return None; - } - - let stream = - unsafe { gst_ffi::gst_stream_collection_get_stream(self.collection.0, self.position) }; - if stream.is_null() { - self.position = self.length; - return None; - } - self.position += 1; - - Some(unsafe { - Stream( - gst_ffi::gst_object_ref(stream as *mut gst_ffi::GstObject) as - *mut gst_ffi::GstStream, - ) - }) - } - - fn size_hint(&self) -> (usize, Option) { - if self.position == self.length { - return (0, Some(0)); - } - - let remaining = (self.length - self.position) as usize; - - (remaining, Some(remaining)) - } -} - -impl<'a> DoubleEndedIterator for StreamCollectionIterator<'a> { - fn next_back(&mut self) -> Option { - if self.position == self.length { - return None; - } - - self.length -= 1; - - let stream = - unsafe { gst_ffi::gst_stream_collection_get_stream(self.collection.0, self.length) }; - if stream.is_null() { - self.position = self.length; - return None; - } - - Some(unsafe { - Stream( - gst_ffi::gst_object_ref(stream as *mut gst_ffi::GstObject) as - *mut gst_ffi::GstStream, - ) - }) - } -} - -impl<'a> ExactSizeIterator for StreamCollectionIterator<'a> {} - -impl Clone for StreamCollection { - fn clone(&self) -> Self { - unsafe { - StreamCollection( - gst_ffi::gst_object_ref(self.0 as *mut gst_ffi::GstObject) as - *mut gst_ffi::GstStreamCollection, - ) - } - } -} - -impl Drop for StreamCollection { - fn drop(&mut self) { - unsafe { gst_ffi::gst_object_unref(self.0 as *mut gst_ffi::GstObject) } - } -} diff --git a/gst-plugin/src/structure.rs b/gst-plugin/src/structure.rs deleted file mode 100644 index 21ff3542..00000000 --- a/gst-plugin/src/structure.rs +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright (C) 2016-2017 Sebastian Dröge -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::fmt; -use std::ptr; -use std::mem; -use std::ffi::{CStr, CString}; -use std::ops::{Deref, DerefMut}; -use std::borrow::{Borrow, BorrowMut, ToOwned}; -use std::marker::PhantomData; - -use value::*; - -use glib_ffi; -use gst_ffi; - -pub struct OwnedStructure(*mut Structure, PhantomData); - -impl OwnedStructure { - pub fn new_empty(name: &str) -> OwnedStructure { - let name_cstr = CString::new(name).unwrap(); - OwnedStructure( - unsafe { gst_ffi::gst_structure_new_empty(name_cstr.as_ptr()) as *mut Structure }, - PhantomData, - ) - } - - pub fn new(name: &str, values: &[(&str, Value)]) -> OwnedStructure { - let mut structure = OwnedStructure::new_empty(name); - - for &(f, ref v) in values { - structure.set(f, v.clone()); - } - - structure - } - - pub fn from_string(s: &str) -> Option { - unsafe { - let cstr = CString::new(s).unwrap(); - let structure = gst_ffi::gst_structure_from_string(cstr.as_ptr(), ptr::null_mut()); - if structure.is_null() { - None - } else { - Some(OwnedStructure(structure as *mut Structure, PhantomData)) - } - } - } - - pub unsafe fn into_ptr(self) -> *mut gst_ffi::GstStructure { - let ptr = self.0 as *mut Structure as *mut gst_ffi::GstStructure; - mem::forget(self); - - ptr - } -} - -impl Deref for OwnedStructure { - type Target = Structure; - - fn deref(&self) -> &Structure { - unsafe { &*self.0 } - } -} - -impl DerefMut for OwnedStructure { - fn deref_mut(&mut self) -> &mut Structure { - unsafe { &mut *self.0 } - } -} - -impl AsRef for OwnedStructure { - fn as_ref(&self) -> &Structure { - self.deref() - } -} - -impl AsMut for OwnedStructure { - fn as_mut(&mut self) -> &mut Structure { - self.deref_mut() - } -} - -impl Clone for OwnedStructure { - fn clone(&self) -> Self { - OwnedStructure( - unsafe { gst_ffi::gst_structure_copy(&(*self.0).0) as *mut Structure }, - PhantomData, - ) - } -} - -impl Drop for OwnedStructure { - fn drop(&mut self) { - unsafe { gst_ffi::gst_structure_free(&mut (*self.0).0) } - } -} - -impl fmt::Debug for OwnedStructure { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl PartialEq for OwnedStructure { - fn eq(&self, other: &OwnedStructure) -> bool { - self.as_ref().eq(other) - } -} - -impl PartialEq for OwnedStructure { - fn eq(&self, other: &Structure) -> bool { - self.as_ref().eq(other) - } -} - -impl Eq for OwnedStructure {} - -impl Borrow for OwnedStructure { - fn borrow(&self) -> &Structure { - unsafe { &*self.0 } - } -} - -impl BorrowMut for OwnedStructure { - fn borrow_mut(&mut self) -> &mut Structure { - unsafe { &mut *self.0 } - } -} - -impl ToOwned for Structure { - type Owned = OwnedStructure; - - fn to_owned(&self) -> OwnedStructure { - OwnedStructure( - unsafe { gst_ffi::gst_structure_copy(&self.0) as *mut Structure }, - PhantomData, - ) - } -} - -#[repr(C)] -pub struct Structure(gst_ffi::GstStructure); - -impl Structure { - pub unsafe fn from_borrowed_ptr<'a>(ptr: *const gst_ffi::GstStructure) -> &'a Structure { - assert!(!ptr.is_null()); - - &*(ptr as *mut Structure) - } - - pub unsafe fn from_borrowed_mut_ptr<'a>(ptr: *mut gst_ffi::GstStructure) -> &'a mut Structure { - assert!(!ptr.is_null()); - - &mut *(ptr as *mut Structure) - } - - pub fn to_string(&self) -> String { - unsafe { - let ptr = gst_ffi::gst_structure_to_string(&self.0); - let s = CStr::from_ptr(ptr).to_str().unwrap().into(); - glib_ffi::g_free(ptr as glib_ffi::gpointer); - - s - } - } - - pub fn get<'a, T: ValueType<'a>>(&'a self, name: &str) -> Option> { - self.get_value(name).and_then(TypedValueRef::from_value_ref) - } - - pub fn get_value<'a>(&'a self, name: &str) -> Option> { - unsafe { - let name_cstr = CString::new(name).unwrap(); - - let value = gst_ffi::gst_structure_get_value(&self.0, name_cstr.as_ptr()); - - if value.is_null() { - return None; - } - - ValueRef::from_ptr(value) - } - } - - pub fn set>(&mut self, name: &str, value: T) { - unsafe { - let name_cstr = CString::new(name).unwrap(); - let mut gvalue = value.into().into_raw(); - - gst_ffi::gst_structure_take_value(&mut self.0, name_cstr.as_ptr(), &mut gvalue); - mem::forget(gvalue); - } - } - - pub fn get_name(&self) -> &str { - unsafe { - let cstr = CStr::from_ptr(gst_ffi::gst_structure_get_name(&self.0)); - cstr.to_str().unwrap() - } - } - - pub fn has_field(&self, field: &str) -> bool { - unsafe { - let cstr = CString::new(field).unwrap(); - gst_ffi::gst_structure_has_field(&self.0, cstr.as_ptr()) == glib_ffi::GTRUE - } - } - - pub fn remove_field(&mut self, field: &str) { - unsafe { - let cstr = CString::new(field).unwrap(); - gst_ffi::gst_structure_remove_field(&mut self.0, cstr.as_ptr()); - } - } - - pub fn remove_all_fields(&mut self) { - unsafe { - gst_ffi::gst_structure_remove_all_fields(&mut self.0); - } - } - - pub fn fields(&self) -> FieldIterator { - FieldIterator::new(self) - } - - pub fn iter(&self) -> Iter { - Iter::new(self) - } - - fn get_nth_field_name(&self, idx: u32) -> Option<&str> { - unsafe { - let field_name = gst_ffi::gst_structure_nth_field_name(&self.0, idx); - if field_name.is_null() { - return None; - } - - let cstr = CStr::from_ptr(field_name); - Some(cstr.to_str().unwrap()) - } - } - - fn n_fields(&self) -> u32 { - unsafe { gst_ffi::gst_structure_n_fields(&self.0) as u32 } - } - - // TODO: Various operations -} - -impl fmt::Debug for Structure { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl PartialEq for Structure { - fn eq(&self, other: &Structure) -> bool { - (unsafe { gst_ffi::gst_structure_is_equal(&self.0, &other.0) } == glib_ffi::GTRUE) - } -} - -impl Eq for Structure {} - -pub struct FieldIterator<'a> { - structure: &'a Structure, - idx: u32, - n_fields: u32, -} - -impl<'a> FieldIterator<'a> { - pub fn new(structure: &'a Structure) -> FieldIterator<'a> { - let n_fields = structure.n_fields(); - - FieldIterator { - structure: structure, - idx: 0, - n_fields: n_fields, - } - } -} - -impl<'a> Iterator for FieldIterator<'a> { - type Item = &'a str; - - fn next(&mut self) -> Option<&'a str> { - if self.idx >= self.n_fields { - return None; - } - - if let Some(field_name) = self.structure.get_nth_field_name(self.idx) { - self.idx += 1; - Some(field_name) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - if self.idx == self.n_fields { - return (0, Some(0)); - } - - let remaining = (self.n_fields - self.idx) as usize; - - (remaining, Some(remaining)) - } -} - -impl<'a> DoubleEndedIterator for FieldIterator<'a> { - fn next_back(&mut self) -> Option { - if self.idx == self.n_fields { - return None; - } - - self.n_fields -= 1; - if let Some(field_name) = self.structure.get_nth_field_name(self.n_fields) { - Some(field_name) - } else { - None - } - } -} - -impl<'a> ExactSizeIterator for FieldIterator<'a> {} - -pub struct Iter<'a> { - iter: FieldIterator<'a>, -} - -impl<'a> Iter<'a> { - pub fn new(structure: &'a Structure) -> Iter<'a> { - Iter { - iter: FieldIterator::new(structure), - } - } -} - -impl<'a> Iterator for Iter<'a> { - type Item = (&'a str, ValueRef<'a>); - - fn next(&mut self) -> Option<(&'a str, ValueRef<'a>)> { - if let Some(f) = self.iter.next() { - let v = self.iter.structure.get_value(f); - Some((f, v.unwrap())) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl<'a> DoubleEndedIterator for Iter<'a> { - fn next_back(&mut self) -> Option { - if let Some(f) = self.iter.next_back() { - let v = self.iter.structure.get_value(f); - Some((f, v.unwrap())) - } else { - None - } - } -} - -impl<'a> ExactSizeIterator for Iter<'a> {} - -#[cfg(test)] -mod tests { - use super::*; - use std::ptr; - - #[test] - fn new_set_get() { - unsafe { gst_ffi::gst_init(ptr::null_mut(), ptr::null_mut()) }; - - let mut s = OwnedStructure::new_empty("test"); - assert_eq!(s.get_name(), "test"); - - s.set("f1", "abc"); - s.set("f2", String::from("bcd")); - s.set("f3", 123i32); - - assert_eq!(s.get::<&str>("f1").unwrap().get(), "abc"); - assert_eq!(s.get::<&str>("f2").unwrap().get(), "bcd"); - assert_eq!(s.get::("f3").unwrap().get(), 123i32); - assert_eq!(s.fields().collect::>(), vec!["f1", "f2", "f3"]); - assert_eq!( - s.iter() - .map(|(f, v)| (f, Value::from_value_ref(&v))) - .collect::>(), - vec![ - ("f1", Value::new("abc")), - ("f2", Value::new("bcd")), - ("f3", Value::new(123i32)), - ] - ); - - let s2 = OwnedStructure::new( - "test", - &[ - ("f1", "abc".into()), - ("f2", "bcd".into()), - ("f3", 123i32.into()), - ], - ); - assert_eq!(s, s2); - } -} diff --git a/gst-plugin/src/tags.rs b/gst-plugin/src/tags.rs deleted file mode 100644 index a2c4a416..00000000 --- a/gst-plugin/src/tags.rs +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright (C) 2016-2017 Sebastian Dröge -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::fmt; -use std::mem; -use std::ffi::{CStr, CString}; -use std::marker::PhantomData; -use value::*; -use miniobject::*; - -use glib_ffi; -use gobject_ffi; -use gst_ffi; - -pub trait Tag<'a> { - type TagType: ValueType<'a>; - fn tag_name() -> &'static str; -} - -macro_rules! impl_tag( - ($name:ident, $t:ty, $tag:expr) => { - pub struct $name; - impl<'a> Tag<'a> for $name { - type TagType = $t; - fn tag_name() -> &'static str { - $tag - } - } - }; -); - -impl_tag!(Title, &'a str, "title"); -impl_tag!(Album, &'a str, "album"); -impl_tag!(Artist, &'a str, "artist"); -impl_tag!(Encoder, &'a str, "encoder"); -impl_tag!(AudioCodec, &'a str, "audio-codec"); -impl_tag!(VideoCodec, &'a str, "video-codec"); -impl_tag!(SubtitleCodec, &'a str, "subtitle-codec"); -impl_tag!(ContainerFormat, &'a str, "container-format"); -// TODO: Should ideally enforce this to be ISO-639 -impl_tag!(LanguageCode, &'a str, "language-code"); -impl_tag!(Duration, u64, "duration"); -impl_tag!(NominalBitrate, u32, "nominal-bitrate"); - -pub enum MergeMode { - ReplaceAll, - Replace, - Append, - Prepend, - Keep, - KeepAll, -} - -impl MergeMode { - fn to_ffi(&self) -> gst_ffi::GstTagMergeMode { - match *self { - MergeMode::ReplaceAll => gst_ffi::GST_TAG_MERGE_REPLACE_ALL, - MergeMode::Replace => gst_ffi::GST_TAG_MERGE_REPLACE, - MergeMode::Append => gst_ffi::GST_TAG_MERGE_APPEND, - MergeMode::Prepend => gst_ffi::GST_TAG_MERGE_PREPEND, - MergeMode::Keep => gst_ffi::GST_TAG_MERGE_KEEP, - MergeMode::KeepAll => gst_ffi::GST_TAG_MERGE_KEEP_ALL, - } - } -} - -pub struct TagList(gst_ffi::GstTagList); - -unsafe impl MiniObject for TagList { - type PtrType = gst_ffi::GstTagList; -} - -impl TagList { - pub fn new() -> GstRc { - unsafe { GstRc::from_owned_ptr(gst_ffi::gst_tag_list_new_empty()) } - } - - pub fn add<'a, T: Tag<'a>>(&mut self, value: T::TagType, mode: MergeMode) - where - T::TagType: Into, - { - unsafe { - let v = value.into(); - let mut gvalue = v.into_raw(); - let tag_name = CString::new(T::tag_name()).unwrap(); - - gst_ffi::gst_tag_list_add_value( - self.as_mut_ptr(), - mode.to_ffi(), - tag_name.as_ptr(), - &gvalue, - ); - - gobject_ffi::g_value_unset(&mut gvalue); - } - } - - pub fn get<'a, T: Tag<'a>>(&self) -> Option> { - unsafe { - let mut gvalue = mem::zeroed(); - let tag_name = CString::new(T::tag_name()).unwrap(); - - let found = - gst_ffi::gst_tag_list_copy_value(&mut gvalue, self.as_ptr(), tag_name.as_ptr()); - - if found == glib_ffi::GFALSE { - return None; - } - - Value::from_raw(gvalue).and_then(TypedValue::from_value) - } - } - - pub fn get_index<'a, T: Tag<'a>>(&'a self, idx: u32) -> Option> { - unsafe { - let tag_name = CString::new(T::tag_name()).unwrap(); - - let value = - gst_ffi::gst_tag_list_get_value_index(self.as_ptr(), tag_name.as_ptr(), idx); - - if value.is_null() { - return None; - } - - ValueRef::from_ptr(value).and_then(TypedValueRef::from_value_ref) - } - } - - pub fn get_size<'a, T: Tag<'a>>(&'a self) -> u32 { - unsafe { - let tag_name = CString::new(T::tag_name()).unwrap(); - - gst_ffi::gst_tag_list_get_tag_size(self.as_ptr(), tag_name.as_ptr()) - } - } - - pub fn iter_tag<'a, T: Tag<'a>>(&'a self) -> TagIterator<'a, T> { - TagIterator::new(self) - } - - pub fn to_string(&self) -> String { - unsafe { - let ptr = gst_ffi::gst_tag_list_to_string(self.as_ptr()); - let s = CStr::from_ptr(ptr).to_str().unwrap().into(); - glib_ffi::g_free(ptr as glib_ffi::gpointer); - - s - } - } -} - -impl fmt::Debug for TagList { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&self.to_string()) - } -} - -impl PartialEq for TagList { - fn eq(&self, other: &TagList) -> bool { - (unsafe { gst_ffi::gst_tag_list_is_equal(self.as_ptr(), other.as_ptr()) } == - glib_ffi::GTRUE) - } -} - -impl Eq for TagList {} - -impl ToOwned for TagList { - type Owned = GstRc; - - fn to_owned(&self) -> GstRc { - unsafe { GstRc::from_unowned_ptr(self.as_ptr()) } - } -} - -unsafe impl Sync for TagList {} -unsafe impl Send for TagList {} - -pub struct TagIterator<'a, T: Tag<'a>> { - taglist: &'a TagList, - idx: u32, - size: u32, - phantom: PhantomData, -} - -impl<'a, T: Tag<'a>> TagIterator<'a, T> { - fn new(taglist: &'a TagList) -> TagIterator<'a, T> { - TagIterator { - taglist: taglist, - idx: 0, - size: taglist.get_size::(), - phantom: PhantomData, - } - } -} - -impl<'a, T: Tag<'a>> Iterator for TagIterator<'a, T> { - type Item = TypedValueRef<'a, T::TagType>; - - fn next(&mut self) -> Option { - if self.idx >= self.size { - return None; - } - - let item = self.taglist.get_index::(self.idx); - self.idx += 1; - - item - } - - fn size_hint(&self) -> (usize, Option) { - if self.idx == self.size { - return (0, Some(0)); - } - - let remaining = (self.size - self.idx) as usize; - - (remaining, Some(remaining)) - } -} - -impl<'a, T: Tag<'a>> DoubleEndedIterator for TagIterator<'a, T> { - fn next_back(&mut self) -> Option { - if self.idx == self.size { - return None; - } - - self.size -= 1; - self.taglist.get_index::(self.size) - } -} - -impl<'a, T: Tag<'a>> ExactSizeIterator for TagIterator<'a, T> {} - -#[cfg(test)] -mod tests { - use super::*; - use std::ptr; - - fn init() { - unsafe { - gst_ffi::gst_init(ptr::null_mut(), ptr::null_mut()); - } - } - - #[test] - fn test_add() { - init(); - - let mut tags = TagList::new(); - assert_eq!(tags.to_string(), "taglist;"); - { - let tags = tags.get_mut().unwrap(); - tags.add::("some title".into(), MergeMode::Append); - tags.add::<Duration>((1000u64 * 1000 * 1000 * 120).into(), MergeMode::Append); - } - assert_eq!( - tags.to_string(), - "taglist, title=(string)\"some\\ title\", duration=(guint64)120000000000;" - ); - } - - #[test] - fn test_get() { - init(); - - let mut tags = TagList::new(); - assert_eq!(tags.to_string(), "taglist;"); - { - let tags = tags.get_mut().unwrap(); - tags.add::<Title>("some title".into(), MergeMode::Append); - tags.add::<Duration>((1000u64 * 1000 * 1000 * 120).into(), MergeMode::Append); - } - - assert_eq!(tags.get::<Title>().unwrap().get(), "some title"); - assert_eq!( - tags.get::<Duration>().unwrap().get(), - (1000u64 * 1000 * 1000 * 120) - ); - assert_eq!(tags.get_index::<Title>(0).unwrap().get(), "some title"); - assert_eq!( - tags.get_index::<Duration>(0).unwrap().get(), - (1000u64 * 1000 * 1000 * 120) - ); - } -} diff --git a/gst-plugin/src/utils.rs b/gst-plugin/src/utils.rs index e247f30b..41be884a 100644 --- a/gst-plugin/src/utils.rs +++ b/gst-plugin/src/utils.rs @@ -8,159 +8,8 @@ use libc::c_char; use std::ffi::CString; -use std::i32; -use num_rational::Rational32; - -use gst_ffi; - -pub struct Element(*mut gst_ffi::GstElement); - -impl Element { - pub unsafe fn new(element: *mut gst_ffi::GstElement) -> Element { - if element.is_null() { - panic!("NULL not allowed"); - } - - gst_ffi::gst_object_ref(element as *mut gst_ffi::GstObject); - - Element(element) - } - - pub unsafe fn as_ptr(&self) -> *mut gst_ffi::GstElement { - self.0 - } -} - -impl Drop for Element { - fn drop(&mut self) { - unsafe { - gst_ffi::gst_object_unref(self.0 as *mut gst_ffi::GstObject); - } - } -} - -impl Clone for Element { - fn clone(&self) -> Self { - unsafe { Element::new(self.0) } - } -} #[no_mangle] pub unsafe extern "C" fn cstring_drop(ptr: *mut c_char) { let _ = CString::from_raw(ptr); } - -pub fn f64_to_fraction(val: f64) -> Option<Rational32> { - // Continued fractions algorithm - // http://mathforum.org/dr.math/faq/faq.fractions.html#decfrac - - let negative = val < 0.0; - - let mut q = val.abs(); - let mut n0 = 0; - let mut d0 = 1; - let mut n1 = 1; - let mut d1 = 0; - - const MAX_ITERATIONS: usize = 30; - const MAX_ERROR: f64 = 1.0e-20; - // 1/EPSILON > i32::MAX - const EPSILON: f64 = 1.0e-10; - - // Overflow - if q > i32::MAX as f64 { - return None; - } - - for _ in 0..MAX_ITERATIONS { - let a = q as u32; - let f = q - (a as f64); - - // Prevent overflow - if a != 0 && - (n1 > (i32::MAX as u32) / a || d1 > (i32::MAX as u32) / a || - a * n1 > (i32::MAX as u32) - n0 || a * d1 > (i32::MAX as u32) - d0) - { - break; - } - - let n = a * n1 + n0; - let d = a * d1 + d0; - - n0 = n1; - d0 = d1; - n1 = n; - d1 = d; - - // Prevent division by ~0 - if f < EPSILON { - break; - } - let r = 1.0 / f; - - // Simplify fraction. Doing so here instead of at the end - // allows us to get closer to the target value without overflows - let g = gcd(n1, d1); - if g != 0 { - n1 /= g; - d1 /= g; - } - - // Close enough? - if ((n as f64) / (d as f64) - val).abs() < MAX_ERROR { - break; - } - - q = r; - } - - // Guaranteed by the overflow check - assert!(n1 <= i32::MAX as u32); - assert!(d1 <= i32::MAX as u32); - - // Overflow - if d1 == 0 { - return None; - } - - // Make negative again if needed - if negative { - Some(Rational32::new(-(n1 as i32), d1 as i32)) - } else { - Some(Rational32::new(n1 as i32, d1 as i32)) - } -} - -pub fn gcd(mut a: u32, mut b: u32) -> u32 { - // Euclid's algorithm - while b != 0 { - let tmp = a; - a = b; - b = tmp % b; - } - - a -} - -#[cfg(test)] -mod tests { - use super::*; - use num_rational::Rational32; - - #[test] - fn test_gcd() { - assert_eq!(gcd(2 * 2 * 2 * 2, 2 * 2 * 2 * 3), 2 * 2 * 2); - assert_eq!(gcd(2 * 3 * 5 * 5 * 7, 2 * 5 * 7), 2 * 5 * 7); - } - - #[test] - fn test_f64_to_fraction() { - assert_eq!(f64_to_fraction(2.0), Some(Rational32::new(2, 1))); - assert_eq!(f64_to_fraction(2.5), Some(Rational32::new(5, 2))); - assert_eq!( - f64_to_fraction(0.127659574), - Some(Rational32::new(29013539, 227272723)) - ); - assert_eq!(f64_to_fraction(29.97), Some(Rational32::new(2997, 100))); - } -} diff --git a/gst-plugin/src/value.rs b/gst-plugin/src/value.rs deleted file mode 100644 index 936a41d3..00000000 --- a/gst-plugin/src/value.rs +++ /dev/null @@ -1,960 +0,0 @@ -// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com> -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::ffi::CStr; -use std::mem; -use std::marker::PhantomData; -use std::borrow::Cow; -use std::fmt; -use std::slice; -use libc::c_char; - -pub use num_rational::Rational32; - -use buffer::*; -use miniobject::*; - -use glib_ffi; -use gobject_ffi; -use gst_ffi; - -#[repr(C)] -pub struct Value(gobject_ffi::GValue); - -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum ValueView<'a> { - Bool(bool), - Int(i32), - UInt(u32), - Int64(i64), - UInt64(u64), - String(Cow<'a, str>), - Fraction(Rational32), - Buffer(GstRc<Buffer>), - Array(Cow<'a, [Value]>), -} - -impl<'a> ValueView<'a> { - pub fn try_get<T: ValueType<'a>>(&'a self) -> Option<T> { - T::from_value_view(self) - } -} - -pub trait ValueType<'a> -where - Self: Sized, -{ - fn g_type() -> glib_ffi::GType; - - fn from_value(v: &'a gobject_ffi::GValue) -> Option<Self>; - fn from_value_view(v: &'a ValueView<'a>) -> Option<Self>; -} - -lazy_static! { - static ref TYPE_BUFFER: glib_ffi::GType = unsafe { gst_ffi::gst_buffer_get_type() }; - static ref TYPE_FRACTION: glib_ffi::GType = unsafe { gst_ffi::gst_fraction_get_type() }; - static ref TYPE_GST_VALUE_ARRAY: glib_ffi::GType = unsafe { gst_ffi::gst_value_array_get_type() }; -} - -impl Value { - pub unsafe fn as_ptr(&self) -> *const gobject_ffi::GValue { - &self.0 - } - - pub unsafe fn from_ptr(ptr: *const gobject_ffi::GValue) -> Option<Value> { - if ptr.is_null() || !Value::is_supported_type((*ptr).g_type) { - return None; - } - - let mut value = Value(mem::zeroed()); - gobject_ffi::g_value_init(&mut value.0, (*ptr).g_type); - gobject_ffi::g_value_copy(ptr, &mut value.0); - - Some(value) - } - - pub fn from_value_ref<'a>(v: &ValueRef<'a>) -> Value { - unsafe { Value::from_ptr(v.0) }.unwrap() - } - - pub unsafe fn from_raw(value: gobject_ffi::GValue) -> Option<Value> { - if !Value::is_supported_type(value.g_type) { - return None; - } - Some(Value(value)) - } - - pub unsafe fn into_raw(mut self) -> gobject_ffi::GValue { - let v = mem::replace(&mut self.0, mem::zeroed()); - mem::forget(self); - - v - } - - fn is_supported_type(typ: glib_ffi::GType) -> bool { - match typ { - gobject_ffi::G_TYPE_BOOLEAN | - gobject_ffi::G_TYPE_INT | - gobject_ffi::G_TYPE_UINT | - gobject_ffi::G_TYPE_INT64 | - gobject_ffi::G_TYPE_UINT64 | - gobject_ffi::G_TYPE_STRING => true, - typ if typ == *TYPE_FRACTION => true, - //typ if typ == *TYPE_BUFFER => true - typ if typ == *TYPE_GST_VALUE_ARRAY => true, - _ => false, - } - } - - pub fn new<T: Into<Value>>(v: T) -> Value { - v.into() - } - - pub fn from_value_view(v: ValueView) -> Value { - match v { - ValueView::Bool(v) => Value::from(v), - ValueView::Int(v) => Value::from(v), - ValueView::UInt(v) => Value::from(v), - ValueView::Int64(v) => Value::from(v), - ValueView::UInt64(v) => Value::from(v), - ValueView::Fraction(v) => Value::from(v), - ValueView::String(v) => Value::from(v), - ValueView::Array(v) => Value::from(v), - ValueView::Buffer(v) => Value::from(v), - } - } - - pub fn get(&self) -> ValueView { - match self.0.g_type { - gobject_ffi::G_TYPE_BOOLEAN => ValueView::Bool(bool::from_value(&self.0).unwrap()), - gobject_ffi::G_TYPE_INT => ValueView::Int(i32::from_value(&self.0).unwrap()), - gobject_ffi::G_TYPE_UINT => ValueView::UInt(u32::from_value(&self.0).unwrap()), - gobject_ffi::G_TYPE_INT64 => ValueView::Int64(i64::from_value(&self.0).unwrap()), - gobject_ffi::G_TYPE_UINT64 => ValueView::UInt64(u64::from_value(&self.0).unwrap()), - typ if typ == *TYPE_FRACTION => { - ValueView::Fraction(Rational32::from_value(&self.0).unwrap()) - } - gobject_ffi::G_TYPE_STRING => ValueView::String(Cow::Borrowed( - <&str as ValueType>::from_value(&self.0).unwrap(), - )), - typ if typ == *TYPE_GST_VALUE_ARRAY => ValueView::Array(Cow::Borrowed( - <&[Value] as ValueType>::from_value(&self.0).unwrap(), - )), - typ if typ == *TYPE_BUFFER => { - ValueView::Buffer(<GstRc<Buffer> as ValueType>::from_value(&self.0).unwrap()) - } - _ => unreachable!(), - } - } - - pub fn try_get<'a, T: ValueType<'a>>(&'a self) -> Option<T> { - T::from_value(&self.0) - } -} - -impl Clone for Value { - fn clone(&self) -> Self { - unsafe { - let mut new_value = Value(mem::zeroed()); - gobject_ffi::g_value_init(&mut new_value.0, self.0.g_type); - gobject_ffi::g_value_copy(&self.0, &mut new_value.0); - - new_value - } - } -} - -impl PartialEq for Value { - fn eq(&self, other: &Value) -> bool { - self.get().eq(&other.get()) - } -} -impl Eq for Value {} - -impl<'a> PartialEq<ValueRef<'a>> for Value { - fn eq(&self, other: &ValueRef<'a>) -> bool { - self.get().eq(&other.get()) - } -} - -impl fmt::Debug for Value { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.get().fmt(f) - } -} - -impl Drop for Value { - fn drop(&mut self) { - unsafe { - if self.0.g_type != gobject_ffi::G_TYPE_NONE { - gobject_ffi::g_value_unset(&mut self.0); - } - } - } -} - -#[derive(Clone)] -pub struct ValueRef<'a>(&'a gobject_ffi::GValue); - -impl<'a> ValueRef<'a> { - pub unsafe fn as_ptr(&self) -> *const gobject_ffi::GValue { - self.0 - } - - pub fn from_value(v: &'a Value) -> ValueRef<'a> { - ValueRef(&v.0) - } - - pub unsafe fn from_ptr(ptr: *const gobject_ffi::GValue) -> Option<ValueRef<'a>> { - if ptr.is_null() || !Value::is_supported_type((*ptr).g_type) { - return None; - } - - Some(ValueRef(&*ptr)) - } - - pub fn get(&self) -> ValueView { - match self.0.g_type { - gobject_ffi::G_TYPE_BOOLEAN => ValueView::Bool(bool::from_value(self.0).unwrap()), - gobject_ffi::G_TYPE_INT => ValueView::Int(i32::from_value(self.0).unwrap()), - gobject_ffi::G_TYPE_UINT => ValueView::UInt(u32::from_value(self.0).unwrap()), - gobject_ffi::G_TYPE_INT64 => ValueView::Int64(i64::from_value(self.0).unwrap()), - gobject_ffi::G_TYPE_UINT64 => ValueView::UInt64(u64::from_value(self.0).unwrap()), - typ if typ == *TYPE_FRACTION => { - ValueView::Fraction(Rational32::from_value(self.0).unwrap()) - } - gobject_ffi::G_TYPE_STRING => ValueView::String(Cow::Borrowed( - <&str as ValueType>::from_value(self.0).unwrap(), - )), - typ if typ == *TYPE_GST_VALUE_ARRAY => ValueView::Array(Cow::Borrowed( - <&[Value] as ValueType>::from_value(self.0).unwrap(), - )), - typ if typ == *TYPE_BUFFER => { - ValueView::Buffer(<GstRc<Buffer> as ValueType>::from_value(self.0).unwrap()) - } - _ => unreachable!(), - } - } - - pub fn try_get<T: ValueType<'a>>(&self) -> Option<T> { - T::from_value(self.0) - } -} - -impl<'a> PartialEq for ValueRef<'a> { - fn eq(&self, other: &ValueRef<'a>) -> bool { - self.get().eq(&other.get()) - } -} -impl<'a> Eq for ValueRef<'a> {} - -impl<'a> PartialEq<Value> for ValueRef<'a> { - fn eq(&self, other: &Value) -> bool { - self.get().eq(&other.get()) - } -} - -impl<'a> fmt::Debug for ValueRef<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.get().fmt(f) - } -} - -macro_rules! impl_value_type_simple( - ($typ:ty, $variant:ident, $g_type:expr, $getter:expr, $setter:expr) => { - impl<'a> ValueType<'a> for $typ { - fn g_type() -> glib_ffi::GType { - $g_type - } - - fn from_value(value: &'a gobject_ffi::GValue) -> Option<Self> { - if value.g_type != Self::g_type() { - return None; - } - - unsafe { - Some($getter(&value)) - } - } - - fn from_value_view(value_view: &'a ValueView<'a>) -> Option<Self> { - if let ValueView::$variant(ref v) = *value_view { - Some(*v) - } else { - None - } - } - } - - impl From<$typ> for Value { - fn from(v: $typ) -> Value { - unsafe { - let mut value = Value(mem::zeroed()); - - gobject_ffi::g_value_init(&mut value.0, <$typ as ValueType>::g_type()); - $setter(&mut value.0, v); - - value - } - } - } - }; -); - -impl_value_type_simple!( - bool, - Bool, - gobject_ffi::G_TYPE_BOOLEAN, - |value: &gobject_ffi::GValue| !(gobject_ffi::g_value_get_boolean(value) == 0), - |value: &mut gobject_ffi::GValue, v| { - gobject_ffi::g_value_set_boolean(value, if v { glib_ffi::GTRUE } else { glib_ffi::GFALSE }) - } -); -impl_value_type_simple!( - i32, - Int, - gobject_ffi::G_TYPE_INT, - |value: &gobject_ffi::GValue| gobject_ffi::g_value_get_int(value), - |value: &mut gobject_ffi::GValue, v| gobject_ffi::g_value_set_int(value, v) -); -impl_value_type_simple!( - u32, - UInt, - gobject_ffi::G_TYPE_UINT, - |value: &gobject_ffi::GValue| gobject_ffi::g_value_get_uint(value), - |value: &mut gobject_ffi::GValue, v| gobject_ffi::g_value_set_uint(value, v) -); -impl_value_type_simple!( - i64, - Int64, - gobject_ffi::G_TYPE_INT64, - |value: &gobject_ffi::GValue| gobject_ffi::g_value_get_int64(value), - |value: &mut gobject_ffi::GValue, v| gobject_ffi::g_value_set_int64(value, v) -); -impl_value_type_simple!( - u64, - UInt64, - gobject_ffi::G_TYPE_UINT64, - |value: &gobject_ffi::GValue| gobject_ffi::g_value_get_uint64(value), - |value: &mut gobject_ffi::GValue, v| gobject_ffi::g_value_set_uint64(value, v) -); -impl_value_type_simple!( - Rational32, - Fraction, - *TYPE_FRACTION, - |value: &gobject_ffi::GValue| { - Rational32::new( - gst_ffi::gst_value_get_fraction_numerator(value), - gst_ffi::gst_value_get_fraction_denominator(value), - ) - }, - |value: &mut gobject_ffi::GValue, v: Rational32| { - gst_ffi::gst_value_set_fraction(value, *v.numer(), *v.denom()) - } -); - -impl<'a> ValueType<'a> for &'a str { - fn g_type() -> glib_ffi::GType { - gobject_ffi::G_TYPE_STRING - } - - fn from_value(value: &'a gobject_ffi::GValue) -> Option<Self> { - if value.g_type != Self::g_type() { - return None; - } - - unsafe { - let s = gobject_ffi::g_value_get_string(value); - if s.is_null() { - return Some(""); - } - - let cstr = CStr::from_ptr(s).to_str().expect("Invalid string"); - Some(cstr) - } - } - - fn from_value_view(value_view: &'a ValueView<'a>) -> Option<Self> { - if let ValueView::String(ref v) = *value_view { - Some(v.as_ref()) - } else { - None - } - } -} - -impl<'a> From<Cow<'a, str>> for Value { - fn from(v: Cow<'a, str>) -> Value { - unsafe { - let mut value = Value(mem::zeroed()); - - gobject_ffi::g_value_init(&mut value.0, <&str as ValueType>::g_type()); - let v_cstr = glib_ffi::g_strndup(v.as_ptr() as *const c_char, v.len()); - gobject_ffi::g_value_take_string(&mut value.0, v_cstr); - - value - } - } -} - -impl From<String> for Value { - fn from(v: String) -> Value { - Value::from(Cow::Owned::<str>(v)) - } -} - -impl<'a> From<&'a str> for Value { - fn from(v: &'a str) -> Value { - Value::from(Cow::Borrowed::<str>(v)) - } -} - -impl<'a> ValueType<'a> for GstRc<Buffer> { - fn g_type() -> glib_ffi::GType { - *TYPE_BUFFER - } - - fn from_value(value: &'a gobject_ffi::GValue) -> Option<Self> { - if value.g_type != Self::g_type() { - return None; - } - - unsafe { - let buffer = gobject_ffi::g_value_get_boxed(value) as *mut gst_ffi::GstBuffer; - Some(GstRc::from_unowned_ptr(buffer)) - } - } - - fn from_value_view(value_view: &'a ValueView<'a>) -> Option<Self> { - if let ValueView::Buffer(ref v) = *value_view { - Some(v.clone()) - } else { - None - } - } -} - -impl From<GstRc<Buffer>> for Value { - fn from(v: GstRc<Buffer>) -> Value { - Value::from(v.as_ref()) - } -} - -impl<'a> From<&'a GstRc<Buffer>> for Value { - fn from(v: &'a GstRc<Buffer>) -> Value { - Value::from(v.as_ref()) - } -} - -impl<'a> From<&'a Buffer> for Value { - fn from(v: &'a Buffer) -> Value { - unsafe { - let mut value = Value(mem::zeroed()); - - gobject_ffi::g_value_init(&mut value.0, <GstRc<Buffer> as ValueType>::g_type()); - gobject_ffi::g_value_set_boxed(&mut value.0, v.as_ptr() as glib_ffi::gpointer); - - value - } - } -} - -impl<'a> ValueType<'a> for &'a [Value] { - fn g_type() -> glib_ffi::GType { - *TYPE_GST_VALUE_ARRAY - } - - fn from_value(value: &'a gobject_ffi::GValue) -> Option<Self> { - if value.g_type != Self::g_type() { - return None; - } - - unsafe { - let arr = value.data[0] as *const glib_ffi::GArray; - - if arr.is_null() { - Some(&[]) - } else { - let arr = &*arr; - Some(slice::from_raw_parts( - arr.data as *const Value, - arr.len as usize, - )) - } - } - } - - fn from_value_view(value_view: &'a ValueView<'a>) -> Option<Self> { - if let ValueView::Array(ref v) = *value_view { - Some(v.as_ref()) - } else { - None - } - } -} - -impl<'a> From<Cow<'a, [Value]>> for Value { - fn from(v: Cow<'a, [Value]>) -> Value { - unsafe { - let mut value = Value(mem::zeroed()); - - gobject_ffi::g_value_init(&mut value.0, <&[Value] as ValueType>::g_type()); - - match v { - Cow::Borrowed(array) => for e in array { - gst_ffi::gst_value_array_append_value( - &mut value.0, - e.as_ptr() as *mut gobject_ffi::GValue, - ); - }, - Cow::Owned(array) => for e in array { - gst_ffi::gst_value_array_append_and_take_value( - &mut value.0, - e.as_ptr() as *mut gobject_ffi::GValue, - ); - mem::forget(e); - }, - } - - value - } - } -} - -impl From<Vec<Value>> for Value { - fn from(v: Vec<Value>) -> Value { - Value::from(Cow::Owned::<[Value]>(v)) - } -} - -impl<'a> From<&'a Vec<Value>> for Value { - fn from(v: &'a Vec<Value>) -> Value { - Value::from(Cow::Borrowed::<[Value]>(v.as_ref())) - } -} - -impl<'a> From<&'a [Value]> for Value { - fn from(v: &'a [Value]) -> Value { - Value::from(Cow::Borrowed::<[Value]>(v)) - } -} - -impl<'a> From<ValueView<'a>> for Value { - fn from(value_view: ValueView<'a>) -> Value { - Value::from_value_view(value_view) - } -} - -impl<'a> From<&'a ValueView<'a>> for Value { - fn from(value_view: &'a ValueView<'a>) -> Value { - Value::from_value_view(value_view.clone()) - } -} - -impl From<(i32, i32)> for Value { - fn from((f_n, f_d): (i32, i32)) -> Value { - Value::from(Rational32::new(f_n, f_d)) - } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct TypedValue<T> { - value: Value, - phantom: PhantomData<T>, -} - -impl<'a, T> TypedValue<T> -where - T: ValueType<'a>, -{ - pub fn new<VT: Into<TypedValue<T>>>(v: VT) -> TypedValue<T> { - v.into() - } - - pub fn from_value(value: Value) -> Option<TypedValue<T>> { - if value.0.g_type != T::g_type() { - return None; - } - - Some(TypedValue { - value: value, - phantom: PhantomData, - }) - } - - pub fn from_typed_value_ref(v: &'a TypedValueRef<'a, T>) -> TypedValue<T> { - TypedValue { - value: Value::from_value_ref(&v.value), - phantom: PhantomData, - } - } - - pub fn get(&'a self) -> T { - self.value.try_get::<T>().unwrap() - } - - pub fn into_value(self) -> Value { - self.value - } - - pub unsafe fn as_ptr(&self) -> *const gobject_ffi::GValue { - &self.value.0 - } - - pub unsafe fn from_ptr(ptr: *const gobject_ffi::GValue) -> Option<TypedValue<T>> { - if let Some(value) = Value::from_ptr(ptr) { - return TypedValue::from_value(value); - } - None - } - - pub unsafe fn from_raw(value: gobject_ffi::GValue) -> Option<TypedValue<T>> { - if let Some(value) = Value::from_raw(value) { - return TypedValue::from_value(value); - } - None - } - - pub unsafe fn into_raw(mut self) -> gobject_ffi::GValue { - mem::replace(&mut self.value.0, mem::zeroed()) - } -} - -impl<'a, T> From<T> for TypedValue<T> -where - T: ValueType<'a> + Into<Value>, -{ - fn from(v: T) -> Self { - TypedValue::from_value(Value::new(v)).unwrap() - } -} - -impl<'a> From<Cow<'a, str>> for TypedValue<&'a str> { - fn from(v: Cow<'a, str>) -> Self { - TypedValue::from_value(Value::new(v)).unwrap() - } -} - -impl<'a> From<String> for TypedValue<&'a str> { - fn from(v: String) -> Self { - TypedValue::from_value(Value::new(v)).unwrap() - } -} - -impl<'a> From<Vec<Value>> for TypedValue<&'a [Value]> { - fn from(v: Vec<Value>) -> Self { - TypedValue::from_value(Value::new(v)).unwrap() - } -} - -impl<'a> From<&'a Vec<Value>> for TypedValue<&'a [Value]> { - fn from(v: &'a Vec<Value>) -> Self { - TypedValue::from_value(Value::new(v)).unwrap() - } -} - -impl<'a> From<Cow<'a, [Value]>> for TypedValue<&'a [Value]> { - fn from(v: Cow<'a, [Value]>) -> Self { - TypedValue::from_value(Value::new(v)).unwrap() - } -} - -impl<'a> From<&'a GstRc<Buffer>> for TypedValue<GstRc<Buffer>> { - fn from(v: &'a GstRc<Buffer>) -> Self { - TypedValue::from_value(Value::new(v)).unwrap() - } -} - -impl<'a> From<&'a Buffer> for TypedValue<GstRc<Buffer>> { - fn from(v: &'a Buffer) -> Self { - TypedValue::from_value(Value::new(v)).unwrap() - } -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct TypedValueRef<'a, T> { - value: ValueRef<'a>, - phantom: PhantomData<T>, -} - -impl<'a, T> TypedValueRef<'a, T> -where - T: ValueType<'a>, -{ - pub fn from_typed_value(v: &'a TypedValue<T>) -> TypedValueRef<'a, T> { - TypedValueRef { - value: ValueRef::from_value(&v.value), - phantom: PhantomData, - } - } - - pub fn from_value_ref(value: ValueRef<'a>) -> Option<TypedValueRef<'a, T>> { - if value.0.g_type != T::g_type() { - return None; - } - - Some(TypedValueRef { - value: value, - phantom: PhantomData, - }) - } - - pub fn get(&'a self) -> T { - self.value.try_get::<T>().unwrap() - } - - pub fn into_value(self) -> ValueRef<'a> { - self.value - } - - pub unsafe fn as_ptr(&self) -> *const gobject_ffi::GValue { - self.value.0 - } - - pub unsafe fn from_ptr(ptr: *const gobject_ffi::GValue) -> Option<TypedValueRef<'a, T>> { - if let Some(value) = ValueRef::from_ptr(ptr) { - return TypedValueRef::from_value_ref(value); - } - None - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::ptr; - - macro_rules! gen_test_value( - ($name: ident, $typ:ty, $value:expr, $variant:ident) => { - #[test] - fn $name() { - unsafe { gst_ffi::gst_init(ptr::null_mut(), ptr::null_mut()) }; - - let value = Value::new($value); - if let ValueView::$variant(v) = value.get() { - assert_eq!(v, $value); - } else { - unreachable!(); - } - - if let Some(v) = value.get().try_get::<$typ>() { - assert_eq!(v, $value); - } else { - unreachable!(); - } - - let value2 = value.clone(); - if let ValueView::$variant(v) = value2.get() { - assert_eq!(v, $value); - } else { - unreachable!(); - } - - let value2 = Value::from_value_view(value.get()); - assert_eq!(value2, value); - - let value3 = TypedValue::new($value); - assert_eq!(value3.get(), $value); - - if let Some(value3) = TypedValue::<$typ>::from_value(value) { - assert_eq!(value3.get(), $value); - } else { - unreachable!(); - } - } - }; - ); - - gen_test_value!(int, i32, 12i32, Int); - gen_test_value!(uint, u32, 12u32, UInt); - gen_test_value!(int64, i64, 12i64, Int64); - gen_test_value!(uint64, u64, 12u64, UInt64); - gen_test_value!(boolean, bool, true, Bool); - gen_test_value!(fraction, Rational32, Rational32::new(1, 2), Fraction); - - #[test] - fn string_owned() { - unsafe { gst_ffi::gst_init(ptr::null_mut(), ptr::null_mut()) }; - - let orig_v = String::from("foo"); - - let value = Value::new(orig_v.clone()); - if let ValueView::String(v) = value.get() { - assert_eq!(v, orig_v); - } else { - unreachable!(); - } - - if let Some(v) = value.get().try_get::<&str>() { - assert_eq!(v, orig_v); - } else { - unreachable!(); - } - - let value2 = value.clone(); - if let ValueView::String(v) = value2.get() { - assert_eq!(v, orig_v); - } else { - unreachable!(); - } - - let value2 = Value::from_value_view(value.get()); - assert_eq!(value2, value); - - - let value2 = Value::from_value_view(value.get()); - assert_eq!(value2, value); - - let value3 = TypedValue::new(orig_v.clone()); - assert_eq!(value3.get(), orig_v.as_str()); - - if let Some(value3) = TypedValue::<&str>::from_value(value) { - assert_eq!(value3.get(), orig_v.as_str()); - } else { - unreachable!(); - } - } - - #[test] - fn string_borrowed() { - unsafe { gst_ffi::gst_init(ptr::null_mut(), ptr::null_mut()) }; - - let orig_v = "foo"; - - let value = Value::new(orig_v); - if let ValueView::String(v) = value.get() { - assert_eq!(v, orig_v); - } else { - unreachable!(); - } - - if let Some(v) = value.get().try_get::<&str>() { - assert_eq!(v, orig_v); - } else { - unreachable!(); - } - - let value2 = value.clone(); - if let ValueView::String(v) = value2.get() { - assert_eq!(v, orig_v); - } else { - unreachable!(); - } - - let value2 = Value::from_value_view(value.get()); - assert_eq!(value2, value); - - let value3 = TypedValue::new(orig_v); - assert_eq!(value3.get(), orig_v); - - if let Some(value3) = TypedValue::<&str>::from_value(value) { - assert_eq!(value3.get(), orig_v); - } else { - unreachable!(); - } - } - - #[test] - fn array_owned() { - unsafe { gst_ffi::gst_init(ptr::null_mut(), ptr::null_mut()) }; - - let orig_v = vec![Value::new("a"), Value::new("b")]; - - let value = Value::new(orig_v.clone()); - if let ValueView::Array(arr) = value.get() { - assert_eq!(arr, orig_v.as_slice()); - } else { - unreachable!(); - } - - if let Some(v) = value.get().try_get::<&[Value]>() { - assert_eq!(v, orig_v.as_slice()); - } else { - unreachable!(); - } - - let value2 = Value::from_value_view(value.get()); - assert_eq!(value2, value); - - let value2 = Value::from_value_view(value.get()); - assert_eq!(value2, value); - - let value3 = TypedValue::new(orig_v.clone()); - assert_eq!(value3.get(), orig_v.as_slice()); - - if let Some(value3) = TypedValue::<&[Value]>::from_value(value) { - assert_eq!(value3.get(), orig_v.as_slice()); - } else { - unreachable!(); - } - } - - #[test] - fn array_borrowed() { - unsafe { gst_ffi::gst_init(ptr::null_mut(), ptr::null_mut()) }; - - let orig_v = vec![Value::new("a"), Value::new("b")]; - - let value = Value::new(&orig_v); - if let ValueView::Array(arr) = value.get() { - assert_eq!(arr, orig_v.as_slice()); - } else { - unreachable!(); - } - - if let Some(arr) = value.get().try_get::<&[Value]>() { - assert_eq!(arr, orig_v.as_slice()); - } else { - unreachable!(); - } - - let value2 = Value::from_value_view(value.get()); - assert_eq!(value2, value); - - let value3 = TypedValue::new(orig_v.as_slice()); - assert_eq!(value3.get(), orig_v.as_slice()); - - if let Some(value3) = TypedValue::<&[Value]>::from_value(value) { - assert_eq!(value3.get(), orig_v.as_slice()); - } else { - unreachable!(); - } - } - - #[test] - fn buffer() { - unsafe { gst_ffi::gst_init(ptr::null_mut(), ptr::null_mut()) }; - - let orig_v = Buffer::from_vec(vec![1, 2, 3, 4]).unwrap(); - - let value = Value::new(orig_v.clone()); - if let ValueView::Buffer(buf) = value.get() { - assert_eq!(buf, orig_v); - } else { - unreachable!(); - } - - if let Some(buf) = value.get().try_get::<GstRc<Buffer>>() { - assert_eq!(buf, orig_v); - } else { - unreachable!(); - } - - let value2 = Value::from_value_view(value.get()); - assert_eq!(value2, value); - - let value3 = TypedValue::new(&orig_v); - assert_eq!(value3.get(), orig_v); - - if let Some(value3) = TypedValue::<GstRc<Buffer>>::from_value(value) { - assert_eq!(value3.get(), orig_v); - } else { - unreachable!(); - } - } -}