mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-12-22 10:06:29 +00:00
Run everything through rustfmt-nightly
This commit is contained in:
parent
3c27685e38
commit
6f04ddf797
22 changed files with 1175 additions and 909 deletions
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
|
);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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"
|
||||||
|
);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>) {
|
||||||
|
|
|
@ -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,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue