Run everything through rustfmt-nightly

This commit is contained in:
Sebastian Dröge 2017-07-31 14:36:35 +01:00
parent 3c27685e38
commit 6f04ddf797
22 changed files with 1175 additions and 909 deletions

View file

@ -37,11 +37,10 @@ impl FileSink {
pub fn new(element: Element) -> FileSink { pub fn new(element: Element) -> FileSink {
FileSink { FileSink {
streaming_state: StreamingState::Stopped, streaming_state: StreamingState::Stopped,
logger: Logger::root(GstDebugDrain::new(Some(&element), logger: Logger::root(
"rsfilesink", GstDebugDrain::new(Some(&element), "rsfilesink", 0, "Rust file sink"),
0, o!(),
"Rust file sink"), ),
o!()),
} }
} }
@ -51,12 +50,12 @@ impl FileSink {
} }
fn validate_uri(uri: &Url) -> Result<(), UriError> { fn validate_uri(uri: &Url) -> Result<(), UriError> {
let _ = try!(uri.to_file_path() let _ = try!(uri.to_file_path().or_else(|_| {
.or_else(|_| { Err(UriError::new(
Err(UriError::new(UriErrorKind::UnsupportedProtocol, UriErrorKind::UnsupportedProtocol,
Some(format!("Unsupported file URI '{}'", Some(format!("Unsupported file URI '{}'", uri.as_str())),
uri.as_str())))) ))
})); }));
Ok(()) Ok(())
} }
@ -70,23 +69,29 @@ impl Sink for FileSink {
return Err(error_msg!(SinkError::Failure, ["Sink already started"])); return Err(error_msg!(SinkError::Failure, ["Sink already started"]));
} }
let location = let location = try!(uri.to_file_path().or_else(|_| {
try!(uri.to_file_path() error!(self.logger, "Unsupported file URI '{}'", uri.as_str());
.or_else(|_| { Err(error_msg!(
error!(self.logger, "Unsupported file URI '{}'", uri.as_str()); SinkError::Failure,
Err(error_msg!(SinkError::Failure, ["Unsupported file URI '{}'", uri.as_str()]
["Unsupported file URI '{}'", uri.as_str()])) ))
})); }));
let file = try!(File::create(location.as_path()).or_else(|err| { let file = try!(File::create(location.as_path()).or_else(|err| {
error!(self.logger, error!(
"Could not open file for writing: {}", self.logger,
err.to_string()); "Could not open file for writing: {}",
Err(error_msg!(SinkError::OpenFailed, err.to_string()
["Could not open file for writing '{}': {}", );
location.to_str().unwrap_or("Non-UTF8 path"), Err(error_msg!(
err.to_string()])) SinkError::OpenFailed,
[
"Could not open file for writing '{}': {}",
location.to_str().unwrap_or("Non-UTF8 path"),
err.to_string()
]
))
})); }));
debug!(self.logger, "Opened file {:?}", file); debug!(self.logger, "Opened file {:?}", file);
@ -117,25 +122,29 @@ impl Sink for FileSink {
ref mut position, ref mut position,
} => (file, position), } => (file, position),
StreamingState::Stopped => { StreamingState::Stopped => {
return Err(FlowError::Error(error_msg!(SinkError::Failure, ["Not started yet"]))); return Err(FlowError::Error(
error_msg!(SinkError::Failure, ["Not started yet"]),
));
} }
}; };
let map = match buffer.map_read() { let map = match buffer.map_read() {
None => { None => {
return Err(FlowError::Error(error_msg!(SinkError::Failure, return Err(FlowError::Error(
["Failed to map buffer"]))); error_msg!(SinkError::Failure, ["Failed to map buffer"]),
));
} }
Some(map) => map, Some(map) => map,
}; };
let data = map.as_slice(); let data = map.as_slice();
try!(file.write_all(data) try!(file.write_all(data).or_else(|err| {
.or_else(|err| { error!(logger, "Failed to write: {}", err);
error!(logger, "Failed to write: {}", err); Err(FlowError::Error(error_msg!(
Err(FlowError::Error(error_msg!(SinkError::WriteFailed, SinkError::WriteFailed,
["Failed to write: {}", err]))) ["Failed to write: {}", err]
})); )))
}));
*position += data.len() as u64; *position += data.len() as u64;

View file

@ -35,11 +35,10 @@ impl FileSrc {
pub fn new(element: Element) -> FileSrc { pub fn new(element: Element) -> FileSrc {
FileSrc { FileSrc {
streaming_state: StreamingState::Stopped, streaming_state: StreamingState::Stopped,
logger: Logger::root(GstDebugDrain::new(Some(&element), logger: Logger::root(
"rsfilesrc", GstDebugDrain::new(Some(&element), "rsfilesrc", 0, "Rust file source"),
0, o!(),
"Rust file source"), ),
o!()),
} }
} }
@ -49,12 +48,12 @@ impl FileSrc {
} }
fn validate_uri(uri: &Url) -> Result<(), UriError> { fn validate_uri(uri: &Url) -> Result<(), UriError> {
let _ = try!(uri.to_file_path() let _ = try!(uri.to_file_path().or_else(|_| {
.or_else(|_| { Err(UriError::new(
Err(UriError::new(UriErrorKind::UnsupportedProtocol, UriErrorKind::UnsupportedProtocol,
Some(format!("Unsupported file URI '{}'", Some(format!("Unsupported file URI '{}'", uri.as_str())),
uri.as_str())))) ))
})); }));
Ok(()) Ok(())
} }
@ -80,22 +79,28 @@ impl Source for FileSrc {
return Err(error_msg!(SourceError::Failure, ["Source already started"])); return Err(error_msg!(SourceError::Failure, ["Source already started"]));
} }
let location = let location = try!(uri.to_file_path().or_else(|_| {
try!(uri.to_file_path() error!(self.logger, "Unsupported file URI '{}'", uri.as_str());
.or_else(|_| { Err(error_msg!(
error!(self.logger, "Unsupported file URI '{}'", uri.as_str()); SourceError::Failure,
Err(error_msg!(SourceError::Failure, ["Unsupported file URI '{}'", uri.as_str()]
["Unsupported file URI '{}'", uri.as_str()])) ))
})); }));
let file = try!(File::open(location.as_path()).or_else(|err| { let file = try!(File::open(location.as_path()).or_else(|err| {
error!(self.logger, error!(
"Could not open file for reading: {}", self.logger,
err.to_string()); "Could not open file for reading: {}",
Err(error_msg!(SourceError::OpenFailed, err.to_string()
["Could not open file for reading '{}': {}", );
location.to_str().unwrap_or("Non-UTF8 path"), Err(error_msg!(
err.to_string()])) SourceError::OpenFailed,
[
"Could not open file for reading '{}': {}",
location.to_str().unwrap_or("Non-UTF8 path"),
err.to_string()
]
))
})); }));
debug!(self.logger, "Opened file {:?}", file); debug!(self.logger, "Opened file {:?}", file);
@ -124,41 +129,42 @@ impl Source for FileSrc {
ref mut position, ref mut position,
} => (file, position), } => (file, position),
StreamingState::Stopped => { StreamingState::Stopped => {
return Err(FlowError::Error(error_msg!(SourceError::Failure, ["Not started yet"]))); return Err(FlowError::Error(
error_msg!(SourceError::Failure, ["Not started yet"]),
));
} }
}; };
if *position != offset { if *position != offset {
try!(file.seek(SeekFrom::Start(offset)) try!(file.seek(SeekFrom::Start(offset)).or_else(|err| {
.or_else(|err| { error!(logger, "Failed to seek to {}: {:?}", offset, err);
error!(logger, "Failed to seek to {}: {:?}", offset, err); Err(FlowError::Error(error_msg!(
Err(FlowError::Error(error_msg!(SourceError::SeekFailed, SourceError::SeekFailed,
["Failed to seek to {}: {}", ["Failed to seek to {}: {}", offset, err.to_string()]
offset, )))
err.to_string()]))) }));
}));
*position = offset; *position = offset;
} }
let size = { let size = {
let mut map = match buffer.map_readwrite() { let mut map = match buffer.map_readwrite() {
None => { None => {
return Err(FlowError::Error(error_msg!(SourceError::Failure, return Err(FlowError::Error(
["Failed to map buffer"]))); error_msg!(SourceError::Failure, ["Failed to map buffer"]),
));
} }
Some(map) => map, Some(map) => map,
}; };
let data = map.as_mut_slice(); let data = map.as_mut_slice();
try!(file.read(data) try!(file.read(data).or_else(|err| {
.or_else(|err| { error!(logger, "Failed to read: {:?}", err);
error!(logger, "Failed to read: {:?}", err); Err(FlowError::Error(error_msg!(
Err(FlowError::Error(error_msg!(SourceError::ReadFailed, SourceError::ReadFailed,
["Failed to read at {}: {}", ["Failed to read at {}: {}", offset, err.to_string()]
offset, )))
err.to_string()]))) }))
}))
}; };
*position += size as u64; *position += size as u64;

View file

@ -6,7 +6,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![crate_type="cdylib"] #![crate_type = "cdylib"]
extern crate url; extern crate url;
#[macro_use] #[macro_use]
@ -25,40 +25,46 @@ use filesrc::FileSrc;
use filesink::FileSink; use filesink::FileSink;
fn plugin_init(plugin: &Plugin) -> bool { fn plugin_init(plugin: &Plugin) -> bool {
source_register(plugin, source_register(
SourceInfo { plugin,
name: "rsfilesrc".into(), SourceInfo {
long_name: "File Source".into(), name: "rsfilesrc".into(),
description: "Reads local files".into(), long_name: "File Source".into(),
classification: "Source/File".into(), description: "Reads local files".into(),
author: "Sebastian Dröge <sebastian@centricular.com>".into(), classification: "Source/File".into(),
rank: 256 + 100, author: "Sebastian Dröge <sebastian@centricular.com>".into(),
create_instance: FileSrc::new_boxed, rank: 256 + 100,
protocols: vec!["file".into()], create_instance: FileSrc::new_boxed,
push_only: false, protocols: vec!["file".into()],
}); push_only: false,
},
);
sink_register(plugin, sink_register(
SinkInfo { plugin,
name: "rsfilesink".into(), SinkInfo {
long_name: "File Sink".into(), name: "rsfilesink".into(),
description: "Writes to local files".into(), long_name: "File Sink".into(),
classification: "Sink/File".into(), description: "Writes to local files".into(),
author: "Luis de Bethencourt <luisbg@osg.samsung.com>".into(), classification: "Sink/File".into(),
rank: 256 + 100, author: "Luis de Bethencourt <luisbg@osg.samsung.com>".into(),
create_instance: FileSink::new_boxed, rank: 256 + 100,
protocols: vec!["file".into()], create_instance: FileSink::new_boxed,
}); protocols: vec!["file".into()],
},
);
true true
} }
plugin_define!(b"rsfile\0", plugin_define!(
b"Rust File Plugin\0", b"rsfile\0",
plugin_init, b"Rust File Plugin\0",
b"1.0\0", plugin_init,
b"MIT/X11\0", b"1.0\0",
b"rsfile\0", b"MIT/X11\0",
b"rsfile\0", b"rsfile\0",
b"https://github.com/sdroege/rsplugin\0", b"rsfile\0",
b"2016-12-08\0"); b"https://github.com/sdroege/rsplugin\0",
b"2016-12-08\0"
);

View file

@ -7,7 +7,7 @@
// except according to those terms. // except according to those terms.
use std::cmp; use std::cmp;
use std::io::{Write, Cursor}; use std::io::{Cursor, Write};
use nom; use nom;
use nom::IResult; use nom::IResult;
@ -87,17 +87,18 @@ struct AudioFormat {
// Ignores bitrate // Ignores bitrate
impl PartialEq for AudioFormat { impl PartialEq for AudioFormat {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.format.eq(&other.format) && self.rate.eq(&other.rate) && self.format.eq(&other.format) && self.rate.eq(&other.rate) && self.width.eq(&other.width) &&
self.width.eq(&other.width) && self.channels.eq(&other.channels) && self.channels.eq(&other.channels) &&
self.aac_sequence_header.eq(&other.aac_sequence_header) self.aac_sequence_header.eq(&other.aac_sequence_header)
} }
} }
impl AudioFormat { impl AudioFormat {
fn new(data_header: &flavors::AudioDataHeader, fn new(
metadata: &Option<Metadata>, data_header: &flavors::AudioDataHeader,
aac_sequence_header: &Option<GstRc<Buffer>>) metadata: &Option<Metadata>,
-> AudioFormat { aac_sequence_header: &Option<GstRc<Buffer>>,
) -> AudioFormat {
let numeric_rate = match (data_header.sound_format, data_header.sound_rate) { let numeric_rate = match (data_header.sound_format, data_header.sound_rate) {
(flavors::SoundFormat::NELLYMOSER_16KHZ_MONO, _) => 16000, (flavors::SoundFormat::NELLYMOSER_16KHZ_MONO, _) => 16000,
(flavors::SoundFormat::NELLYMOSER_8KHZ_MONO, _) => 8000, (flavors::SoundFormat::NELLYMOSER_8KHZ_MONO, _) => 8000,
@ -146,47 +147,52 @@ impl AudioFormat {
fn to_caps(&self) -> Option<GstRc<Caps>> { fn to_caps(&self) -> Option<GstRc<Caps>> {
let mut caps = match self.format { let mut caps = match self.format {
flavors::SoundFormat::MP3 | flavors::SoundFormat::MP3 | flavors::SoundFormat::MP3_8KHZ => Some(Caps::new_simple(
flavors::SoundFormat::MP3_8KHZ => { "audio/mpeg",
Some(Caps::new_simple("audio/mpeg", &[("mpegversion", 1i32.into()), ("layer", 3i32.into())],
&[("mpegversion", 1i32.into()), ("layer", 3i32.into())])) )),
} flavors::SoundFormat::PCM_NE | flavors::SoundFormat::PCM_LE => {
flavors::SoundFormat::PCM_NE |
flavors::SoundFormat::PCM_LE => {
if self.rate != 0 && self.channels != 0 { if self.rate != 0 && self.channels != 0 {
// Assume little-endian for "PCM_NE", it's probably more common and we have no // 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 // way to know what the endianness of the system creating the stream was
Some(Caps::new_simple("audio/x-raw", Some(Caps::new_simple(
&[("layout", "interleaved".into()), "audio/x-raw",
("format", &[
if self.width == 8 { ("layout", "interleaved".into()),
"U8".into() (
} else { "format",
"S16LE".into() if self.width == 8 {
})])) "U8".into()
} else {
"S16LE".into()
},
),
],
))
} else { } else {
None None
} }
} }
flavors::SoundFormat::ADPCM => { flavors::SoundFormat::ADPCM => Some(Caps::new_simple(
Some(Caps::new_simple("audio/x-adpcm", &[("layout", "swf".into())])) "audio/x-adpcm",
} &[("layout", "swf".into())],
)),
flavors::SoundFormat::NELLYMOSER_16KHZ_MONO | flavors::SoundFormat::NELLYMOSER_16KHZ_MONO |
flavors::SoundFormat::NELLYMOSER_8KHZ_MONO | flavors::SoundFormat::NELLYMOSER_8KHZ_MONO |
flavors::SoundFormat::NELLYMOSER => Some(Caps::new_simple("audio/x-nellymoser", &[])), flavors::SoundFormat::NELLYMOSER => Some(Caps::new_simple("audio/x-nellymoser", &[])),
flavors::SoundFormat::PCM_ALAW => Some(Caps::new_simple("audio/x-alaw", &[])), flavors::SoundFormat::PCM_ALAW => Some(Caps::new_simple("audio/x-alaw", &[])),
flavors::SoundFormat::PCM_ULAW => Some(Caps::new_simple("audio/x-mulaw", &[])), flavors::SoundFormat::PCM_ULAW => Some(Caps::new_simple("audio/x-mulaw", &[])),
flavors::SoundFormat::AAC => { flavors::SoundFormat::AAC => self.aac_sequence_header.as_ref().map(|header| {
self.aac_sequence_header Caps::new_simple(
.as_ref() "audio/mpeg",
.map(|header| { &[
Caps::new_simple("audio/mpeg", ("mpegversion", 4i32.into()),
&[("mpegversion", 4i32.into()), ("framed", true.into()),
("framed", true.into()), ("stream-format", "raw".into()),
("stream-format", "raw".into()), ("codec_data", header.as_ref().into()),
("codec_data", header.as_ref().into())]) ],
}) )
} }),
flavors::SoundFormat::SPEEX => { flavors::SoundFormat::SPEEX => {
let header = { let header = {
let header_size = 80; let header_size = 80;
@ -227,9 +233,10 @@ impl AudioFormat {
}; };
let comment = Buffer::from_vec(comment).unwrap(); let comment = Buffer::from_vec(comment).unwrap();
Some(Caps::new_simple("audio/x-speex", Some(Caps::new_simple(
&[("streamheader", "audio/x-speex",
vec![header.into(), comment.into()].into())])) &[("streamheader", vec![header.into(), comment.into()].into())],
))
} }
flavors::SoundFormat::DEVICE_SPECIFIC => { flavors::SoundFormat::DEVICE_SPECIFIC => {
// Nobody knows // Nobody knows
@ -238,20 +245,18 @@ impl AudioFormat {
}; };
if self.rate != 0 { if self.rate != 0 {
caps.as_mut() caps.as_mut().map(|c| {
.map(|c| { c.get_mut()
c.get_mut() .unwrap()
.unwrap() .set_simple(&[("rate", (self.rate as i32).into())])
.set_simple(&[("rate", (self.rate as i32).into())]) });
});
} }
if self.channels != 0 { if self.channels != 0 {
caps.as_mut() caps.as_mut().map(|c| {
.map(|c| { c.get_mut()
c.get_mut() .unwrap()
.unwrap() .set_simple(&[("channels", (self.channels as i32).into())])
.set_simple(&[("channels", (self.channels as i32).into())]) });
});
} }
caps caps
@ -270,17 +275,16 @@ struct VideoFormat {
} }
impl VideoFormat { impl VideoFormat {
fn new(data_header: &flavors::VideoDataHeader, fn new(
metadata: &Option<Metadata>, data_header: &flavors::VideoDataHeader,
avc_sequence_header: &Option<GstRc<Buffer>>) metadata: &Option<Metadata>,
-> VideoFormat { avc_sequence_header: &Option<GstRc<Buffer>>,
) -> VideoFormat {
VideoFormat { VideoFormat {
format: data_header.codec_id, format: data_header.codec_id,
width: metadata.as_ref().and_then(|m| m.video_width), width: metadata.as_ref().and_then(|m| m.video_width),
height: metadata.as_ref().and_then(|m| m.video_height), height: metadata.as_ref().and_then(|m| m.video_height),
pixel_aspect_ratio: metadata pixel_aspect_ratio: metadata.as_ref().and_then(|m| m.video_pixel_aspect_ratio),
.as_ref()
.and_then(|m| m.video_pixel_aspect_ratio),
framerate: metadata.as_ref().and_then(|m| m.video_framerate), framerate: metadata.as_ref().and_then(|m| m.video_framerate),
bitrate: metadata.as_ref().and_then(|m| m.video_bitrate), bitrate: metadata.as_ref().and_then(|m| m.video_bitrate),
avc_sequence_header: avc_sequence_header.clone(), avc_sequence_header: avc_sequence_header.clone(),
@ -324,28 +328,28 @@ impl VideoFormat {
fn to_caps(&self) -> Option<GstRc<Caps>> { fn to_caps(&self) -> Option<GstRc<Caps>> {
let mut caps = match self.format { let mut caps = match self.format {
flavors::CodecId::SORENSON_H263 => { flavors::CodecId::SORENSON_H263 => Some(Caps::new_simple(
Some(Caps::new_simple("video/x-flash-video", &[("flvversion", 1i32.into())])) "video/x-flash-video",
} &[("flvversion", 1i32.into())],
)),
flavors::CodecId::SCREEN => Some(Caps::new_simple("video/x-flash-screen", &[])), flavors::CodecId::SCREEN => Some(Caps::new_simple("video/x-flash-screen", &[])),
flavors::CodecId::VP6 => Some(Caps::new_simple("video/x-vp6-flash", &[])), 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::VP6A => Some(Caps::new_simple("video/x-vp6-flash-alpha", &[])),
flavors::CodecId::SCREEN2 => Some(Caps::new_simple("video/x-flash-screen2", &[])), flavors::CodecId::SCREEN2 => Some(Caps::new_simple("video/x-flash-screen2", &[])),
flavors::CodecId::H264 => { flavors::CodecId::H264 => self.avc_sequence_header.as_ref().map(|header| {
self.avc_sequence_header Caps::new_simple(
.as_ref() "video/x-h264",
.map(|header| { &[
Caps::new_simple("video/x-h264", ("stream-format", "avc".into()),
&[("stream-format", "avc".into()), ("codec_data", header.as_ref().into()),
("codec_data", header.as_ref().into())]) ],
}) )
} }),
flavors::CodecId::H263 => Some(Caps::new_simple("video/x-h263", &[])), flavors::CodecId::H263 => Some(Caps::new_simple("video/x-h263", &[])),
flavors::CodecId::MPEG4Part2 => { flavors::CodecId::MPEG4Part2 => Some(Caps::new_simple(
Some(Caps::new_simple("video/x-h263", "video/x-h263",
&[("mpegversion", 4i32.into()), &[("mpegversion", 4i32.into()), ("systemstream", false.into())],
("systemstream", false.into())])) )),
}
flavors::CodecId::JPEG => { flavors::CodecId::JPEG => {
// Unused according to spec // Unused according to spec
None None
@ -353,34 +357,31 @@ impl VideoFormat {
}; };
if let (Some(width), Some(height)) = (self.width, self.height) { if let (Some(width), Some(height)) = (self.width, self.height) {
caps.as_mut() caps.as_mut().map(|c| {
.map(|c| { c.get_mut().unwrap().set_simple(&[
c.get_mut() ("width", (width as i32).into()),
.unwrap() ("height", (height as i32).into()),
.set_simple(&[("width", (width as i32).into()), ])
("height", (height as i32).into())]) });
});
} }
if let Some(par) = self.pixel_aspect_ratio { if let Some(par) = self.pixel_aspect_ratio {
if *par.numer() != 0 && par.numer() != par.denom() { if *par.numer() != 0 && par.numer() != par.denom() {
caps.as_mut() caps.as_mut().map(|c| {
.map(|c| { c.get_mut()
c.get_mut() .unwrap()
.unwrap() .set_simple(&[("pixel-aspect-ratio", par.into())])
.set_simple(&[("pixel-aspect-ratio", par.into())]) });
});
} }
} }
if let Some(fps) = self.framerate { if let Some(fps) = self.framerate {
if *fps.numer() != 0 { if *fps.numer() != 0 {
caps.as_mut() caps.as_mut().map(|c| {
.map(|c| { c.get_mut()
c.get_mut() .unwrap()
.unwrap() .set_simple(&[("framerate", fps.into())])
.set_simple(&[("framerate", fps.into())]) });
});
} }
} }
@ -392,10 +393,10 @@ impl VideoFormat {
impl PartialEq for VideoFormat { impl PartialEq for VideoFormat {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.format.eq(&other.format) && self.width.eq(&other.width) && self.format.eq(&other.format) && self.width.eq(&other.width) &&
self.height.eq(&other.height) && self.height.eq(&other.height) &&
self.pixel_aspect_ratio.eq(&other.pixel_aspect_ratio) && self.pixel_aspect_ratio.eq(&other.pixel_aspect_ratio) &&
self.framerate.eq(&other.framerate) && self.framerate.eq(&other.framerate) &&
self.avc_sequence_header.eq(&other.avc_sequence_header) self.avc_sequence_header.eq(&other.avc_sequence_header)
} }
} }
@ -509,11 +510,10 @@ pub struct FlvDemux {
impl FlvDemux { impl FlvDemux {
pub fn new(element: Element) -> FlvDemux { pub fn new(element: Element) -> FlvDemux {
FlvDemux { FlvDemux {
logger: Logger::root(GstDebugDrain::new(Some(&element), logger: Logger::root(
"rsflvdemux", GstDebugDrain::new(Some(&element), "rsflvdemux", 0, "Rust FLV demuxer"),
0, o!(),
"Rust FLV demuxer"), ),
o!()),
state: State::Stopped, state: State::Stopped,
adapter: Adapter::new(), adapter: Adapter::new(),
streaming_state: None, streaming_state: None,
@ -524,9 +524,10 @@ impl FlvDemux {
Box::new(FlvDemux::new(element)) Box::new(FlvDemux::new(element))
} }
fn handle_script_tag(&mut self, fn handle_script_tag(
tag_header: &flavors::TagHeader) &mut self,
-> Result<HandleBufferResult, FlowError> { tag_header: &flavors::TagHeader,
) -> Result<HandleBufferResult, FlowError> {
if self.adapter.get_available() < (15 + tag_header.data_size) as usize { if self.adapter.get_available() < (15 + tag_header.data_size) as usize {
return Ok(HandleBufferResult::NeedMoreData); return Ok(HandleBufferResult::NeedMoreData);
} }
@ -564,14 +565,14 @@ impl FlvDemux {
let mut streams = Vec::new(); let mut streams = Vec::new();
if audio_changed { if audio_changed {
if let Some(caps) = if let Some(caps) = streaming_state.audio.as_ref().and_then(|a| a.to_caps())
streaming_state.audio.as_ref().and_then(|a| a.to_caps()) { {
streams.push(Stream::new(AUDIO_STREAM_ID, caps, String::from("audio"))); streams.push(Stream::new(AUDIO_STREAM_ID, caps, String::from("audio")));
} }
} }
if video_changed { if video_changed {
if let Some(caps) = if let Some(caps) = streaming_state.video.as_ref().and_then(|v| v.to_caps())
streaming_state.video.as_ref().and_then(|v| v.to_caps()) { {
streams.push(Stream::new(VIDEO_STREAM_ID, caps, String::from("video"))); streams.push(Stream::new(VIDEO_STREAM_ID, caps, String::from("video")));
} }
} }
@ -582,8 +583,7 @@ impl FlvDemux {
IResult::Done(_, ref script_data) => { IResult::Done(_, ref script_data) => {
trace!(self.logger, "Got script tag: {:?}", script_data); trace!(self.logger, "Got script tag: {:?}", script_data);
} }
IResult::Error(_) | IResult::Error(_) | IResult::Incomplete(_) => {
IResult::Incomplete(_) => {
// ignore // ignore
} }
} }
@ -591,17 +591,20 @@ impl FlvDemux {
Ok(HandleBufferResult::Again) Ok(HandleBufferResult::Again)
} }
fn update_audio_stream(&mut self, fn update_audio_stream(
data_header: &flavors::AudioDataHeader) &mut self,
-> Result<HandleBufferResult, FlowError> { data_header: &flavors::AudioDataHeader,
) -> Result<HandleBufferResult, FlowError> {
let logger = self.logger.clone(); let logger = self.logger.clone();
trace!(logger, "Got audio data header: {:?}", data_header); trace!(logger, "Got audio data header: {:?}", data_header);
let streaming_state = self.streaming_state.as_mut().unwrap(); let streaming_state = self.streaming_state.as_mut().unwrap();
let new_audio_format = AudioFormat::new(data_header, let new_audio_format = AudioFormat::new(
&streaming_state.metadata, data_header,
&streaming_state.aac_sequence_header); &streaming_state.metadata,
&streaming_state.aac_sequence_header,
);
if streaming_state.audio.as_ref() != Some(&new_audio_format) { if streaming_state.audio.as_ref() != Some(&new_audio_format) {
debug!(logger, "Got new audio format: {:?}", new_audio_format); debug!(logger, "Got new audio format: {:?}", new_audio_format);
@ -622,8 +625,9 @@ impl FlvDemux {
} }
if !streaming_state.got_all_streams && streaming_state.audio != None && if !streaming_state.got_all_streams && streaming_state.audio != None &&
(streaming_state.expect_video && streaming_state.video != None || (streaming_state.expect_video && streaming_state.video != None ||
!streaming_state.expect_video) { !streaming_state.expect_video)
{
streaming_state.got_all_streams = true; streaming_state.got_all_streams = true;
return Ok(HandleBufferResult::HaveAllStreams); return Ok(HandleBufferResult::HaveAllStreams);
} }
@ -631,10 +635,11 @@ impl FlvDemux {
Ok(HandleBufferResult::Again) Ok(HandleBufferResult::Again)
} }
fn handle_audio_tag(&mut self, fn handle_audio_tag(
tag_header: &flavors::TagHeader, &mut self,
data_header: &flavors::AudioDataHeader) tag_header: &flavors::TagHeader,
-> Result<HandleBufferResult, FlowError> { data_header: &flavors::AudioDataHeader,
) -> Result<HandleBufferResult, FlowError> {
let res = self.update_audio_stream(data_header); let res = self.update_audio_stream(data_header);
match res { match res {
Ok(HandleBufferResult::Again) => (), Ok(HandleBufferResult::Again) => (),
@ -652,17 +657,18 @@ impl FlvDemux {
self.adapter self.adapter
.flush(15 + tag_header.data_size as usize) .flush(15 + tag_header.data_size as usize)
.unwrap(); .unwrap();
warn!(self.logger, warn!(
"Too small packet for AAC packet header {}", self.logger,
15 + tag_header.data_size); "Too small packet for AAC packet header {}",
15 + tag_header.data_size
);
return Ok(HandleBufferResult::Again); return Ok(HandleBufferResult::Again);
} }
let mut data = [0u8; 17]; let mut data = [0u8; 17];
self.adapter.peek_into(&mut data).unwrap(); self.adapter.peek_into(&mut data).unwrap();
match flavors::aac_audio_packet_header(&data[16..]) { match flavors::aac_audio_packet_header(&data[16..]) {
IResult::Error(_) | IResult::Error(_) | IResult::Incomplete(_) => {
IResult::Incomplete(_) => {
unimplemented!(); unimplemented!();
} }
IResult::Done(_, header) => { IResult::Done(_, header) => {
@ -673,10 +679,12 @@ impl FlvDemux {
let buffer = self.adapter let buffer = self.adapter
.get_buffer((tag_header.data_size - 1 - 1) as usize) .get_buffer((tag_header.data_size - 1 - 1) as usize)
.unwrap(); .unwrap();
debug!(self.logger, debug!(
"Got AAC sequence header {:?} of size {}", self.logger,
buffer, "Got AAC sequence header {:?} of size {}",
tag_header.data_size - 1 - 1); buffer,
tag_header.data_size - 1 - 1
);
let streaming_state = self.streaming_state.as_mut().unwrap(); let streaming_state = self.streaming_state.as_mut().unwrap();
streaming_state.aac_sequence_header = Some(buffer); streaming_state.aac_sequence_header = Some(buffer);
@ -731,26 +739,31 @@ impl FlvDemux {
buffer.set_pts(Some((tag_header.timestamp as u64) * 1000 * 1000)); buffer.set_pts(Some((tag_header.timestamp as u64) * 1000 * 1000));
} }
trace!(self.logger, trace!(
"Outputting audio buffer {:?} for tag {:?} of size {}", self.logger,
buffer, "Outputting audio buffer {:?} for tag {:?} of size {}",
tag_header, buffer,
tag_header.data_size - 1); tag_header,
tag_header.data_size - 1
);
Ok(HandleBufferResult::BufferForStream(AUDIO_STREAM_ID, buffer)) Ok(HandleBufferResult::BufferForStream(AUDIO_STREAM_ID, buffer))
} }
fn update_video_stream(&mut self, fn update_video_stream(
data_header: &flavors::VideoDataHeader) &mut self,
-> Result<HandleBufferResult, FlowError> { data_header: &flavors::VideoDataHeader,
) -> Result<HandleBufferResult, FlowError> {
let logger = self.logger.clone(); let logger = self.logger.clone();
trace!(logger, "Got video data header: {:?}", data_header); trace!(logger, "Got video data header: {:?}", data_header);
let streaming_state = self.streaming_state.as_mut().unwrap(); let streaming_state = self.streaming_state.as_mut().unwrap();
let new_video_format = VideoFormat::new(data_header, let new_video_format = VideoFormat::new(
&streaming_state.metadata, data_header,
&streaming_state.avc_sequence_header); &streaming_state.metadata,
&streaming_state.avc_sequence_header,
);
if streaming_state.video.as_ref() != Some(&new_video_format) { if streaming_state.video.as_ref() != Some(&new_video_format) {
debug!(logger, "Got new video format: {:?}", new_video_format); debug!(logger, "Got new video format: {:?}", new_video_format);
@ -772,8 +785,9 @@ impl FlvDemux {
} }
if !streaming_state.got_all_streams && streaming_state.video != None && if !streaming_state.got_all_streams && streaming_state.video != None &&
(streaming_state.expect_audio && streaming_state.audio != None || (streaming_state.expect_audio && streaming_state.audio != None ||
!streaming_state.expect_audio) { !streaming_state.expect_audio)
{
streaming_state.got_all_streams = true; streaming_state.got_all_streams = true;
return Ok(HandleBufferResult::HaveAllStreams); return Ok(HandleBufferResult::HaveAllStreams);
} }
@ -781,10 +795,11 @@ impl FlvDemux {
Ok(HandleBufferResult::Again) Ok(HandleBufferResult::Again)
} }
fn handle_video_tag(&mut self, fn handle_video_tag(
tag_header: &flavors::TagHeader, &mut self,
data_header: &flavors::VideoDataHeader) tag_header: &flavors::TagHeader,
-> Result<HandleBufferResult, FlowError> { data_header: &flavors::VideoDataHeader,
) -> Result<HandleBufferResult, FlowError> {
let res = self.update_video_stream(data_header); let res = self.update_video_stream(data_header);
match res { match res {
Ok(HandleBufferResult::Again) => (), Ok(HandleBufferResult::Again) => (),
@ -804,17 +819,18 @@ impl FlvDemux {
self.adapter self.adapter
.flush(15 + tag_header.data_size as usize) .flush(15 + tag_header.data_size as usize)
.unwrap(); .unwrap();
warn!(self.logger, warn!(
"Too small packet for AVC packet header {}", self.logger,
15 + tag_header.data_size); "Too small packet for AVC packet header {}",
15 + tag_header.data_size
);
return Ok(HandleBufferResult::Again); return Ok(HandleBufferResult::Again);
} }
let mut data = [0u8; 20]; let mut data = [0u8; 20];
self.adapter.peek_into(&mut data).unwrap(); self.adapter.peek_into(&mut data).unwrap();
match flavors::avc_video_packet_header(&data[16..]) { match flavors::avc_video_packet_header(&data[16..]) {
IResult::Error(_) | IResult::Error(_) | IResult::Incomplete(_) => {
IResult::Incomplete(_) => {
unimplemented!(); unimplemented!();
} }
IResult::Done(_, header) => { IResult::Done(_, header) => {
@ -825,10 +841,12 @@ impl FlvDemux {
let buffer = self.adapter let buffer = self.adapter
.get_buffer((tag_header.data_size - 1 - 4) as usize) .get_buffer((tag_header.data_size - 1 - 4) as usize)
.unwrap(); .unwrap();
debug!(self.logger, debug!(
"Got AVC sequence header {:?} of size {}", self.logger,
buffer, "Got AVC sequence header {:?} of size {}",
tag_header.data_size - 1 - 4); buffer,
tag_header.data_size - 1 - 4
);
let streaming_state = self.streaming_state.as_mut().unwrap(); let streaming_state = self.streaming_state.as_mut().unwrap();
streaming_state.avc_sequence_header = Some(buffer); streaming_state.avc_sequence_header = Some(buffer);
@ -864,8 +882,7 @@ impl FlvDemux {
self.adapter.flush(16).unwrap(); self.adapter.flush(16).unwrap();
let offset = match video.format { let offset = match video.format {
flavors::CodecId::VP6 | flavors::CodecId::VP6 | flavors::CodecId::VP6A => 1,
flavors::CodecId::VP6A => 1,
flavors::CodecId::H264 => 4, flavors::CodecId::H264 => 4,
_ => 0, _ => 0,
}; };
@ -905,12 +922,14 @@ impl FlvDemux {
buffer.set_pts(Some(pts * 1000 * 1000)); buffer.set_pts(Some(pts * 1000 * 1000));
} }
trace!(self.logger, trace!(
"Outputting video buffer {:?} for tag {:?} of size {}, keyframe: {}", self.logger,
buffer, "Outputting video buffer {:?} for tag {:?} of size {}, keyframe: {}",
tag_header, buffer,
tag_header.data_size - 1 - offset, tag_header,
is_keyframe); tag_header.data_size - 1 - offset,
is_keyframe
);
Ok(HandleBufferResult::BufferForStream(VIDEO_STREAM_ID, buffer)) Ok(HandleBufferResult::BufferForStream(VIDEO_STREAM_ID, buffer))
} }
@ -924,8 +943,7 @@ impl FlvDemux {
self.adapter.peek_into(&mut data).unwrap(); self.adapter.peek_into(&mut data).unwrap();
match flavors::header(&data) { match flavors::header(&data) {
IResult::Error(_) | IResult::Error(_) | IResult::Incomplete(_) => {
IResult::Incomplete(_) => {
// fall through // fall through
} }
IResult::Done(_, ref header) => { IResult::Done(_, ref header) => {
@ -964,7 +982,9 @@ impl FlvDemux {
Ok(HandleBufferResult::Again) Ok(HandleBufferResult::Again)
} }
State::Skipping { ref mut skip_left, .. } => { State::Skipping {
ref mut skip_left, ..
} => {
let skip = cmp::min(self.adapter.get_available(), *skip_left as usize); let skip = cmp::min(self.adapter.get_available(), *skip_left as usize);
self.adapter.flush(skip).unwrap(); self.adapter.flush(skip).unwrap();
*skip_left -= skip as u32; *skip_left -= skip as u32;
@ -980,8 +1000,7 @@ impl FlvDemux {
self.adapter.peek_into(&mut data).unwrap(); self.adapter.peek_into(&mut data).unwrap();
match nom::be_u32(&data[0..4]) { match nom::be_u32(&data[0..4]) {
IResult::Error(_) | IResult::Error(_) | IResult::Incomplete(_) => {
IResult::Incomplete(_) => {
unimplemented!(); unimplemented!();
} }
IResult::Done(_, previous_size) => { IResult::Done(_, previous_size) => {
@ -991,8 +1010,7 @@ impl FlvDemux {
} }
let tag_header = match flavors::tag_header(&data[4..]) { let tag_header = match flavors::tag_header(&data[4..]) {
IResult::Error(_) | IResult::Error(_) | IResult::Incomplete(_) => {
IResult::Incomplete(_) => {
unimplemented!(); unimplemented!();
} }
IResult::Done(_, tag_header) => tag_header, IResult::Done(_, tag_header) => tag_header,
@ -1008,8 +1026,7 @@ impl FlvDemux {
trace!(self.logger, "Found audio tag"); trace!(self.logger, "Found audio tag");
let data_header = match flavors::audio_data_header(&data[15..]) { let data_header = match flavors::audio_data_header(&data[15..]) {
IResult::Error(_) | IResult::Error(_) | IResult::Incomplete(_) => {
IResult::Incomplete(_) => {
unimplemented!(); unimplemented!();
} }
IResult::Done(_, data_header) => data_header, IResult::Done(_, data_header) => data_header,
@ -1021,8 +1038,7 @@ impl FlvDemux {
trace!(self.logger, "Found video tag"); trace!(self.logger, "Found video tag");
let data_header = match flavors::video_data_header(&data[15..]) { let data_header = match flavors::video_data_header(&data[15..]) {
IResult::Error(_) | IResult::Error(_) | IResult::Incomplete(_) => {
IResult::Incomplete(_) => {
unimplemented!(); unimplemented!();
} }
IResult::Done(_, data_header) => data_header, IResult::Done(_, data_header) => data_header,
@ -1056,10 +1072,11 @@ impl FlvDemux {
} }
impl Demuxer for FlvDemux { impl Demuxer for FlvDemux {
fn start(&mut self, fn start(
_upstream_size: Option<u64>, &mut self,
_random_access: bool) _upstream_size: Option<u64>,
-> Result<(), ErrorMessage> { _random_access: bool,
) -> Result<(), ErrorMessage> {
self.state = State::NeedHeader; self.state = State::NeedHeader;
Ok(()) Ok(())
@ -1077,9 +1094,10 @@ impl Demuxer for FlvDemux {
unimplemented!(); unimplemented!();
} }
fn handle_buffer(&mut self, fn handle_buffer(
buffer: Option<GstRc<Buffer>>) &mut self,
-> Result<HandleBufferResult, FlowError> { buffer: Option<GstRc<Buffer>>,
) -> Result<HandleBufferResult, FlowError> {
if let Some(buffer) = buffer { if let Some(buffer) = buffer {
self.adapter.push(buffer); self.adapter.push(buffer);
} }
@ -1105,8 +1123,11 @@ impl Demuxer for FlvDemux {
} }
fn get_duration(&self) -> Option<u64> { fn get_duration(&self) -> Option<u64> {
if let Some(StreamingState { metadata: Some(Metadata { duration, .. }), .. }) = if let Some(StreamingState {
self.streaming_state { metadata: Some(Metadata { duration, .. }),
..
}) = self.streaming_state
{
return duration; return duration;
} }

View file

@ -6,7 +6,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![crate_type="cdylib"] #![crate_type = "cdylib"]
extern crate url; extern crate url;
#[macro_use] #[macro_use]
@ -26,28 +26,32 @@ mod flvdemux;
use flvdemux::FlvDemux; use flvdemux::FlvDemux;
fn plugin_init(plugin: &Plugin) -> bool { fn plugin_init(plugin: &Plugin) -> bool {
demuxer_register(plugin, demuxer_register(
&DemuxerInfo { plugin,
name: "rsflvdemux", &DemuxerInfo {
long_name: "FLV Demuxer", name: "rsflvdemux",
description: "Demuxes FLV Streams", long_name: "FLV Demuxer",
classification: "Codec/Demuxer", description: "Demuxes FLV Streams",
author: "Sebastian Dröge <sebastian@centricular.com>", classification: "Codec/Demuxer",
rank: 256 + 100, author: "Sebastian Dröge <sebastian@centricular.com>",
create_instance: FlvDemux::new_boxed, rank: 256 + 100,
input_caps: &Caps::new_simple("video/x-flv", &[]), create_instance: FlvDemux::new_boxed,
output_caps: &Caps::new_any(), input_caps: &Caps::new_simple("video/x-flv", &[]),
}); output_caps: &Caps::new_any(),
},
);
true true
} }
plugin_define!(b"rsflv\0", plugin_define!(
b"Rust FLV Plugin\0", b"rsflv\0",
plugin_init, b"Rust FLV Plugin\0",
b"1.0\0", plugin_init,
b"MIT/X11\0", b"1.0\0",
b"rsflv\0", b"MIT/X11\0",
b"rsflv\0", b"rsflv\0",
b"https://github.com/sdroege/rsplugin\0", b"rsflv\0",
b"2016-12-08\0"); b"https://github.com/sdroege/rsplugin\0",
b"2016-12-08\0"
);

View file

@ -10,8 +10,8 @@ use std::u64;
use std::io::Read; use std::io::Read;
use url::Url; use url::Url;
use reqwest::{Client, Response}; use reqwest::{Client, Response};
use reqwest::header::{ContentLength, ContentRange, ContentRangeSpec, Range, ByteRangeSpec, use reqwest::header::{AcceptRanges, ByteRangeSpec, ContentLength, ContentRange, ContentRangeSpec,
AcceptRanges, RangeUnit}; Range, RangeUnit};
use gst_plugin::error::*; use gst_plugin::error::*;
use gst_plugin::source::*; use gst_plugin::source::*;
@ -46,11 +46,10 @@ impl HttpSrc {
pub fn new(element: Element) -> HttpSrc { pub fn new(element: Element) -> HttpSrc {
HttpSrc { HttpSrc {
streaming_state: StreamingState::Stopped, streaming_state: StreamingState::Stopped,
logger: Logger::root(GstDebugDrain::new(Some(&element), logger: Logger::root(
"rshttpsink", GstDebugDrain::new(Some(&element), "rshttpsink", 0, "Rust http sink"),
0, o!(),
"Rust http sink"), ),
o!()),
client: Client::new().unwrap(), client: Client::new().unwrap(),
} }
} }
@ -59,11 +58,12 @@ impl HttpSrc {
Box::new(HttpSrc::new(element)) Box::new(HttpSrc::new(element))
} }
fn do_request(&self, fn do_request(
uri: Url, &self,
start: u64, uri: Url,
stop: Option<u64>) start: u64,
-> Result<StreamingState, ErrorMessage> { stop: Option<u64>,
) -> Result<StreamingState, ErrorMessage> {
let mut req = self.client.get(uri.clone()).unwrap(); let mut req = self.client.get(uri.clone()).unwrap();
match (start != 0, stop) { match (start != 0, stop) {
@ -78,18 +78,20 @@ impl HttpSrc {
debug!(self.logger, "Doing new request {:?}", req); debug!(self.logger, "Doing new request {:?}", req);
let response = let response = try!(req.send().or_else(|err| {
try!(req.send() error!(self.logger, "Request failed: {:?}", err);
.or_else(|err| { Err(error_msg!(
error!(self.logger, "Request failed: {:?}", err); SourceError::ReadFailed,
Err(error_msg!(SourceError::ReadFailed, ["Failed to fetch {}: {}", uri, err.to_string()]
["Failed to fetch {}: {}", uri, err.to_string()])) ))
})); }));
if !response.status().is_success() { if !response.status().is_success() {
error!(self.logger, "Request status failed: {:?}", response); error!(self.logger, "Request status failed: {:?}", response);
return Err(error_msg!(SourceError::ReadFailed, return Err(error_msg!(
["Failed to fetch {}: {}", uri, response.status()])); SourceError::ReadFailed,
["Failed to fetch {}: {}", uri, response.status()]
));
} }
let size = response let size = response
@ -97,8 +99,7 @@ impl HttpSrc {
.get() .get()
.map(|&ContentLength(cl)| cl + start); .map(|&ContentLength(cl)| cl + start);
let accept_byte_ranges = if let Some(&AcceptRanges(ref ranges)) = let accept_byte_ranges = if let Some(&AcceptRanges(ref ranges)) = response.headers().get() {
response.headers().get() {
ranges.iter().any(|u| *u == RangeUnit::Bytes) ranges.iter().any(|u| *u == RangeUnit::Bytes)
} else { } else {
false false
@ -106,37 +107,45 @@ impl HttpSrc {
let seekable = size.is_some() && accept_byte_ranges; let seekable = size.is_some() && accept_byte_ranges;
let position = if let Some(&ContentRange(ContentRangeSpec::Bytes { let position = if let Some(
range: Some((range_start, _)), .. &ContentRange(ContentRangeSpec::Bytes {
})) = response.headers().get() { range: Some((range_start, _)),
..
}),
) = response.headers().get()
{
range_start range_start
} else { } else {
start start
}; };
if position != start { if position != start {
return Err(error_msg!(SourceError::SeekFailed, return Err(error_msg!(
["Failed to seek to {}: Got {}", start, position])); SourceError::SeekFailed,
["Failed to seek to {}: Got {}", start, position]
));
} }
debug!(self.logger, "Request successful: {:?}", response); debug!(self.logger, "Request successful: {:?}", response);
Ok(StreamingState::Started { Ok(StreamingState::Started {
uri: uri, uri: uri,
response: response, response: response,
seekable: seekable, seekable: seekable,
position: 0, position: 0,
size: size, size: size,
start: start, start: start,
stop: stop, stop: stop,
}) })
} }
} }
fn validate_uri(uri: &Url) -> Result<(), UriError> { fn validate_uri(uri: &Url) -> Result<(), UriError> {
if uri.scheme() != "http" && uri.scheme() != "https" { if uri.scheme() != "http" && uri.scheme() != "https" {
return Err(UriError::new(UriErrorKind::UnsupportedProtocol, return Err(UriError::new(
Some(format!("Unsupported URI '{}'", uri.as_str())))); UriErrorKind::UnsupportedProtocol,
Some(format!("Unsupported URI '{}'", uri.as_str())),
));
} }
Ok(()) Ok(())
@ -207,37 +216,38 @@ impl Source for HttpSrc {
.. ..
} => (response, position), } => (response, position),
StreamingState::Stopped => { StreamingState::Stopped => {
return Err(FlowError::Error(error_msg!(SourceError::Failure, ["Not started yet"]))); return Err(FlowError::Error(
error_msg!(SourceError::Failure, ["Not started yet"]),
));
} }
}; };
if *position != offset { if *position != offset {
return Err(FlowError::Error(error_msg!(SourceError::SeekFailed, return Err(FlowError::Error(error_msg!(
["Got unexpected offset {}, expected {}", SourceError::SeekFailed,
offset, ["Got unexpected offset {}, expected {}", offset, position]
position]))); )));
} }
let size = { let size = {
let mut map = match buffer.map_readwrite() { let mut map = match buffer.map_readwrite() {
None => { None => {
return Err(FlowError::Error(error_msg!(SourceError::Failure, return Err(FlowError::Error(
["Failed to map buffer"]))); error_msg!(SourceError::Failure, ["Failed to map buffer"]),
));
} }
Some(map) => map, Some(map) => map,
}; };
let data = map.as_mut_slice(); let data = map.as_mut_slice();
try!(response try!(response.read(data).or_else(|err| {
.read(data) error!(logger, "Failed to read: {:?}", err);
.or_else(|err| { Err(FlowError::Error(error_msg!(
error!(logger, "Failed to read: {:?}", err); SourceError::ReadFailed,
Err(FlowError::Error(error_msg!(SourceError::ReadFailed, ["Failed to read at {}: {}", offset, err.to_string()]
["Failed to read at {}: {}", )))
offset, }))
err.to_string()])))
}))
}; };
if size == 0 { if size == 0 {

View file

@ -6,7 +6,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![crate_type="cdylib"] #![crate_type = "cdylib"]
extern crate url; extern crate url;
#[macro_use] #[macro_use]
@ -23,28 +23,32 @@ mod httpsrc;
use httpsrc::HttpSrc; use httpsrc::HttpSrc;
fn plugin_init(plugin: &Plugin) -> bool { fn plugin_init(plugin: &Plugin) -> bool {
source_register(plugin, source_register(
SourceInfo { plugin,
name: "rshttpsrc".into(), SourceInfo {
long_name: "HTTP/HTTPS Source".into(), name: "rshttpsrc".into(),
description: "Reads HTTP/HTTPS streams".into(), long_name: "HTTP/HTTPS Source".into(),
classification: "Source/File".into(), description: "Reads HTTP/HTTPS streams".into(),
author: "Sebastian Dröge <sebastian@centricular.com>".into(), classification: "Source/File".into(),
rank: 256 + 100, author: "Sebastian Dröge <sebastian@centricular.com>".into(),
create_instance: HttpSrc::new_boxed, rank: 256 + 100,
protocols: vec!["http".into(), "https".into()], create_instance: HttpSrc::new_boxed,
push_only: true, protocols: vec!["http".into(), "https".into()],
}); push_only: true,
},
);
true true
} }
plugin_define!(b"rshttp\0", plugin_define!(
b"Rust HTTP Plugin\0", b"rshttp\0",
plugin_init, b"Rust HTTP Plugin\0",
b"1.0\0", plugin_init,
b"MIT/X11\0", b"1.0\0",
b"rshttp\0", b"MIT/X11\0",
b"rshttp\0", b"rshttp\0",
b"https://github.com/sdroege/rsplugin\0", b"rshttp\0",
b"2016-12-08\0"); b"https://github.com/sdroege/rsplugin\0",
b"2016-12-08\0"
);

View file

@ -50,11 +50,13 @@ impl Adapter {
let size = buffer.get_size(); let size = buffer.get_size();
self.size += size; self.size += size;
trace!(LOGGER, trace!(
"Storing {:?} of size {}, now have size {}", LOGGER,
buffer, "Storing {:?} of size {}, now have size {}",
size, buffer,
self.size); size,
self.size
);
self.deque self.deque
.push_back(Buffer::into_read_mapped_buffer(buffer).unwrap()); .push_back(Buffer::into_read_mapped_buffer(buffer).unwrap());
} }
@ -82,11 +84,13 @@ impl Adapter {
let data_item = item.as_slice(); let data_item = item.as_slice();
let to_copy = cmp::min(left, data_item.len() - skip); let to_copy = cmp::min(left, data_item.len() - skip);
trace!(LOGGER, trace!(
"Copying {} bytes from {:?}, {} more to go", LOGGER,
to_copy, "Copying {} bytes from {:?}, {} more to go",
item, to_copy,
left - to_copy); item,
left - to_copy
);
data[idx..idx + to_copy].copy_from_slice(&data_item[skip..skip + to_copy]); data[idx..idx + to_copy].copy_from_slice(&data_item[skip..skip + to_copy]);
skip = 0; skip = 0;
@ -103,10 +107,12 @@ impl Adapter {
let size = data.len(); let size = data.len();
if self.size < size { if self.size < size {
debug!(LOGGER, debug!(
"Peeking {} bytes into, not enough data: have {}", LOGGER,
size, "Peeking {} bytes into, not enough data: have {}",
self.size); size,
self.size
);
return Err(AdapterError::NotEnoughData); return Err(AdapterError::NotEnoughData);
} }
@ -121,10 +127,12 @@ impl Adapter {
pub fn peek(&mut self, size: usize) -> Result<&[u8], AdapterError> { pub fn peek(&mut self, size: usize) -> Result<&[u8], AdapterError> {
if self.size < size { if self.size < size {
debug!(LOGGER, debug!(
"Peeking {} bytes, not enough data: have {}", LOGGER,
size, "Peeking {} bytes, not enough data: have {}",
self.size); size,
self.size
);
return Err(AdapterError::NotEnoughData); return Err(AdapterError::NotEnoughData);
} }
@ -153,10 +161,12 @@ impl Adapter {
pub fn get_buffer(&mut self, size: usize) -> Result<GstRc<Buffer>, AdapterError> { pub fn get_buffer(&mut self, size: usize) -> Result<GstRc<Buffer>, AdapterError> {
if self.size < size { if self.size < size {
debug!(LOGGER, debug!(
"Get buffer of {} bytes, not enough data: have {}", LOGGER,
size, "Get buffer of {} bytes, not enough data: have {}",
self.size); size,
self.size
);
return Err(AdapterError::NotEnoughData); return Err(AdapterError::NotEnoughData);
} }
@ -164,18 +174,18 @@ impl Adapter {
return Ok(Buffer::new()); return Ok(Buffer::new());
} }
let sub = self.deque let sub = self.deque.front().and_then(
.front() |front| if front.get_size() - self.skip >= size {
.and_then(|front| if front.get_size() - self.skip >= size { trace!(LOGGER, "Get buffer of {} bytes, subbuffer of first", size);
trace!(LOGGER, "Get buffer of {} bytes, subbuffer of first", size); let new = front
let new = front .get_buffer()
.get_buffer() .copy_region(self.skip, Some(size))
.copy_region(self.skip, Some(size)) .unwrap();
.unwrap(); Some(new)
Some(new) } else {
} else { None
None },
}); );
if let Some(s) = sub { if let Some(s) = sub {
self.flush(size).unwrap(); self.flush(size).unwrap();
@ -195,10 +205,12 @@ impl Adapter {
pub fn flush(&mut self, size: usize) -> Result<(), AdapterError> { pub fn flush(&mut self, size: usize) -> Result<(), AdapterError> {
if self.size < size { if self.size < size {
debug!(LOGGER, debug!(
"Flush {} bytes, not enough data: have {}", LOGGER,
size, "Flush {} bytes, not enough data: have {}",
self.size); size,
self.size
);
return Err(AdapterError::NotEnoughData); return Err(AdapterError::NotEnoughData);
} }
@ -213,19 +225,23 @@ impl Adapter {
let front_size = self.deque.front().unwrap().get_size() - self.skip; let front_size = self.deque.front().unwrap().get_size() - self.skip;
if front_size <= left { if front_size <= left {
trace!(LOGGER, trace!(
"Flushing whole {:?}, {} more to go", LOGGER,
self.deque.front(), "Flushing whole {:?}, {} more to go",
left - front_size); self.deque.front(),
left - front_size
);
self.deque.pop_front(); self.deque.pop_front();
self.size -= front_size; self.size -= front_size;
self.skip = 0; self.skip = 0;
left -= front_size; left -= front_size;
} else { } else {
trace!(LOGGER, trace!(
"Flushing partial {:?}, {} more left", LOGGER,
self.deque.front(), "Flushing partial {:?}, {} more left",
front_size - left); self.deque.front(),
front_size - left
);
self.skip += left; self.skip += left;
self.size -= left; self.size -= left;
left = 0; left = 0;

View file

@ -24,7 +24,7 @@ pub struct Buffer(gst::GstBuffer);
#[derivative(Debug)] #[derivative(Debug)]
pub struct ReadBufferMap<'a> { pub struct ReadBufferMap<'a> {
buffer: &'a Buffer, buffer: &'a Buffer,
#[derivative(Debug="ignore")] #[derivative(Debug = "ignore")]
map_info: gst::GstMapInfo, map_info: gst::GstMapInfo,
} }
@ -32,7 +32,7 @@ pub struct ReadBufferMap<'a> {
#[derivative(Debug)] #[derivative(Debug)]
pub struct ReadWriteBufferMap<'a> { pub struct ReadWriteBufferMap<'a> {
buffer: &'a Buffer, buffer: &'a Buffer,
#[derivative(Debug="ignore")] #[derivative(Debug = "ignore")]
map_info: gst::GstMapInfo, map_info: gst::GstMapInfo,
} }
@ -40,7 +40,7 @@ pub struct ReadWriteBufferMap<'a> {
#[derivative(Debug)] #[derivative(Debug)]
pub struct ReadMappedBuffer { pub struct ReadMappedBuffer {
buffer: GstRc<Buffer>, buffer: GstRc<Buffer>,
#[derivative(Debug="ignore")] #[derivative(Debug = "ignore")]
map_info: gst::GstMapInfo, map_info: gst::GstMapInfo,
} }
@ -48,7 +48,7 @@ pub struct ReadMappedBuffer {
#[derivative(Debug)] #[derivative(Debug)]
pub struct ReadWriteMappedBuffer { pub struct ReadWriteMappedBuffer {
buffer: GstRc<Buffer>, buffer: GstRc<Buffer>,
#[derivative(Debug="ignore")] #[derivative(Debug = "ignore")]
map_info: gst::GstMapInfo, map_info: gst::GstMapInfo,
} }
@ -82,13 +82,15 @@ impl Buffer {
let size = vec.len(); let size = vec.len();
let data = vec.as_mut_ptr(); let data = vec.as_mut_ptr();
let user_data = Box::into_raw(vec); let user_data = Box::into_raw(vec);
gst::gst_buffer_new_wrapped_full(gst::GstMemoryFlags::empty(), gst::gst_buffer_new_wrapped_full(
data as glib::gpointer, gst::GstMemoryFlags::empty(),
maxsize, data as glib::gpointer,
0, maxsize,
size, 0,
user_data as glib::gpointer, size,
Some(Buffer::vec_drop)) user_data as glib::gpointer,
Some(Buffer::vec_drop),
)
}; };
if raw.is_null() { if raw.is_null() {
@ -101,15 +103,17 @@ impl Buffer {
pub fn map_read(&self) -> Option<ReadBufferMap> { pub fn map_read(&self) -> Option<ReadBufferMap> {
let mut map_info: gst::GstMapInfo = unsafe { mem::zeroed() }; let mut map_info: gst::GstMapInfo = unsafe { mem::zeroed() };
let res = unsafe { let res = unsafe {
gst::gst_buffer_map(self.as_mut_ptr() as *mut gst::GstBuffer, gst::gst_buffer_map(
&mut map_info, self.as_mut_ptr() as *mut gst::GstBuffer,
gst::GST_MAP_READ) &mut map_info,
gst::GST_MAP_READ,
)
}; };
if res == glib::GTRUE { if res == glib::GTRUE {
Some(ReadBufferMap { Some(ReadBufferMap {
buffer: self, buffer: self,
map_info: map_info, map_info: map_info,
}) })
} else { } else {
None None
} }
@ -122,9 +126,9 @@ impl Buffer {
}; };
if res == glib::GTRUE { if res == glib::GTRUE {
Some(ReadWriteBufferMap { Some(ReadWriteBufferMap {
buffer: self, buffer: self,
map_info: map_info, map_info: map_info,
}) })
} else { } else {
None None
} }
@ -136,9 +140,9 @@ impl Buffer {
unsafe { gst::gst_buffer_map(buffer.as_mut_ptr(), &mut map_info, gst::GST_MAP_READ) }; unsafe { gst::gst_buffer_map(buffer.as_mut_ptr(), &mut map_info, gst::GST_MAP_READ) };
if res == glib::GTRUE { if res == glib::GTRUE {
Some(ReadMappedBuffer { Some(ReadMappedBuffer {
buffer: buffer, buffer: buffer,
map_info: map_info, map_info: map_info,
}) })
} else { } else {
None None
} }
@ -151,9 +155,9 @@ impl Buffer {
}; };
if res == glib::GTRUE { if res == glib::GTRUE {
Some(ReadWriteMappedBuffer { Some(ReadWriteMappedBuffer {
buffer: buffer, buffer: buffer,
map_info: map_info, map_info: map_info,
}) })
} else { } else {
None None
} }
@ -161,8 +165,10 @@ impl Buffer {
pub fn append(buffer: GstRc<Buffer>, other: GstRc<Buffer>) -> GstRc<Buffer> { pub fn append(buffer: GstRc<Buffer>, other: GstRc<Buffer>) -> GstRc<Buffer> {
unsafe { unsafe {
GstRc::from_owned_ptr(gst::gst_buffer_append(buffer.into_ptr() as *mut gst::GstBuffer, GstRc::from_owned_ptr(gst::gst_buffer_append(
other.into_ptr() as *mut gst::GstBuffer)) buffer.into_ptr() as *mut gst::GstBuffer,
other.into_ptr() as *mut gst::GstBuffer,
))
} }
} }
@ -170,10 +176,12 @@ impl Buffer {
let size_real = size.unwrap_or(usize::MAX); let size_real = size.unwrap_or(usize::MAX);
let raw = unsafe { let raw = unsafe {
gst::gst_buffer_copy_region(self.as_mut_ptr(), gst::gst_buffer_copy_region(
gst::GST_BUFFER_COPY_ALL, self.as_mut_ptr(),
offset, gst::GST_BUFFER_COPY_ALL,
size_real) offset,
size_real,
)
}; };
if raw.is_null() { if raw.is_null() {
@ -194,7 +202,11 @@ impl Buffer {
gst::gst_buffer_fill(self.as_mut_ptr(), offset, src as glib::gconstpointer, size) gst::gst_buffer_fill(self.as_mut_ptr(), offset, src as glib::gconstpointer, size)
}; };
if copied == size { Ok(()) } else { Err(copied) } if copied == size {
Ok(())
} else {
Err(copied)
}
} }
pub fn copy_to_slice(&self, offset: usize, slice: &mut [u8]) -> Result<(), usize> { pub fn copy_to_slice(&self, offset: usize, slice: &mut [u8]) -> Result<(), usize> {
@ -208,7 +220,11 @@ impl Buffer {
gst::gst_buffer_extract(self.as_mut_ptr(), offset, dest as glib::gpointer, size) gst::gst_buffer_extract(self.as_mut_ptr(), offset, dest as glib::gpointer, size)
}; };
if copied == size { Ok(()) } else { Err(copied) } if copied == size {
Ok(())
} else {
Err(copied)
}
} }
pub fn get_size(&self) -> usize { pub fn get_size(&self) -> usize {
@ -219,11 +235,13 @@ impl Buffer {
let mut maxsize: usize = 0; let mut maxsize: usize = 0;
unsafe { unsafe {
gst::gst_buffer_get_sizes_range(self.as_mut_ptr(), gst::gst_buffer_get_sizes_range(
0, self.as_mut_ptr(),
-1, 0,
ptr::null_mut(), -1,
&mut maxsize as *mut usize); ptr::null_mut(),
&mut maxsize as *mut usize,
);
}; };
maxsize maxsize
@ -270,7 +288,11 @@ impl Buffer {
pub fn get_pts(&self) -> Option<u64> { pub fn get_pts(&self) -> Option<u64> {
let pts = self.0.pts; let pts = self.0.pts;
if pts == u64::MAX { None } else { Some(pts) } if pts == u64::MAX {
None
} else {
Some(pts)
}
} }
pub fn set_pts(&mut self, pts: Option<u64>) { pub fn set_pts(&mut self, pts: Option<u64>) {
@ -281,7 +303,11 @@ impl Buffer {
pub fn get_dts(&self) -> Option<u64> { pub fn get_dts(&self) -> Option<u64> {
let dts = self.0.dts; let dts = self.0.dts;
if dts == u64::MAX { None } else { Some(dts) } if dts == u64::MAX {
None
} else {
Some(dts)
}
} }
pub fn set_dts(&mut self, dts: Option<u64>) { pub fn set_dts(&mut self, dts: Option<u64>) {

View file

@ -6,7 +6,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
pub use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian}; pub use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io; use std::io;
pub trait ReadBytesExtShort: io::Read { pub trait ReadBytesExtShort: io::Read {
@ -72,7 +72,11 @@ pub trait ReadBytesExtShort: io::Read {
} }
} }
impl<T> ReadBytesExtShort for T where T: ReadBytesExt {} impl<T> ReadBytesExtShort for T
where
T: ReadBytesExt,
{
}
pub trait WriteBytesExtShort: WriteBytesExt { pub trait WriteBytesExtShort: WriteBytesExt {
fn write_u16le(&mut self, n: u16) -> io::Result<()> { fn write_u16le(&mut self, n: u16) -> io::Result<()> {
@ -137,4 +141,8 @@ pub trait WriteBytesExtShort: WriteBytesExt {
} }
} }
impl<T> WriteBytesExtShort for T where T: WriteBytesExt {} impl<T> WriteBytesExtShort for T
where
T: WriteBytesExt,
{
}

View file

@ -88,7 +88,9 @@ impl Caps {
return None; return None;
} }
Some(Structure::from_borrowed_ptr(structure as *const gst::GstStructure)) Some(Structure::from_borrowed_ptr(
structure as *const gst::GstStructure,
))
} }
} }
@ -99,7 +101,9 @@ impl Caps {
return None; return None;
} }
Some(Structure::from_borrowed_mut_ptr(structure as *mut gst::GstStructure)) Some(Structure::from_borrowed_mut_ptr(
structure as *mut gst::GstStructure,
))
} }
} }
@ -146,24 +150,35 @@ mod tests {
fn test_simple() { fn test_simple() {
init(); init();
let caps = Caps::new_simple("foo/bar", let caps = Caps::new_simple(
&[("int", 12.into()), "foo/bar",
("bool", true.into()), &[
("string", "bla".into()), ("int", 12.into()),
("fraction", (1, 2).into()), ("bool", true.into()),
("array", vec![1.into(), 2.into()].into())]); ("string", "bla".into()),
assert_eq!(caps.to_string(), ("fraction", (1, 2).into()),
"foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, \ ("array", vec![1.into(), 2.into()].into()),
fraction=(fraction)1/2, array=(int)< 1, 2 >"); ],
);
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(); let s = caps.get_structure(0).unwrap();
assert_eq!(s, assert_eq!(
OwnedStructure::new("foo/bar", s,
&[("int", 12.into()), OwnedStructure::new(
("bool", true.into()), "foo/bar",
("string", "bla".into()), &[
("fraction", (1, 2).into()), ("int", 12.into()),
("array", vec![1.into(), 2.into()].into())]) ("bool", true.into()),
.as_ref()); ("string", "bla".into()),
("fraction", (1, 2).into()),
("array", vec![1.into(), 2.into()].into())
]
).as_ref()
);
} }
} }

View file

@ -57,16 +57,18 @@ pub enum HandleBufferResult {
} }
pub trait Demuxer { pub trait Demuxer {
fn start(&mut self, fn start(
upstream_size: Option<u64>, &mut self,
random_access: bool) upstream_size: Option<u64>,
-> Result<(), ErrorMessage>; random_access: bool,
) -> Result<(), ErrorMessage>;
fn stop(&mut self) -> Result<(), ErrorMessage>; fn stop(&mut self) -> Result<(), ErrorMessage>;
fn seek(&mut self, start: u64, stop: Option<u64>) -> Result<SeekResult, ErrorMessage>; fn seek(&mut self, start: u64, stop: Option<u64>) -> Result<SeekResult, ErrorMessage>;
fn handle_buffer(&mut self, fn handle_buffer(
buffer: Option<GstRc<Buffer>>) &mut self,
-> Result<HandleBufferResult, FlowError>; buffer: Option<GstRc<Buffer>>,
) -> Result<HandleBufferResult, FlowError>;
fn end_of_stream(&mut self) -> Result<(), ErrorMessage>; fn end_of_stream(&mut self) -> Result<(), ErrorMessage>;
fn is_seekable(&self) -> bool; fn is_seekable(&self) -> bool;
@ -102,11 +104,15 @@ impl DemuxerWrapper {
fn new(raw: *mut gst::GstElement, demuxer: Box<Demuxer>) -> DemuxerWrapper { fn new(raw: *mut gst::GstElement, demuxer: Box<Demuxer>) -> DemuxerWrapper {
DemuxerWrapper { DemuxerWrapper {
raw: raw, raw: raw,
logger: Logger::root(GstDebugDrain::new(Some(unsafe { &Element::new(raw) }), logger: Logger::root(
"rsdemux", GstDebugDrain::new(
0, Some(unsafe { &Element::new(raw) }),
"Rust demuxer base class"), "rsdemux",
o!()), 0,
"Rust demuxer base class",
),
o!(),
),
demuxer: Mutex::new(demuxer), demuxer: Mutex::new(demuxer),
panicked: AtomicBool::new(false), panicked: AtomicBool::new(false),
} }
@ -115,10 +121,12 @@ impl DemuxerWrapper {
fn start(&self, upstream_size: u64, random_access: bool) -> bool { fn start(&self, upstream_size: u64, random_access: bool) -> bool {
let demuxer = &mut self.demuxer.lock().unwrap(); let demuxer = &mut self.demuxer.lock().unwrap();
debug!(self.logger, debug!(
"Starting with upstream size {} and random access {}", self.logger,
upstream_size, "Starting with upstream size {} and random access {}",
random_access); upstream_size,
random_access
);
let upstream_size = if upstream_size == u64::MAX { let upstream_size = if upstream_size == u64::MAX {
None None
@ -250,19 +258,24 @@ impl DemuxerWrapper {
fn handle_buffer(&self, buffer: GstRc<Buffer>) -> gst::GstFlowReturn { fn handle_buffer(&self, buffer: GstRc<Buffer>) -> gst::GstFlowReturn {
extern "C" { extern "C" {
fn gst_rs_demuxer_stream_eos(raw: *mut gst::GstElement, index: u32); fn gst_rs_demuxer_stream_eos(raw: *mut gst::GstElement, index: u32);
fn gst_rs_demuxer_add_stream(raw: *mut gst::GstElement, fn gst_rs_demuxer_add_stream(
index: u32, raw: *mut gst::GstElement,
caps: *const gst::GstCaps, index: u32,
stream_id: *const c_char); caps: *const gst::GstCaps,
stream_id: *const c_char,
);
fn gst_rs_demuxer_added_all_streams(raw: *mut gst::GstElement); fn gst_rs_demuxer_added_all_streams(raw: *mut gst::GstElement);
// fn gst_rs_demuxer_remove_all_streams(raw: *mut gst::GstElement); // fn gst_rs_demuxer_remove_all_streams(raw: *mut gst::GstElement);
fn gst_rs_demuxer_stream_format_changed(raw: *mut gst::GstElement, fn gst_rs_demuxer_stream_format_changed(
index: u32, raw: *mut gst::GstElement,
caps: *const gst::GstCaps); index: u32,
fn gst_rs_demuxer_stream_push_buffer(raw: *mut gst::GstElement, caps: *const gst::GstCaps,
index: u32, );
buffer: *mut gst::GstBuffer) fn gst_rs_demuxer_stream_push_buffer(
-> gst::GstFlowReturn; raw: *mut gst::GstElement,
index: u32,
buffer: *mut gst::GstBuffer,
) -> gst::GstFlowReturn;
}; };
let mut res = { let mut res = {
@ -275,8 +288,9 @@ impl DemuxerWrapper {
Err(flow_error) => { Err(flow_error) => {
error!(self.logger, "Failed handling buffer: {:?}", flow_error); error!(self.logger, "Failed handling buffer: {:?}", flow_error);
match flow_error { match flow_error {
FlowError::NotNegotiated(ref msg) | FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => {
FlowError::Error(ref msg) => self.post_message(msg), self.post_message(msg)
}
_ => (), _ => (),
} }
return flow_error.to_native(); return flow_error.to_native();
@ -296,34 +310,40 @@ impl DemuxerWrapper {
let stream_id_cstr = CString::new(stream.stream_id.as_bytes()).unwrap(); let stream_id_cstr = CString::new(stream.stream_id.as_bytes()).unwrap();
unsafe { unsafe {
gst_rs_demuxer_add_stream(self.raw, gst_rs_demuxer_add_stream(
stream.index, self.raw,
stream.caps.as_ptr(), stream.index,
stream_id_cstr.as_ptr()); stream.caps.as_ptr(),
stream_id_cstr.as_ptr(),
);
} }
} }
HandleBufferResult::HaveAllStreams => unsafe { HandleBufferResult::HaveAllStreams => unsafe {
gst_rs_demuxer_added_all_streams(self.raw); gst_rs_demuxer_added_all_streams(self.raw);
}, },
HandleBufferResult::StreamChanged(stream) => unsafe { HandleBufferResult::StreamChanged(stream) => unsafe {
gst_rs_demuxer_stream_format_changed(self.raw, gst_rs_demuxer_stream_format_changed(
stream.index, self.raw,
stream.caps.as_ptr()); stream.index,
stream.caps.as_ptr(),
);
}, },
HandleBufferResult::StreamsChanged(streams) => { HandleBufferResult::StreamsChanged(streams) => for stream in streams {
for stream in streams { unsafe {
unsafe { gst_rs_demuxer_stream_format_changed(
gst_rs_demuxer_stream_format_changed(self.raw, self.raw,
stream.index, stream.index,
stream.caps.as_ptr()); stream.caps.as_ptr(),
} );
} }
} },
HandleBufferResult::BufferForStream(index, buffer) => { HandleBufferResult::BufferForStream(index, buffer) => {
let flow_ret = unsafe { let flow_ret = unsafe {
gst_rs_demuxer_stream_push_buffer(self.raw, gst_rs_demuxer_stream_push_buffer(
index, self.raw,
buffer.into_ptr() as *mut gst::GstBuffer) index,
buffer.into_ptr() as *mut gst::GstBuffer,
)
}; };
if flow_ret != gst::GST_FLOW_OK { if flow_ret != gst::GST_FLOW_OK {
return flow_ret; return flow_ret;
@ -352,8 +372,9 @@ impl DemuxerWrapper {
Err(flow_error) => { Err(flow_error) => {
error!(self.logger, "Failed calling again: {:?}", flow_error); error!(self.logger, "Failed calling again: {:?}", flow_error);
match flow_error { match flow_error {
FlowError::NotNegotiated(ref msg) | FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => {
FlowError::Error(ref msg) => self.post_message(msg), self.post_message(msg)
}
_ => (), _ => (),
} }
return flow_error.to_native(); return flow_error.to_native();
@ -384,9 +405,10 @@ impl DemuxerWrapper {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn demuxer_new(demuxer: *mut gst::GstElement, pub unsafe extern "C" fn demuxer_new(
create_instance: fn(Element) -> Box<Demuxer>) demuxer: *mut gst::GstElement,
-> *mut DemuxerWrapper { create_instance: fn(Element) -> Box<Demuxer>,
) -> *mut DemuxerWrapper {
let instance = create_instance(Element::new(demuxer)); let instance = create_instance(Element::new(demuxer));
Box::into_raw(Box::new(DemuxerWrapper::new(demuxer, instance))) Box::into_raw(Box::new(DemuxerWrapper::new(demuxer, instance)))
} }
@ -397,10 +419,11 @@ pub unsafe extern "C" fn demuxer_drop(ptr: *mut DemuxerWrapper) {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn demuxer_start(ptr: *const DemuxerWrapper, pub unsafe extern "C" fn demuxer_start(
upstream_size: u64, ptr: *const DemuxerWrapper,
random_access: glib::gboolean) upstream_size: u64,
-> glib::gboolean { random_access: glib::gboolean,
) -> glib::gboolean {
let wrap: &DemuxerWrapper = &*ptr; let wrap: &DemuxerWrapper = &*ptr;
panic_to_error!(wrap, glib::GFALSE, { panic_to_error!(wrap, glib::GFALSE, {
@ -439,9 +462,10 @@ pub unsafe extern "C" fn demuxer_is_seekable(ptr: *const DemuxerWrapper) -> glib
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn demuxer_get_position(ptr: *const DemuxerWrapper, pub unsafe extern "C" fn demuxer_get_position(
position: *mut u64) ptr: *const DemuxerWrapper,
-> glib::gboolean { position: *mut u64,
) -> glib::gboolean {
let wrap: &DemuxerWrapper = &*ptr; let wrap: &DemuxerWrapper = &*ptr;
panic_to_error!(wrap, glib::GFALSE, { panic_to_error!(wrap, glib::GFALSE, {
@ -451,9 +475,10 @@ pub unsafe extern "C" fn demuxer_get_position(ptr: *const DemuxerWrapper,
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn demuxer_get_duration(ptr: *const DemuxerWrapper, pub unsafe extern "C" fn demuxer_get_duration(
duration: *mut u64) ptr: *const DemuxerWrapper,
-> glib::gboolean { duration: *mut u64,
) -> glib::gboolean {
let wrap: &DemuxerWrapper = &*ptr; let wrap: &DemuxerWrapper = &*ptr;
panic_to_error!(wrap, glib::GFALSE, { panic_to_error!(wrap, glib::GFALSE, {
@ -463,11 +488,12 @@ pub unsafe extern "C" fn demuxer_get_duration(ptr: *const DemuxerWrapper,
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn demuxer_seek(ptr: *mut DemuxerWrapper, pub unsafe extern "C" fn demuxer_seek(
start: u64, ptr: *mut DemuxerWrapper,
stop: u64, start: u64,
offset: *mut u64) stop: u64,
-> glib::gboolean { offset: *mut u64,
) -> glib::gboolean {
let wrap: &mut DemuxerWrapper = &mut *ptr; let wrap: &mut DemuxerWrapper = &mut *ptr;
@ -483,9 +509,10 @@ pub unsafe extern "C" fn demuxer_seek(ptr: *mut DemuxerWrapper,
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn demuxer_handle_buffer(ptr: *mut DemuxerWrapper, pub unsafe extern "C" fn demuxer_handle_buffer(
buffer: *mut gst::GstBuffer) ptr: *mut DemuxerWrapper,
-> gst::GstFlowReturn { buffer: *mut gst::GstBuffer,
) -> gst::GstFlowReturn {
let wrap: &mut DemuxerWrapper = &mut *ptr; let wrap: &mut DemuxerWrapper = &mut *ptr;
panic_to_error!(wrap, gst::GST_FLOW_ERROR, { panic_to_error!(wrap, gst::GST_FLOW_ERROR, {
@ -517,17 +544,18 @@ pub struct DemuxerInfo<'a> {
pub fn demuxer_register(plugin: &Plugin, demuxer_info: &DemuxerInfo) { pub fn demuxer_register(plugin: &Plugin, demuxer_info: &DemuxerInfo) {
extern "C" { extern "C" {
fn gst_rs_demuxer_register(plugin: *const gst::GstPlugin, fn gst_rs_demuxer_register(
name: *const c_char, plugin: *const gst::GstPlugin,
long_name: *const c_char, name: *const c_char,
description: *const c_char, long_name: *const c_char,
classification: *const c_char, description: *const c_char,
author: *const c_char, classification: *const c_char,
rank: i32, author: *const c_char,
create_instance: *const c_void, rank: i32,
input_caps: *const gst::GstCaps, create_instance: *const c_void,
output_caps: *const gst::GstCaps) input_caps: *const gst::GstCaps,
-> glib::gboolean; output_caps: *const gst::GstCaps,
) -> glib::gboolean;
} }
let cname = CString::new(demuxer_info.name).unwrap(); let cname = CString::new(demuxer_info.name).unwrap();
@ -537,15 +565,17 @@ pub fn demuxer_register(plugin: &Plugin, demuxer_info: &DemuxerInfo) {
let cauthor = CString::new(demuxer_info.author).unwrap(); let cauthor = CString::new(demuxer_info.author).unwrap();
unsafe { unsafe {
gst_rs_demuxer_register(plugin.as_ptr(), gst_rs_demuxer_register(
cname.as_ptr(), plugin.as_ptr(),
clong_name.as_ptr(), cname.as_ptr(),
cdescription.as_ptr(), clong_name.as_ptr(),
cclassification.as_ptr(), cdescription.as_ptr(),
cauthor.as_ptr(), cclassification.as_ptr(),
demuxer_info.rank, cauthor.as_ptr(),
demuxer_info.create_instance as *const c_void, demuxer_info.rank,
demuxer_info.input_caps.as_ptr(), demuxer_info.create_instance as *const c_void,
demuxer_info.output_caps.as_ptr()); demuxer_info.input_caps.as_ptr(),
demuxer_info.output_caps.as_ptr(),
);
} }
} }

View file

@ -81,13 +81,14 @@ pub struct ErrorMessage {
} }
impl ErrorMessage { impl ErrorMessage {
pub fn new<T: ToGError>(error: &T, pub fn new<T: ToGError>(
message: Option<Cow<str>>, error: &T,
debug: Option<Cow<str>>, message: Option<Cow<str>>,
filename: &'static str, debug: Option<Cow<str>>,
function: &'static str, filename: &'static str,
line: u32) function: &'static str,
-> ErrorMessage { line: u32,
) -> ErrorMessage {
let (gdomain, gcode) = error.to_gerror(); let (gdomain, gcode) = error.to_gerror();
ErrorMessage { ErrorMessage {
@ -125,15 +126,17 @@ impl ErrorMessage {
let function_cstr = CString::new(function.as_bytes()).unwrap(); let function_cstr = CString::new(function.as_bytes()).unwrap();
let function_ptr = function_cstr.as_ptr(); let function_ptr = function_cstr.as_ptr();
gst::gst_element_message_full(element, gst::gst_element_message_full(
gst::GST_MESSAGE_ERROR, element,
error_domain, gst::GST_MESSAGE_ERROR,
error_code, error_domain,
glib::g_strndup(message_ptr, message_len), error_code,
glib::g_strndup(debug_ptr, debug_len), glib::g_strndup(message_ptr, message_len),
file_ptr, glib::g_strndup(debug_ptr, debug_len),
function_ptr, file_ptr,
line as i32); function_ptr,
line as i32,
);
} }
} }
@ -160,18 +163,18 @@ impl Display for FlowError {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self { match *self {
FlowError::Flushing | FlowError::Eos => f.write_str(self.description()), FlowError::Flushing | FlowError::Eos => f.write_str(self.description()),
FlowError::NotNegotiated(ref m) => { FlowError::NotNegotiated(ref m) => f.write_fmt(format_args!(
f.write_fmt(format_args!("{}: {} ({})", "{}: {} ({})",
self.description(), self.description(),
m.message.as_ref().map_or("None", |s| s.as_str()), m.message.as_ref().map_or("None", |s| s.as_str()),
m.debug.as_ref().map_or("None", |s| s.as_str()))) m.debug.as_ref().map_or("None", |s| s.as_str())
} )),
FlowError::Error(ref m) => { FlowError::Error(ref m) => f.write_fmt(format_args!(
f.write_fmt(format_args!("{}: {} ({})", "{}: {} ({})",
self.description(), self.description(),
m.message.as_ref().map_or("None", |s| s.as_str()), m.message.as_ref().map_or("None", |s| s.as_str()),
m.debug.as_ref().map_or("None", |s| s.as_str()))) m.debug.as_ref().map_or("None", |s| s.as_str())
} )),
} }
} }
} }
@ -220,15 +223,19 @@ impl UriError {
pub unsafe fn into_gerror(self, err: *mut *mut glib::GError) { pub unsafe fn into_gerror(self, err: *mut *mut glib::GError) {
if let Some(msg) = self.message { if let Some(msg) = self.message {
let cmsg = CString::new(msg.as_str()).unwrap(); let cmsg = CString::new(msg.as_str()).unwrap();
glib::g_set_error_literal(err, glib::g_set_error_literal(
gst::gst_uri_error_quark(), err,
self.error_kind as i32, gst::gst_uri_error_quark(),
cmsg.as_ptr()); self.error_kind as i32,
cmsg.as_ptr(),
);
} else { } else {
glib::g_set_error_literal(err, glib::g_set_error_literal(
gst::gst_uri_error_quark(), err,
self.error_kind as i32, gst::gst_uri_error_quark(),
ptr::null()); self.error_kind as i32,
ptr::null(),
);
} }
} }
} }

View file

@ -8,7 +8,7 @@
use libc::c_char; use libc::c_char;
use std::ffi::CString; use std::ffi::CString;
use slog::{Drain, Record, OwnedKVList, Never, Level}; use slog::{Drain, Level, Never, OwnedKVList, Record};
use std::fmt; use std::fmt;
use std::ptr; use std::ptr;
use std::mem; use std::mem;
@ -24,16 +24,18 @@ pub struct GstDebugDrain {
} }
impl GstDebugDrain { impl GstDebugDrain {
pub fn new(element: Option<&Element>, pub fn new(
name: &str, element: Option<&Element>,
color: u32, name: &str,
description: &str) color: u32,
-> GstDebugDrain { description: &str,
) -> GstDebugDrain {
extern "C" { extern "C" {
fn _gst_debug_category_new(name: *const c_char, fn _gst_debug_category_new(
color: u32, name: *const c_char,
description: *const c_char) color: u32,
-> *mut gst::GstDebugCategory; description: *const c_char,
) -> *mut gst::GstDebugCategory;
} }
let name_cstr = CString::new(name.as_bytes()).unwrap(); let name_cstr = CString::new(name.as_bytes()).unwrap();
@ -99,16 +101,19 @@ impl Drain for GstDebugDrain {
let message_cstr = CString::new(fmt::format(*record.msg()).as_bytes()).unwrap(); let message_cstr = CString::new(fmt::format(*record.msg()).as_bytes()).unwrap();
unsafe { unsafe {
let element = gobject::g_weak_ref_get(&*self.element as *const gobject::GWeakRef as let element = gobject::g_weak_ref_get(
*mut gobject::GWeakRef); &*self.element as *const gobject::GWeakRef as *mut gobject::GWeakRef,
);
gst::gst_debug_log(self.category, gst::gst_debug_log(
level, self.category,
file_cstr.as_ptr(), level,
function_cstr.as_ptr(), file_cstr.as_ptr(),
record.line() as i32, function_cstr.as_ptr(),
element as *mut gobject::GObject, record.line() as i32,
message_cstr.as_ptr()); element as *mut gobject::GObject,
message_cstr.as_ptr(),
);
if !element.is_null() { if !element.is_null() {
gst::gst_object_unref(element as *mut gst::GstObject); gst::gst_object_unref(element as *mut gst::GstObject);

View file

@ -6,7 +6,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::{fmt, ops, borrow}; use std::{borrow, fmt, ops};
use std::mem; use std::mem;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -41,9 +41,10 @@ impl<T: MiniObject> GstRc<T> {
return &mut *self.0; return &mut *self.0;
} }
self.0 = T::from_mut_ptr(gst::gst_mini_object_make_writable(self.as_mut_ptr() as self.0 = T::from_mut_ptr(
*mut gst::GstMiniObject) as gst::gst_mini_object_make_writable(self.as_mut_ptr() as *mut gst::GstMiniObject) as
*mut T::PtrType); *mut T::PtrType,
);
assert!(self.is_writable()); assert!(self.is_writable());
&mut *self.0 &mut *self.0
@ -60,16 +61,16 @@ impl<T: MiniObject> GstRc<T> {
pub fn copy(&self) -> Self { pub fn copy(&self) -> Self {
unsafe { unsafe {
GstRc::from_owned_ptr(gst::gst_mini_object_copy(self.as_ptr() as GstRc::from_owned_ptr(
*const gst::GstMiniObject) as gst::gst_mini_object_copy(self.as_ptr() as *const gst::GstMiniObject) as
*const T::PtrType) *const T::PtrType,
)
} }
} }
fn is_writable(&self) -> bool { fn is_writable(&self) -> bool {
(unsafe { (unsafe { gst::gst_mini_object_is_writable(self.as_ptr() as *const gst::GstMiniObject) } ==
gst::gst_mini_object_is_writable(self.as_ptr() as *const gst::GstMiniObject) glib::GTRUE)
} == glib::GTRUE)
} }
pub unsafe fn into_ptr(self) -> *mut T::PtrType { pub unsafe fn into_ptr(self) -> *mut T::PtrType {
@ -132,7 +133,8 @@ impl<T: MiniObject + fmt::Display> fmt::Display for GstRc<T> {
} }
pub unsafe trait MiniObject pub unsafe trait MiniObject
where Self: Sized where
Self: Sized,
{ {
type PtrType; type PtrType;

View file

@ -77,11 +77,15 @@ impl SinkWrapper {
fn new(raw: *mut gst::GstElement, sink: Box<Sink>) -> SinkWrapper { fn new(raw: *mut gst::GstElement, sink: Box<Sink>) -> SinkWrapper {
SinkWrapper { SinkWrapper {
raw: raw, raw: raw,
logger: Logger::root(GstDebugDrain::new(Some(unsafe { &Element::new(raw) }), logger: Logger::root(
"rssink", GstDebugDrain::new(
0, Some(unsafe { &Element::new(raw) }),
"Rust sink base class"), "rssink",
o!()), 0,
"Rust sink base class",
),
o!(),
),
uri: Mutex::new((None, false)), uri: Mutex::new((None, false)),
uri_validator: sink.uri_validator(), uri_validator: sink.uri_validator(),
sink: Mutex::new(sink), sink: Mutex::new(sink),
@ -95,7 +99,10 @@ impl SinkWrapper {
debug!(self.logger, "Setting URI {:?}", uri_str); debug!(self.logger, "Setting URI {:?}", uri_str);
if uri_storage.1 { if uri_storage.1 {
return Err(UriError::new(UriErrorKind::BadState, Some("Already started".to_string()))); return Err(UriError::new(
UriErrorKind::BadState,
Some("Already started".to_string()),
));
} }
uri_storage.0 = None; uri_storage.0 = None;
@ -107,10 +114,10 @@ impl SinkWrapper {
uri_storage.0 = Some(uri); uri_storage.0 = Some(uri);
Ok(()) Ok(())
} }
Err(err) => { Err(err) => Err(UriError::new(
Err(UriError::new(UriErrorKind::BadUri, UriErrorKind::BadUri,
Some(format!("Failed to parse URI '{}': {}", uri_str, err)))) Some(format!("Failed to parse URI '{}': {}", uri_str, err)),
} )),
} }
} else { } else {
Ok(()) Ok(())
@ -119,10 +126,7 @@ impl SinkWrapper {
fn get_uri(&self) -> Option<String> { fn get_uri(&self) -> Option<String> {
let uri_storage = &self.uri.lock().unwrap(); let uri_storage = &self.uri.lock().unwrap();
uri_storage uri_storage.0.as_ref().map(|uri| String::from(uri.as_str()))
.0
.as_ref()
.map(|uri| String::from(uri.as_str()))
} }
fn start(&self) -> bool { fn start(&self) -> bool {
@ -187,8 +191,9 @@ impl SinkWrapper {
Err(flow_error) => { Err(flow_error) => {
error!(self.logger, "Failed to render: {:?}", flow_error); error!(self.logger, "Failed to render: {:?}", flow_error);
match flow_error { match flow_error {
FlowError::NotNegotiated(ref msg) | FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => {
FlowError::Error(ref msg) => self.post_message(msg), self.post_message(msg)
}
_ => (), _ => (),
} }
flow_error.to_native() flow_error.to_native()
@ -203,10 +208,11 @@ impl SinkWrapper {
} }
} }
unsafe fn sink_set_uri(ptr: *const RsSink, unsafe fn sink_set_uri(
uri_ptr: *const c_char, ptr: *const RsSink,
cerr: *mut *mut glib::GError) uri_ptr: *const c_char,
-> glib::gboolean { cerr: *mut *mut glib::GError,
) -> glib::gboolean {
let sink = &*(ptr as *const RsSink); let sink = &*(ptr as *const RsSink);
let wrap: &SinkWrapper = &*sink.wrap; let wrap: &SinkWrapper = &*sink.wrap;
@ -266,16 +272,15 @@ unsafe extern "C" fn sink_stop(ptr: *mut gst_base::GstBaseSink) -> glib::gboolea
}) })
} }
unsafe extern "C" fn sink_render(ptr: *mut gst_base::GstBaseSink, unsafe extern "C" fn sink_render(
buffer: *mut gst::GstBuffer) ptr: *mut gst_base::GstBaseSink,
-> gst::GstFlowReturn { buffer: *mut gst::GstBuffer,
) -> gst::GstFlowReturn {
let sink = &*(ptr as *const RsSink); let sink = &*(ptr as *const RsSink);
let wrap: &SinkWrapper = &*sink.wrap; let wrap: &SinkWrapper = &*sink.wrap;
let buffer: &Buffer = Buffer::from_ptr(buffer); let buffer: &Buffer = Buffer::from_ptr(buffer);
panic_to_error!(wrap, gst::GST_FLOW_ERROR, { panic_to_error!(wrap, gst::GST_FLOW_ERROR, { wrap.render(buffer) })
wrap.render(buffer)
})
} }
pub struct SinkInfo { pub struct SinkInfo {
@ -314,10 +319,12 @@ unsafe extern "C" fn sink_finalize(obj: *mut gobject::GObject) {
parent_klass.finalize.map(|f| f(obj)); parent_klass.finalize.map(|f| f(obj));
} }
unsafe extern "C" fn sink_set_property(obj: *mut gobject::GObject, unsafe extern "C" fn sink_set_property(
id: u32, obj: *mut gobject::GObject,
value: *mut gobject::GValue, id: u32,
_pspec: *mut gobject::GParamSpec) { value: *mut gobject::GValue,
_pspec: *mut gobject::GParamSpec,
) {
let sink = &*(obj as *const RsSink); let sink = &*(obj as *const RsSink);
match id { match id {
@ -329,10 +336,12 @@ unsafe extern "C" fn sink_set_property(obj: *mut gobject::GObject,
} }
} }
unsafe extern "C" fn sink_get_property(obj: *mut gobject::GObject, unsafe extern "C" fn sink_get_property(
id: u32, obj: *mut gobject::GObject,
value: *mut gobject::GValue, id: u32,
_pspec: *mut gobject::GParamSpec) { value: *mut gobject::GValue,
_pspec: *mut gobject::GParamSpec,
) {
let sink = &*(obj as *const RsSink); let sink = &*(obj as *const RsSink);
match id { match id {
@ -350,10 +359,10 @@ unsafe extern "C" fn sink_class_init(klass: glib::gpointer, klass_data: glib::gp
{ {
let gobject_klass = &mut sink_klass let gobject_klass = &mut sink_klass
.parent_class .parent_class
.parent_class .parent_class
.parent_class .parent_class
.parent_class; .parent_class;
gobject_klass.set_property = Some(sink_set_property); gobject_klass.set_property = Some(sink_set_property);
gobject_klass.get_property = Some(sink_get_property); gobject_klass.get_property = Some(sink_get_property);
gobject_klass.finalize = Some(sink_finalize); gobject_klass.finalize = Some(sink_finalize);
@ -362,12 +371,17 @@ unsafe extern "C" fn sink_class_init(klass: glib::gpointer, klass_data: glib::gp
let nick_cstr = CString::new("URI").unwrap(); let nick_cstr = CString::new("URI").unwrap();
let blurb_cstr = CString::new("URI to read from").unwrap(); let blurb_cstr = CString::new("URI to read from").unwrap();
gobject::g_object_class_install_property(klass as *mut gobject::GObjectClass, 1, gobject::g_object_class_install_property(
gobject::g_param_spec_string(name_cstr.as_ptr(), klass as *mut gobject::GObjectClass,
nick_cstr.as_ptr(), 1,
blurb_cstr.as_ptr(), gobject::g_param_spec_string(
ptr::null_mut(), name_cstr.as_ptr(),
gobject::G_PARAM_READWRITE)); nick_cstr.as_ptr(),
blurb_cstr.as_ptr(),
ptr::null_mut(),
gobject::G_PARAM_READWRITE,
),
);
} }
{ {
@ -378,18 +392,22 @@ unsafe extern "C" fn sink_class_init(klass: glib::gpointer, klass_data: glib::gp
let description_cstr = CString::new(sink_info.classification.clone()).unwrap(); let description_cstr = CString::new(sink_info.classification.clone()).unwrap();
let author_cstr = CString::new(sink_info.author.clone()).unwrap(); let author_cstr = CString::new(sink_info.author.clone()).unwrap();
gst::gst_element_class_set_static_metadata(element_klass, gst::gst_element_class_set_static_metadata(
longname_cstr.into_raw(), element_klass,
classification_cstr.into_raw(), longname_cstr.into_raw(),
description_cstr.into_raw(), classification_cstr.into_raw(),
author_cstr.into_raw()); description_cstr.into_raw(),
author_cstr.into_raw(),
);
let caps = Caps::new_any(); let caps = Caps::new_any();
let templ_name = CString::new("sink").unwrap(); let templ_name = CString::new("sink").unwrap();
let pad_template = gst::gst_pad_template_new(templ_name.into_raw(), let pad_template = gst::gst_pad_template_new(
gst::GST_PAD_SINK, templ_name.into_raw(),
gst::GST_PAD_ALWAYS, gst::GST_PAD_SINK,
caps.as_ptr() as *mut gst::GstCaps); gst::GST_PAD_ALWAYS,
caps.as_ptr() as *mut gst::GstCaps,
);
gst::gst_element_class_add_pad_template(element_klass, pad_template); gst::gst_element_class_add_pad_template(element_klass, pad_template);
} }
@ -418,8 +436,10 @@ unsafe extern "C" fn sink_init(instance: *mut gobject::GTypeInstance, klass: gli
sink.sink_info = sink_info; sink.sink_info = sink_info;
let wrap = Box::new(SinkWrapper::new(&mut sink.parent.element, let wrap = Box::new(SinkWrapper::new(
(sink_info.create_instance)(Element::new(&mut sink.parent.element)))); &mut sink.parent.element,
(sink_info.create_instance)(Element::new(&mut sink.parent.element)),
));
sink.wrap = Box::into_raw(wrap); sink.wrap = Box::into_raw(wrap);
gst_base::gst_base_sink_set_sync(&mut sink.parent, glib::GFALSE); gst_base::gst_base_sink_set_sync(&mut sink.parent, glib::GFALSE);
@ -439,10 +459,11 @@ unsafe extern "C" fn sink_uri_handler_get_uri(uri_handler: *mut gst::GstURIHandl
sink_get_uri(uri_handler as *const RsSink) sink_get_uri(uri_handler as *const RsSink)
} }
unsafe extern "C" fn sink_uri_handler_set_uri(uri_handler: *mut gst::GstURIHandler, unsafe extern "C" fn sink_uri_handler_set_uri(
uri: *const c_char, uri_handler: *mut gst::GstURIHandler,
err: *mut *mut glib::GError) uri: *const c_char,
-> glib::gboolean { err: *mut *mut glib::GError,
) -> glib::gboolean {
sink_set_uri(uri_handler as *const RsSink, uri, err) sink_set_uri(uri_handler as *const RsSink, uri, err)
} }
@ -481,10 +502,12 @@ pub fn sink_register(plugin: &Plugin, sink_info: SinkInfo) {
value_table: ptr::null(), value_table: ptr::null(),
}; };
let type_ = gobject::g_type_register_static(parent_type, let type_ = gobject::g_type_register_static(
type_name_cstr.as_ptr(), parent_type,
&type_info, type_name_cstr.as_ptr(),
gobject::GTypeFlags::empty()); &type_info,
gobject::GTypeFlags::empty(),
);
let iface_info = gobject::GInterfaceInfo { let iface_info = gobject::GInterfaceInfo {
interface_init: Some(sink_uri_handler_init), interface_init: Some(sink_uri_handler_init),

View file

@ -80,11 +80,15 @@ impl SourceWrapper {
fn new(raw: *mut gst::GstElement, source: Box<Source>) -> SourceWrapper { fn new(raw: *mut gst::GstElement, source: Box<Source>) -> SourceWrapper {
SourceWrapper { SourceWrapper {
raw: raw, raw: raw,
logger: Logger::root(GstDebugDrain::new(Some(unsafe { &Element::new(raw) }), logger: Logger::root(
"rssrc", GstDebugDrain::new(
0, Some(unsafe { &Element::new(raw) }),
"Rust source base class"), "rssrc",
o!()), 0,
"Rust source base class",
),
o!(),
),
uri: Mutex::new((None, false)), uri: Mutex::new((None, false)),
uri_validator: source.uri_validator(), uri_validator: source.uri_validator(),
source: Mutex::new(source), source: Mutex::new(source),
@ -98,7 +102,10 @@ impl SourceWrapper {
debug!(self.logger, "Setting URI {:?}", uri_str); debug!(self.logger, "Setting URI {:?}", uri_str);
if uri_storage.1 { if uri_storage.1 {
return Err(UriError::new(UriErrorKind::BadState, Some("Already started".to_string()))); return Err(UriError::new(
UriErrorKind::BadState,
Some("Already started".to_string()),
));
} }
uri_storage.0 = None; uri_storage.0 = None;
@ -110,10 +117,10 @@ impl SourceWrapper {
uri_storage.0 = Some(uri); uri_storage.0 = Some(uri);
Ok(()) Ok(())
} }
Err(err) => { Err(err) => Err(UriError::new(
Err(UriError::new(UriErrorKind::BadUri, UriErrorKind::BadUri,
Some(format!("Failed to parse URI '{}': {}", uri_str, err)))) Some(format!("Failed to parse URI '{}': {}", uri_str, err)),
} )),
} }
} else { } else {
Ok(()) Ok(())
@ -122,10 +129,7 @@ impl SourceWrapper {
fn get_uri(&self) -> Option<String> { fn get_uri(&self) -> Option<String> {
let uri_storage = &self.uri.lock().unwrap(); let uri_storage = &self.uri.lock().unwrap();
uri_storage uri_storage.0.as_ref().map(|uri| String::from(uri.as_str()))
.0
.as_ref()
.map(|uri| String::from(uri.as_str()))
} }
fn is_seekable(&self) -> bool { fn is_seekable(&self) -> bool {
@ -193,19 +197,22 @@ impl SourceWrapper {
fn fill(&self, offset: u64, length: u32, buffer: &mut Buffer) -> gst::GstFlowReturn { fn fill(&self, offset: u64, length: u32, buffer: &mut Buffer) -> gst::GstFlowReturn {
let source = &mut self.source.lock().unwrap(); let source = &mut self.source.lock().unwrap();
trace!(self.logger, trace!(
"Filling buffer {:?} with offset {} and length {}", self.logger,
buffer, "Filling buffer {:?} with offset {} and length {}",
offset, buffer,
length); offset,
length
);
match source.fill(offset, length, buffer) { match source.fill(offset, length, buffer) {
Ok(()) => gst::GST_FLOW_OK, Ok(()) => gst::GST_FLOW_OK,
Err(flow_error) => { Err(flow_error) => {
error!(self.logger, "Failed to fill: {:?}", flow_error); error!(self.logger, "Failed to fill: {:?}", flow_error);
match flow_error { match flow_error {
FlowError::NotNegotiated(ref msg) | FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => {
FlowError::Error(ref msg) => self.post_message(msg), self.post_message(msg)
}
_ => (), _ => (),
} }
flow_error.to_native() flow_error.to_native()
@ -235,10 +242,11 @@ impl SourceWrapper {
} }
} }
unsafe fn source_set_uri(ptr: *const RsSrc, unsafe fn source_set_uri(
uri_ptr: *const c_char, ptr: *const RsSrc,
cerr: *mut *mut glib::GError) uri_ptr: *const c_char,
-> glib::gboolean { cerr: *mut *mut glib::GError,
) -> glib::gboolean {
let src = &*(ptr as *const RsSrc); let src = &*(ptr as *const RsSrc);
let wrap: &SourceWrapper = &*src.wrap; let wrap: &SourceWrapper = &*src.wrap;
@ -285,9 +293,10 @@ unsafe extern "C" fn source_is_seekable(ptr: *mut gst_base::GstBaseSrc) -> glib:
}) })
} }
unsafe extern "C" fn source_get_size(ptr: *mut gst_base::GstBaseSrc, unsafe extern "C" fn source_get_size(
size: *mut u64) ptr: *mut gst_base::GstBaseSrc,
-> glib::gboolean { size: *mut u64,
) -> glib::gboolean {
let src = &*(ptr as *const RsSrc); let src = &*(ptr as *const RsSrc);
let wrap: &SourceWrapper = &*src.wrap; let wrap: &SourceWrapper = &*src.wrap;
@ -323,23 +332,27 @@ unsafe extern "C" fn source_stop(ptr: *mut gst_base::GstBaseSrc) -> glib::gboole
}) })
} }
unsafe extern "C" fn source_fill(ptr: *mut gst_base::GstBaseSrc, unsafe extern "C" fn source_fill(
offset: u64, ptr: *mut gst_base::GstBaseSrc,
length: u32, offset: u64,
buffer: *mut gst::GstBuffer) length: u32,
-> gst::GstFlowReturn { buffer: *mut gst::GstBuffer,
) -> gst::GstFlowReturn {
let src = &*(ptr as *const RsSrc); let src = &*(ptr as *const RsSrc);
let wrap: &SourceWrapper = &*src.wrap; let wrap: &SourceWrapper = &*src.wrap;
let buffer: &mut Buffer = <Buffer as MiniObject>::from_mut_ptr(buffer); let buffer: &mut Buffer = <Buffer as MiniObject>::from_mut_ptr(buffer);
panic_to_error!(wrap, gst::GST_FLOW_ERROR, { panic_to_error!(
wrap.fill(offset, length, buffer) wrap,
}) gst::GST_FLOW_ERROR,
{ wrap.fill(offset, length, buffer) }
)
} }
unsafe extern "C" fn source_seek(ptr: *mut gst_base::GstBaseSrc, unsafe extern "C" fn source_seek(
segment: *mut gst::GstSegment) ptr: *mut gst_base::GstBaseSrc,
-> glib::gboolean { segment: *mut gst::GstSegment,
) -> glib::gboolean {
let src = &*(ptr as *const RsSrc); let src = &*(ptr as *const RsSrc);
let wrap: &SourceWrapper = &*src.wrap; let wrap: &SourceWrapper = &*src.wrap;
@ -392,10 +405,12 @@ unsafe extern "C" fn source_finalize(obj: *mut gobject::GObject) {
parent_klass.finalize.map(|f| f(obj)); parent_klass.finalize.map(|f| f(obj));
} }
unsafe extern "C" fn source_set_property(obj: *mut gobject::GObject, unsafe extern "C" fn source_set_property(
id: u32, obj: *mut gobject::GObject,
value: *mut gobject::GValue, id: u32,
_pspec: *mut gobject::GParamSpec) { value: *mut gobject::GValue,
_pspec: *mut gobject::GParamSpec,
) {
let src = &*(obj as *const RsSrc); let src = &*(obj as *const RsSrc);
match id { match id {
@ -407,10 +422,12 @@ unsafe extern "C" fn source_set_property(obj: *mut gobject::GObject,
} }
} }
unsafe extern "C" fn source_get_property(obj: *mut gobject::GObject, unsafe extern "C" fn source_get_property(
id: u32, obj: *mut gobject::GObject,
value: *mut gobject::GValue, id: u32,
_pspec: *mut gobject::GParamSpec) { value: *mut gobject::GValue,
_pspec: *mut gobject::GParamSpec,
) {
let src = &*(obj as *const RsSrc); let src = &*(obj as *const RsSrc);
match id { match id {
@ -428,11 +445,11 @@ unsafe extern "C" fn source_class_init(klass: glib::gpointer, klass_data: glib::
{ {
let gobject_klass = &mut src_klass let gobject_klass = &mut src_klass
.parent_class .parent_class
.parent_class .parent_class
.parent_class .parent_class
.parent_class .parent_class
.parent_class; .parent_class;
gobject_klass.set_property = Some(source_set_property); gobject_klass.set_property = Some(source_set_property);
gobject_klass.get_property = Some(source_get_property); gobject_klass.get_property = Some(source_get_property);
gobject_klass.finalize = Some(source_finalize); gobject_klass.finalize = Some(source_finalize);
@ -441,12 +458,17 @@ unsafe extern "C" fn source_class_init(klass: glib::gpointer, klass_data: glib::
let nick_cstr = CString::new("URI").unwrap(); let nick_cstr = CString::new("URI").unwrap();
let blurb_cstr = CString::new("URI to read from").unwrap(); let blurb_cstr = CString::new("URI to read from").unwrap();
gobject::g_object_class_install_property(klass as *mut gobject::GObjectClass, 1, gobject::g_object_class_install_property(
gobject::g_param_spec_string(name_cstr.as_ptr(), klass as *mut gobject::GObjectClass,
nick_cstr.as_ptr(), 1,
blurb_cstr.as_ptr(), gobject::g_param_spec_string(
ptr::null_mut(), name_cstr.as_ptr(),
gobject::G_PARAM_READWRITE)); nick_cstr.as_ptr(),
blurb_cstr.as_ptr(),
ptr::null_mut(),
gobject::G_PARAM_READWRITE,
),
);
} }
{ {
@ -457,18 +479,22 @@ unsafe extern "C" fn source_class_init(klass: glib::gpointer, klass_data: glib::
let description_cstr = CString::new(source_info.classification.clone()).unwrap(); let description_cstr = CString::new(source_info.classification.clone()).unwrap();
let author_cstr = CString::new(source_info.author.clone()).unwrap(); let author_cstr = CString::new(source_info.author.clone()).unwrap();
gst::gst_element_class_set_static_metadata(element_klass, gst::gst_element_class_set_static_metadata(
longname_cstr.into_raw(), element_klass,
classification_cstr.into_raw(), longname_cstr.into_raw(),
description_cstr.into_raw(), classification_cstr.into_raw(),
author_cstr.into_raw()); description_cstr.into_raw(),
author_cstr.into_raw(),
);
let caps = Caps::new_any(); let caps = Caps::new_any();
let templ_name = CString::new("src").unwrap(); let templ_name = CString::new("src").unwrap();
let pad_template = gst::gst_pad_template_new(templ_name.into_raw(), let pad_template = gst::gst_pad_template_new(
gst::GST_PAD_SRC, templ_name.into_raw(),
gst::GST_PAD_ALWAYS, gst::GST_PAD_SRC,
caps.as_ptr() as *mut gst::GstCaps); gst::GST_PAD_ALWAYS,
caps.as_ptr() as *mut gst::GstCaps,
);
gst::gst_element_class_add_pad_template(element_klass, pad_template); gst::gst_element_class_add_pad_template(element_klass, pad_template);
} }
@ -500,8 +526,10 @@ unsafe extern "C" fn source_init(instance: *mut gobject::GTypeInstance, klass: g
src.source_info = source_info; src.source_info = source_info;
let wrap = Box::new(SourceWrapper::new(&mut src.parent.parent.element, let wrap = Box::new(SourceWrapper::new(
(source_info.create_instance)(Element::new(&mut src.parent.parent.element)))); &mut src.parent.parent.element,
(source_info.create_instance)(Element::new(&mut src.parent.parent.element)),
));
src.wrap = Box::into_raw(wrap); src.wrap = Box::into_raw(wrap);
gst_base::gst_base_src_set_blocksize(&mut src.parent.parent, 4096); gst_base::gst_base_src_set_blocksize(&mut src.parent.parent, 4096);
@ -517,15 +545,17 @@ unsafe extern "C" fn source_uri_handler_get_protocols(type_: glib::GType) -> *co
(*src_klass.protocols).as_ptr() (*src_klass.protocols).as_ptr()
} }
unsafe extern "C" fn source_uri_handler_get_uri(uri_handler: *mut gst::GstURIHandler) unsafe extern "C" fn source_uri_handler_get_uri(
-> *mut c_char { uri_handler: *mut gst::GstURIHandler,
) -> *mut c_char {
source_get_uri(uri_handler as *const RsSrc) source_get_uri(uri_handler as *const RsSrc)
} }
unsafe extern "C" fn source_uri_handler_set_uri(uri_handler: *mut gst::GstURIHandler, unsafe extern "C" fn source_uri_handler_set_uri(
uri: *const c_char, uri_handler: *mut gst::GstURIHandler,
err: *mut *mut glib::GError) uri: *const c_char,
-> glib::gboolean { err: *mut *mut glib::GError,
) -> glib::gboolean {
source_set_uri(uri_handler as *const RsSrc, uri, err) source_set_uri(uri_handler as *const RsSrc, uri, err)
} }
@ -568,10 +598,12 @@ pub fn source_register(plugin: &Plugin, source_info: SourceInfo) {
value_table: ptr::null(), value_table: ptr::null(),
}; };
let type_ = gobject::g_type_register_static(parent_type, let type_ = gobject::g_type_register_static(
type_name_cstr.as_ptr(), parent_type,
&type_info, type_name_cstr.as_ptr(),
gobject::GTypeFlags::empty()); &type_info,
gobject::GTypeFlags::empty(),
);
let iface_info = gobject::GInterfaceInfo { let iface_info = gobject::GInterfaceInfo {
interface_init: Some(source_uri_handler_init), interface_init: Some(source_uri_handler_init),

View file

@ -39,21 +39,24 @@ bitflags! {
} }
impl Stream { impl Stream {
pub fn new(stream_id: &str, pub fn new(
caps: Option<GstRc<Caps>>, stream_id: &str,
t: StreamType, caps: Option<GstRc<Caps>>,
flags: StreamFlags) t: StreamType,
-> Self { flags: StreamFlags,
) -> Self {
let stream_id_cstr = CString::new(stream_id).unwrap(); let stream_id_cstr = CString::new(stream_id).unwrap();
let caps = caps.map(|caps| unsafe { caps.as_mut_ptr() }) let caps = caps.map(|caps| unsafe { caps.as_mut_ptr() })
.unwrap_or(ptr::null_mut()); .unwrap_or(ptr::null_mut());
Stream(unsafe { Stream(unsafe {
gst::gst_stream_new(stream_id_cstr.as_ptr(), gst::gst_stream_new(
caps, stream_id_cstr.as_ptr(),
mem::transmute(t.bits()), caps,
mem::transmute(flags.bits())) mem::transmute(t.bits()),
}) mem::transmute(flags.bits()),
)
})
} }
pub unsafe fn as_ptr(&self) -> *const gst::GstStream { pub unsafe fn as_ptr(&self) -> *const gst::GstStream {
@ -118,7 +121,10 @@ impl Stream {
impl Clone for Stream { impl Clone for Stream {
fn clone(&self) -> Self { fn clone(&self) -> Self {
unsafe { Stream(gst::gst_object_ref(self.0 as *mut gst::GstObject) as *mut gst::GstStream) } unsafe {
Stream(gst::gst_object_ref(self.0 as *mut gst::GstObject) as
*mut gst::GstStream)
}
} }
} }
@ -131,8 +137,9 @@ impl Drop for Stream {
impl StreamCollection { impl StreamCollection {
pub fn new(upstream_id: &str, streams: &[Stream]) -> Self { pub fn new(upstream_id: &str, streams: &[Stream]) -> Self {
let upstream_id_cstr = CString::new(upstream_id).unwrap(); let upstream_id_cstr = CString::new(upstream_id).unwrap();
let collection = let collection = StreamCollection(unsafe {
StreamCollection(unsafe { gst::gst_stream_collection_new(upstream_id_cstr.as_ptr()) }); gst::gst_stream_collection_new(upstream_id_cstr.as_ptr())
});
for stream in streams { for stream in streams {
unsafe { gst::gst_stream_collection_add_stream(collection.0, stream.clone().0) }; unsafe { gst::gst_stream_collection_add_stream(collection.0, stream.clone().0) };
@ -196,8 +203,9 @@ impl<'a> Iterator for StreamCollectionIterator<'a> {
self.position += 1; self.position += 1;
Some(unsafe { Some(unsafe {
Stream(gst::gst_object_ref(stream as *mut gst::GstObject) as *mut gst::GstStream) Stream(gst::gst_object_ref(stream as *mut gst::GstObject) as
}) *mut gst::GstStream)
})
} }
fn size_hint(&self) -> (usize, Option<usize>) { fn size_hint(&self) -> (usize, Option<usize>) {
@ -227,8 +235,9 @@ impl<'a> DoubleEndedIterator for StreamCollectionIterator<'a> {
} }
Some(unsafe { Some(unsafe {
Stream(gst::gst_object_ref(stream as *mut gst::GstObject) as *mut gst::GstStream) Stream(gst::gst_object_ref(stream as *mut gst::GstObject) as
}) *mut gst::GstStream)
})
} }
} }
@ -238,7 +247,7 @@ impl Clone for StreamCollection {
fn clone(&self) -> Self { fn clone(&self) -> Self {
unsafe { unsafe {
StreamCollection(gst::gst_object_ref(self.0 as *mut gst::GstObject) as StreamCollection(gst::gst_object_ref(self.0 as *mut gst::GstObject) as
*mut gst::GstStreamCollection) *mut gst::GstStreamCollection)
} }
} }
} }

View file

@ -11,7 +11,7 @@ use std::ptr;
use std::mem; use std::mem;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::borrow::{Borrow, ToOwned, BorrowMut}; use std::borrow::{Borrow, BorrowMut, ToOwned};
use std::marker::PhantomData; use std::marker::PhantomData;
use value::*; use value::*;
@ -24,10 +24,10 @@ pub struct OwnedStructure(*mut Structure, PhantomData<Structure>);
impl OwnedStructure { impl OwnedStructure {
pub fn new_empty(name: &str) -> OwnedStructure { pub fn new_empty(name: &str) -> OwnedStructure {
let name_cstr = CString::new(name).unwrap(); let name_cstr = CString::new(name).unwrap();
OwnedStructure(unsafe { OwnedStructure(
gst::gst_structure_new_empty(name_cstr.as_ptr()) as *mut Structure unsafe { gst::gst_structure_new_empty(name_cstr.as_ptr()) as *mut Structure },
}, PhantomData,
PhantomData) )
} }
pub fn new(name: &str, values: &[(&str, Value)]) -> OwnedStructure { pub fn new(name: &str, values: &[(&str, Value)]) -> OwnedStructure {
@ -88,8 +88,10 @@ impl AsMut<Structure> for OwnedStructure {
impl Clone for OwnedStructure { impl Clone for OwnedStructure {
fn clone(&self) -> Self { fn clone(&self) -> Self {
OwnedStructure(unsafe { gst::gst_structure_copy(&(*self.0).0) as *mut Structure }, OwnedStructure(
PhantomData) unsafe { gst::gst_structure_copy(&(*self.0).0) as *mut Structure },
PhantomData,
)
} }
} }
@ -135,8 +137,10 @@ impl ToOwned for Structure {
type Owned = OwnedStructure; type Owned = OwnedStructure;
fn to_owned(&self) -> OwnedStructure { fn to_owned(&self) -> OwnedStructure {
OwnedStructure(unsafe { gst::gst_structure_copy(&self.0) as *mut Structure }, OwnedStructure(
PhantomData) unsafe { gst::gst_structure_copy(&self.0) as *mut Structure },
PhantomData,
)
} }
} }
@ -167,8 +171,7 @@ impl Structure {
} }
pub fn get<'a, T: ValueType<'a>>(&'a self, name: &str) -> Option<TypedValueRef<'a, T>> { pub fn get<'a, T: ValueType<'a>>(&'a self, name: &str) -> Option<TypedValueRef<'a, T>> {
self.get_value(name) self.get_value(name).and_then(TypedValueRef::from_value_ref)
.and_then(TypedValueRef::from_value_ref)
} }
pub fn get_value<'a>(&'a self, name: &str) -> Option<ValueRef<'a>> { pub fn get_value<'a>(&'a self, name: &str) -> Option<ValueRef<'a>> {
@ -331,7 +334,9 @@ pub struct Iter<'a> {
impl<'a> Iter<'a> { impl<'a> Iter<'a> {
pub fn new(structure: &'a Structure) -> Iter<'a> { pub fn new(structure: &'a Structure) -> Iter<'a> {
Iter { iter: FieldIterator::new(structure) } Iter {
iter: FieldIterator::new(structure),
}
} }
} }
@ -385,17 +390,25 @@ mod tests {
assert_eq!(s.get::<&str>("f2").unwrap().get(), "bcd"); assert_eq!(s.get::<&str>("f2").unwrap().get(), "bcd");
assert_eq!(s.get::<i32>("f3").unwrap().get(), 123i32); assert_eq!(s.get::<i32>("f3").unwrap().get(), 123i32);
assert_eq!(s.fields().collect::<Vec<_>>(), vec!["f1", "f2", "f3"]); assert_eq!(s.fields().collect::<Vec<_>>(), vec!["f1", "f2", "f3"]);
assert_eq!(s.iter() assert_eq!(
.map(|(f, v)| (f, Value::from_value_ref(&v))) s.iter()
.collect::<Vec<_>>(), .map(|(f, v)| (f, Value::from_value_ref(&v)))
vec![("f1", Value::new("abc")), .collect::<Vec<_>>(),
("f2", Value::new("bcd")), vec![
("f3", Value::new(123i32))]); ("f1", Value::new("abc")),
("f2", Value::new("bcd")),
("f3", Value::new(123i32)),
]
);
let s2 = OwnedStructure::new("test", let s2 = OwnedStructure::new(
&[("f1", "abc".into()), "test",
("f2", "bcd".into()), &[
("f3", 123i32.into())]); ("f1", "abc".into()),
("f2", "bcd".into()),
("f3", 123i32.into()),
],
);
assert_eq!(s, s2); assert_eq!(s, s2);
} }
} }

View file

@ -81,17 +81,20 @@ impl TagList {
} }
pub fn add<'a, T: Tag<'a>>(&mut self, value: T::TagType, mode: MergeMode) pub fn add<'a, T: Tag<'a>>(&mut self, value: T::TagType, mode: MergeMode)
where T::TagType: Into<Value> where
T::TagType: Into<Value>,
{ {
unsafe { unsafe {
let v = value.into(); let v = value.into();
let mut gvalue = v.into_raw(); let mut gvalue = v.into_raw();
let tag_name = CString::new(T::tag_name()).unwrap(); let tag_name = CString::new(T::tag_name()).unwrap();
gst::gst_tag_list_add_value(self.as_mut_ptr(), gst::gst_tag_list_add_value(
mode.to_ffi(), self.as_mut_ptr(),
tag_name.as_ptr(), mode.to_ffi(),
&gvalue); tag_name.as_ptr(),
&gvalue,
);
gobject::g_value_unset(&mut gvalue); gobject::g_value_unset(&mut gvalue);
} }
@ -252,8 +255,10 @@ mod tests {
tags.add::<Title>("some title".into(), MergeMode::Append); tags.add::<Title>("some title".into(), MergeMode::Append);
tags.add::<Duration>((1000u64 * 1000 * 1000 * 120).into(), MergeMode::Append); tags.add::<Duration>((1000u64 * 1000 * 1000 * 120).into(), MergeMode::Append);
} }
assert_eq!(tags.to_string(), assert_eq!(
"taglist, title=(string)\"some\\ title\", duration=(guint64)120000000000;"); tags.to_string(),
"taglist, title=(string)\"some\\ title\", duration=(guint64)120000000000;"
);
} }
#[test] #[test]
@ -269,10 +274,14 @@ mod tests {
} }
assert_eq!(tags.get::<Title>().unwrap().get(), "some title"); assert_eq!(tags.get::<Title>().unwrap().get(), "some title");
assert_eq!(tags.get::<Duration>().unwrap().get(), assert_eq!(
(1000u64 * 1000 * 1000 * 120)); 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::<Title>(0).unwrap().get(), "some title");
assert_eq!(tags.get_index::<Duration>(0).unwrap().get(), assert_eq!(
(1000u64 * 1000 * 1000 * 120)); tags.get_index::<Duration>(0).unwrap().get(),
(1000u64 * 1000 * 1000 * 120)
);
} }
} }

View file

@ -78,8 +78,9 @@ pub fn f64_to_fraction(val: f64) -> Option<Rational32> {
// Prevent overflow // Prevent overflow
if a != 0 && if a != 0 &&
(n1 > (i32::MAX as u32) / a || d1 > (i32::MAX as u32) / a || (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) { a * n1 > (i32::MAX as u32) - n0 || a * d1 > (i32::MAX as u32) - d0)
{
break; break;
} }
@ -156,8 +157,10 @@ mod tests {
fn test_f64_to_fraction() { fn test_f64_to_fraction() {
assert_eq!(f64_to_fraction(2.0), Some(Rational32::new(2, 1))); 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(2.5), Some(Rational32::new(5, 2)));
assert_eq!(f64_to_fraction(0.127659574), assert_eq!(
Some(Rational32::new(29013539, 227272723))); f64_to_fraction(0.127659574),
Some(Rational32::new(29013539, 227272723))
);
assert_eq!(f64_to_fraction(29.97), Some(Rational32::new(2997, 100))); assert_eq!(f64_to_fraction(29.97), Some(Rational32::new(2997, 100)));
} }
} }

View file

@ -46,7 +46,8 @@ impl<'a> ValueView<'a> {
} }
pub trait ValueType<'a> pub trait ValueType<'a>
where Self: Sized where
Self: Sized,
{ {
fn g_type() -> glib::GType; fn g_type() -> glib::GType;
@ -138,13 +139,12 @@ impl Value {
typ if typ == *TYPE_FRACTION => { typ if typ == *TYPE_FRACTION => {
ValueView::Fraction(Rational32::from_value(&self.0).unwrap()) ValueView::Fraction(Rational32::from_value(&self.0).unwrap())
} }
gobject::G_TYPE_STRING => { gobject::G_TYPE_STRING => ValueView::String(Cow::Borrowed(
ValueView::String(Cow::Borrowed(<&str as ValueType>::from_value(&self.0).unwrap())) <&str as ValueType>::from_value(&self.0).unwrap(),
} )),
typ if typ == *TYPE_GST_VALUE_ARRAY => { typ if typ == *TYPE_GST_VALUE_ARRAY => ValueView::Array(Cow::Borrowed(
ValueView::Array(Cow::Borrowed(<&[Value] as ValueType>::from_value(&self.0) <&[Value] as ValueType>::from_value(&self.0).unwrap(),
.unwrap())) )),
}
typ if typ == *TYPE_BUFFER => { typ if typ == *TYPE_BUFFER => {
ValueView::Buffer(<GstRc<Buffer> as ValueType>::from_value(&self.0).unwrap()) ValueView::Buffer(<GstRc<Buffer> as ValueType>::from_value(&self.0).unwrap())
} }
@ -228,13 +228,12 @@ impl<'a> ValueRef<'a> {
typ if typ == *TYPE_FRACTION => { typ if typ == *TYPE_FRACTION => {
ValueView::Fraction(Rational32::from_value(self.0).unwrap()) ValueView::Fraction(Rational32::from_value(self.0).unwrap())
} }
gobject::G_TYPE_STRING => { gobject::G_TYPE_STRING => ValueView::String(Cow::Borrowed(
ValueView::String(Cow::Borrowed(<&str as ValueType>::from_value(self.0).unwrap())) <&str as ValueType>::from_value(self.0).unwrap(),
} )),
typ if typ == *TYPE_GST_VALUE_ARRAY => { typ if typ == *TYPE_GST_VALUE_ARRAY => ValueView::Array(Cow::Borrowed(
ValueView::Array(Cow::Borrowed(<&[Value] as ValueType>::from_value(self.0) <&[Value] as ValueType>::from_value(self.0).unwrap(),
.unwrap())) )),
}
typ if typ == *TYPE_BUFFER => { typ if typ == *TYPE_BUFFER => {
ValueView::Buffer(<GstRc<Buffer> as ValueType>::from_value(self.0).unwrap()) ValueView::Buffer(<GstRc<Buffer> as ValueType>::from_value(self.0).unwrap())
} }
@ -335,16 +334,20 @@ impl_value_type_simple!(u64,
gobject::G_TYPE_UINT64, gobject::G_TYPE_UINT64,
|value: &gobject::GValue| gobject::g_value_get_uint64(value), |value: &gobject::GValue| gobject::g_value_get_uint64(value),
|value: &mut gobject::GValue, v| gobject::g_value_set_uint64(value, v)); |value: &mut gobject::GValue, v| gobject::g_value_set_uint64(value, v));
impl_value_type_simple!(Rational32, impl_value_type_simple!(
Fraction, Rational32,
*TYPE_FRACTION, Fraction,
|value: &gobject::GValue| { *TYPE_FRACTION,
Rational32::new(gst::gst_value_get_fraction_numerator(value), |value: &gobject::GValue| {
gst::gst_value_get_fraction_denominator(value)) Rational32::new(
}, gst::gst_value_get_fraction_numerator(value),
|value: &mut gobject::GValue, v: Rational32| { gst::gst_value_get_fraction_denominator(value),
gst::gst_value_set_fraction(value, *v.numer(), *v.denom()) )
}); },
|value: &mut gobject::GValue, v: Rational32| {
gst::gst_value_set_fraction(value, *v.numer(), *v.denom())
}
);
impl<'a> ValueType<'a> for &'a str { impl<'a> ValueType<'a> for &'a str {
fn g_type() -> glib::GType { fn g_type() -> glib::GType {
@ -469,7 +472,10 @@ impl<'a> ValueType<'a> for &'a [Value] {
Some(&[]) Some(&[])
} else { } else {
let arr = &*arr; let arr = &*arr;
Some(slice::from_raw_parts(arr.data as *const Value, arr.len as usize)) Some(slice::from_raw_parts(
arr.data as *const Value,
arr.len as usize,
))
} }
} }
} }
@ -491,20 +497,19 @@ impl<'a> From<Cow<'a, [Value]>> for Value {
gobject::g_value_init(&mut value.0, <&[Value] as ValueType>::g_type()); gobject::g_value_init(&mut value.0, <&[Value] as ValueType>::g_type());
match v { match v {
Cow::Borrowed(array) => { Cow::Borrowed(array) => for e in array {
for e in array { gst::gst_value_array_append_value(
gst::gst_value_array_append_value(&mut value.0, &mut value.0,
e.as_ptr() as *mut gobject::GValue); e.as_ptr() as *mut gobject::GValue,
} );
} },
Cow::Owned(array) => { Cow::Owned(array) => for e in array {
for e in array { gst::gst_value_array_append_and_take_value(
gst::gst_value_array_append_and_take_value(&mut value.0, &mut value.0,
e.as_ptr() as e.as_ptr() as *mut gobject::GValue,
*mut gobject::GValue); );
mem::forget(e); mem::forget(e);
} },
}
} }
value value
@ -555,7 +560,8 @@ pub struct TypedValue<T> {
} }
impl<'a, T> TypedValue<T> impl<'a, T> TypedValue<T>
where T: ValueType<'a> where
T: ValueType<'a>,
{ {
pub fn new<VT: Into<TypedValue<T>>>(v: VT) -> TypedValue<T> { pub fn new<VT: Into<TypedValue<T>>>(v: VT) -> TypedValue<T> {
v.into() v.into()
@ -567,9 +573,9 @@ impl<'a, T> TypedValue<T>
} }
Some(TypedValue { Some(TypedValue {
value: value, value: value,
phantom: PhantomData, phantom: PhantomData,
}) })
} }
pub fn from_typed_value_ref(v: &'a TypedValueRef<'a, T>) -> TypedValue<T> { pub fn from_typed_value_ref(v: &'a TypedValueRef<'a, T>) -> TypedValue<T> {
@ -611,7 +617,8 @@ impl<'a, T> TypedValue<T>
} }
impl<'a, T> From<T> for TypedValue<T> impl<'a, T> From<T> for TypedValue<T>
where T: ValueType<'a> + Into<Value> where
T: ValueType<'a> + Into<Value>,
{ {
fn from(v: T) -> Self { fn from(v: T) -> Self {
TypedValue::from_value(Value::new(v)).unwrap() TypedValue::from_value(Value::new(v)).unwrap()
@ -667,7 +674,8 @@ pub struct TypedValueRef<'a, T> {
} }
impl<'a, T> TypedValueRef<'a, T> impl<'a, T> TypedValueRef<'a, T>
where T: ValueType<'a> where
T: ValueType<'a>,
{ {
pub fn from_typed_value(v: &'a TypedValue<T>) -> TypedValueRef<'a, T> { pub fn from_typed_value(v: &'a TypedValue<T>) -> TypedValueRef<'a, T> {
TypedValueRef { TypedValueRef {
@ -682,9 +690,9 @@ impl<'a, T> TypedValueRef<'a, T>
} }
Some(TypedValueRef { Some(TypedValueRef {
value: value, value: value,
phantom: PhantomData, phantom: PhantomData,
}) })
} }
pub fn get(&'a self) -> T { pub fn get(&'a self) -> T {