mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-12-26 10:00:32 +00:00
Add support for TypeFind and implement Ord on Rank and TypeFindProbability
Fixes https://github.com/sdroege/gstreamer-rs/issues/11
This commit is contained in:
parent
917255de89
commit
6d8cfa5de0
3 changed files with 336 additions and 0 deletions
|
@ -12,6 +12,9 @@ use PadLinkReturn;
|
|||
use ClockReturn;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::cmp;
|
||||
|
||||
use glib::translate::ToGlib;
|
||||
|
||||
impl StateChangeReturn {
|
||||
pub fn into_result(self) -> Result<StateChangeSuccess, StateChangeError> {
|
||||
|
@ -285,3 +288,29 @@ impl Error for ClockError {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for ::TypeFindProbability {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
self.to_glib().partial_cmp(&other.to_glib())
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ::TypeFindProbability {
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
self.to_glib().cmp(&other.to_glib())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl PartialOrd for ::Rank {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
||||
self.to_glib().partial_cmp(&other.to_glib())
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ::Rank {
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
self.to_glib().cmp(&other.to_glib())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -126,6 +126,9 @@ pub use clock_time::ClockTime;
|
|||
|
||||
mod plugin;
|
||||
|
||||
mod typefind;
|
||||
pub use typefind::*;
|
||||
|
||||
pub mod format;
|
||||
pub use format::{FormattedValue, GenericFormattedValue, SpecificFormattedValue};
|
||||
|
||||
|
|
304
gstreamer/src/typefind.rs
Normal file
304
gstreamer/src/typefind.rs
Normal file
|
@ -0,0 +1,304 @@
|
|||
// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ffi;
|
||||
use Plugin;
|
||||
use TypeFindProbability;
|
||||
use TypeFindFactory;
|
||||
use Caps;
|
||||
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use std::marker::PhantomData;
|
||||
use glib_ffi;
|
||||
use glib::translate::*;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct TypeFind<'a>(ffi::GstTypeFind, PhantomData<&'a ()>);
|
||||
|
||||
pub trait TypeFindImpl {
|
||||
fn peek(&mut self, offset: i64, size: u32) -> Option<&[u8]>;
|
||||
fn suggest(&mut self, probability: TypeFindProbability, caps: &Caps);
|
||||
fn get_length(&self) -> Option<u64> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TypeFind<'a> {
|
||||
pub fn register<
|
||||
'b,
|
||||
'c,
|
||||
'd,
|
||||
P: Into<Option<&'b Plugin>>,
|
||||
R: Into<Option<&'c str>>,
|
||||
S: Into<Option<&'d Caps>>,
|
||||
F,
|
||||
>(
|
||||
plugin: P,
|
||||
name: &str,
|
||||
rank: u32,
|
||||
extensions: R,
|
||||
possible_caps: S,
|
||||
func: F,
|
||||
) -> bool
|
||||
where
|
||||
F: Fn(&mut TypeFind) + Send + Sync + 'static,
|
||||
{
|
||||
let plugin = plugin.into();
|
||||
let extensions = extensions.into();
|
||||
let possible_caps = possible_caps.into();
|
||||
unsafe {
|
||||
let func: Box<Box<Fn(&mut TypeFind) + Send + Sync + 'static>> =
|
||||
Box::new(Box::new(func));
|
||||
let func = Box::into_raw(func);
|
||||
|
||||
from_glib(ffi::gst_type_find_register(
|
||||
plugin.to_glib_none().0,
|
||||
name.to_glib_none().0,
|
||||
rank,
|
||||
Some(type_find_trampoline),
|
||||
extensions.to_glib_none().0,
|
||||
possible_caps.to_glib_none().0,
|
||||
func as *mut _,
|
||||
Some(type_find_closure_drop),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peek(&mut self, offset: i64, size: u32) -> Option<&[u8]> {
|
||||
unsafe {
|
||||
let data = ffi::gst_type_find_peek(&mut self.0, offset, size);
|
||||
if data.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(slice::from_raw_parts(data, size as usize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest(&mut self, probability: TypeFindProbability, caps: &Caps) {
|
||||
unsafe {
|
||||
ffi::gst_type_find_suggest(
|
||||
&mut self.0,
|
||||
probability.to_glib() as u32,
|
||||
caps.to_glib_none().0,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a> Send for TypeFind<'a> {}
|
||||
|
||||
impl TypeFindFactory {
|
||||
pub fn call_function(&self, find: &mut TypeFindImpl) {
|
||||
unsafe {
|
||||
let find_ptr = &find as *const &mut TypeFindImpl as glib_ffi::gpointer;
|
||||
let mut find = ffi::GstTypeFind {
|
||||
peek: Some(type_find_peek),
|
||||
suggest: Some(type_find_suggest),
|
||||
data: find_ptr,
|
||||
get_length: Some(type_find_get_length),
|
||||
_gst_reserved: [ptr::null_mut(); 4],
|
||||
};
|
||||
|
||||
ffi::gst_type_find_factory_call_function(self.to_glib_none().0, &mut find)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn type_find_trampoline(
|
||||
find: *mut ffi::GstTypeFind,
|
||||
user_data: glib_ffi::gpointer,
|
||||
) {
|
||||
callback_guard!();
|
||||
let func: &&(Fn(&mut TypeFind) + Send + Sync + 'static) = mem::transmute(user_data);
|
||||
func(&mut *(find as *mut TypeFind));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn type_find_closure_drop(data: glib_ffi::gpointer) {
|
||||
callback_guard!();
|
||||
Box::<Box<Fn(&mut TypeFind) + Send + Sync + 'static>>::from_raw(data as *mut _);
|
||||
}
|
||||
|
||||
unsafe extern "C" fn type_find_peek(data: glib_ffi::gpointer, offset: i64, size: u32) -> *const u8 {
|
||||
callback_guard!();
|
||||
let find: &mut &mut TypeFindImpl = &mut *(data as *mut &mut TypeFindImpl);
|
||||
match find.peek(offset, size) {
|
||||
None => ptr::null(),
|
||||
Some(data) => data.as_ptr(),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn type_find_suggest(
|
||||
data: glib_ffi::gpointer,
|
||||
probability: u32,
|
||||
caps: *mut ffi::GstCaps,
|
||||
) {
|
||||
callback_guard!();
|
||||
let find: &mut &mut TypeFindImpl = &mut *(data as *mut &mut TypeFindImpl);
|
||||
find.suggest(from_glib(probability as i32), &from_glib_borrow(caps));
|
||||
}
|
||||
|
||||
unsafe extern "C" fn type_find_get_length(data: glib_ffi::gpointer) -> u64 {
|
||||
use std::u64;
|
||||
|
||||
callback_guard!();
|
||||
let find: &mut &mut TypeFindImpl = &mut *(data as *mut &mut TypeFindImpl);
|
||||
find.get_length().unwrap_or(u64::MAX)
|
||||
}
|
||||
|
||||
pub struct SliceTypeFind<T: AsRef<[u8]>> {
|
||||
pub probability: Option<TypeFindProbability>,
|
||||
pub caps: Option<Caps>,
|
||||
data: T,
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> SliceTypeFind<T> {
|
||||
pub fn new(data: T) -> SliceTypeFind<T> {
|
||||
SliceTypeFind {
|
||||
probability: None,
|
||||
caps: None,
|
||||
data: data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
let factories = TypeFindFactory::get_list();
|
||||
|
||||
for factory in factories {
|
||||
factory.call_function(self);
|
||||
if let Some(prob) = self.probability {
|
||||
if prob >= TypeFindProbability::Maximum {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_find(data: T) -> (TypeFindProbability, Option<Caps>) {
|
||||
let mut t = SliceTypeFind {
|
||||
probability: None,
|
||||
caps: None,
|
||||
data: data,
|
||||
};
|
||||
|
||||
t.run();
|
||||
|
||||
(t.probability.unwrap_or(TypeFindProbability::None), t.caps)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> TypeFindImpl for SliceTypeFind<T> {
|
||||
fn peek(&mut self, offset: i64, size: u32) -> Option<&[u8]> {
|
||||
let data = self.data.as_ref();
|
||||
let len = data.len();
|
||||
|
||||
let offset = if offset >= 0 {
|
||||
offset as usize
|
||||
} else {
|
||||
if len < offset.abs() as usize {
|
||||
return None;
|
||||
}
|
||||
|
||||
len - (offset.abs() as usize)
|
||||
};
|
||||
|
||||
let size = size as usize;
|
||||
if offset + size <= len {
|
||||
Some(&data[offset..(offset + size)])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn suggest(&mut self, probability: TypeFindProbability, caps: &Caps) {
|
||||
match self.probability {
|
||||
None => {
|
||||
self.probability = Some(probability);
|
||||
self.caps = Some(caps.clone());
|
||||
}
|
||||
Some(old_probability) if old_probability < probability => {
|
||||
self.probability = Some(probability);
|
||||
self.caps = Some(caps.clone());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
fn get_length(&self) -> Option<u64> {
|
||||
Some(self.data.as_ref().len() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_typefind_call_function() {
|
||||
::init().unwrap();
|
||||
|
||||
let xml_factory = TypeFindFactory::get_list()
|
||||
.iter()
|
||||
.cloned()
|
||||
.find(|f| {
|
||||
f.get_caps()
|
||||
.map(|c| {
|
||||
c.get_structure(0).unwrap().get_name() == "application/xml"
|
||||
})
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let data = b"<?xml version=\"1.0\"?><test>test</test>";
|
||||
let data = &data[..];
|
||||
let mut typefind = SliceTypeFind::new(&data);
|
||||
xml_factory.call_function(&mut typefind);
|
||||
|
||||
assert_eq!(
|
||||
typefind.caps,
|
||||
Some(Caps::new_simple("application/xml", &[]))
|
||||
);
|
||||
assert_eq!(typefind.probability, Some(TypeFindProbability::Minimum));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_typefind_register() {
|
||||
::init().unwrap();
|
||||
|
||||
TypeFind::register(
|
||||
None,
|
||||
"test_typefind",
|
||||
::Rank::Primary.to_glib() as u32,
|
||||
None,
|
||||
&Caps::new_simple("test/test", &[]),
|
||||
|typefind| {
|
||||
let mut found = false;
|
||||
if let Some(data) = typefind.peek(0, 8) {
|
||||
if data == b"abcdefgh" {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
typefind.suggest(
|
||||
TypeFindProbability::Likely,
|
||||
&Caps::new_simple("test/test", &[]),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let data = b"abcdefgh";
|
||||
let data = &data[..];
|
||||
let (probability, caps) = SliceTypeFind::type_find(&data);
|
||||
|
||||
assert_eq!(caps, Some(Caps::new_simple("test/test", &[])));
|
||||
assert_eq!(probability, TypeFindProbability::Likely);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue