mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-05-20 17:28:49 +00:00
Add support for Speex to FLV demuxer
... and arrays of values in caps while at the same time refactoring the Value code a bit.
This commit is contained in:
parent
2ce9aa7b58
commit
93f09c8a4a
|
@ -16,6 +16,7 @@
|
|||
// Boston, MA 02110-1301, USA.
|
||||
|
||||
use std::cmp;
|
||||
use std::io::{Write, Cursor};
|
||||
|
||||
use nom;
|
||||
use nom::IResult;
|
||||
|
@ -31,6 +32,7 @@ use gst_plugin::utils::Element;
|
|||
use gst_plugin::log::*;
|
||||
use gst_plugin::caps::Caps;
|
||||
use gst_plugin::caps;
|
||||
use gst_plugin::bytes::*;
|
||||
|
||||
use slog::*;
|
||||
|
||||
|
@ -195,8 +197,42 @@ impl AudioFormat {
|
|||
})
|
||||
}
|
||||
flavors::SoundFormat::SPEEX => {
|
||||
// TODO: This requires creating a Speex streamheader...
|
||||
None
|
||||
let mut header = Buffer::new_with_size(80).unwrap();
|
||||
{
|
||||
let mut map = header.map_readwrite().unwrap();
|
||||
let mut data = Cursor::new(map.as_mut_slice());
|
||||
data.write(b"Speex 1.1.12").unwrap();
|
||||
data.write(&[0; 14]).unwrap();
|
||||
data.write_u32le(1).unwrap(); // version
|
||||
data.write_u32le(80).unwrap(); // header size
|
||||
data.write_u32le(16000).unwrap(); // sample rate
|
||||
data.write_u32le(1).unwrap(); // mode = wideband
|
||||
data.write_u32le(4).unwrap(); // mode bitstream version
|
||||
data.write_u32le(1).unwrap(); // channels
|
||||
data.write_i32le(-1).unwrap(); // bitrate
|
||||
data.write_u32le(0x50).unwrap(); // frame size
|
||||
data.write_u32le(0).unwrap(); // VBR
|
||||
data.write_u32le(1).unwrap(); // frames per packet
|
||||
data.write_u32le(0).unwrap(); // extra headers
|
||||
data.write_u32le(0).unwrap(); // reserved 1
|
||||
data.write_u32le(0).unwrap(); // reserved 2
|
||||
}
|
||||
|
||||
let comment_size = 4 + 7 /* nothing */ + 4 + 1;
|
||||
|
||||
let mut comment = Buffer::new_with_size(comment_size).unwrap();
|
||||
{
|
||||
let mut map = comment.map_readwrite().unwrap();
|
||||
let mut data = Cursor::new(map.as_mut_slice());
|
||||
data.write_u32le(7).unwrap(); // length of "nothing"
|
||||
data.write(b"nothing").unwrap(); // "vendor" string
|
||||
data.write_u32le(0).unwrap(); // number of elements
|
||||
data.write_u8(1);
|
||||
}
|
||||
Some(Caps::new_simple("audio/x-speex",
|
||||
&[("streamheader",
|
||||
&caps::Value::Array(vec![caps::Value::Buffer(header),
|
||||
caps::Value::Buffer(comment)]))]))
|
||||
}
|
||||
flavors::SoundFormat::DEVICE_SPECIFIC => {
|
||||
// Nobody knows
|
||||
|
|
|
@ -12,6 +12,7 @@ url = "1.1"
|
|||
bitflags = "0.7"
|
||||
slog = { version = "1.3", features = ["max_level_trace"] }
|
||||
lazy_static = "0.2"
|
||||
byteorder = "1.0"
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3"
|
||||
|
|
149
gst-plugin/src/bytes.rs
Normal file
149
gst-plugin/src/bytes.rs
Normal file
|
@ -0,0 +1,149 @@
|
|||
// Copyright (C) 2016 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the
|
||||
// Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
// Boston, MA 02110-1301, USA.
|
||||
|
||||
pub use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
|
||||
use std::io;
|
||||
|
||||
pub trait ReadBytesExtShort: io::Read {
|
||||
fn read_u16le(&mut self) -> io::Result<u16> {
|
||||
self.read_u16::<LittleEndian>()
|
||||
}
|
||||
fn read_i16le(&mut self) -> io::Result<i16> {
|
||||
self.read_i16::<LittleEndian>()
|
||||
}
|
||||
fn read_u32le(&mut self) -> io::Result<u32> {
|
||||
self.read_u32::<LittleEndian>()
|
||||
}
|
||||
fn read_i32le(&mut self) -> io::Result<i32> {
|
||||
self.read_i32::<LittleEndian>()
|
||||
}
|
||||
fn read_u64le(&mut self) -> io::Result<u64> {
|
||||
self.read_u64::<LittleEndian>()
|
||||
}
|
||||
fn read_i64le(&mut self) -> io::Result<i64> {
|
||||
self.read_i64::<LittleEndian>()
|
||||
}
|
||||
fn read_uintle(&mut self, nbytes: usize) -> io::Result<u64> {
|
||||
self.read_uint::<LittleEndian>(nbytes)
|
||||
}
|
||||
fn read_intle(&mut self, nbytes: usize) -> io::Result<i64> {
|
||||
self.read_int::<LittleEndian>(nbytes)
|
||||
}
|
||||
fn read_f32le(&mut self) -> io::Result<f32> {
|
||||
self.read_f32::<LittleEndian>()
|
||||
}
|
||||
fn read_f64le(&mut self) -> io::Result<f64> {
|
||||
self.read_f64::<LittleEndian>()
|
||||
}
|
||||
fn read_u16be(&mut self) -> io::Result<u16> {
|
||||
self.read_u16::<BigEndian>()
|
||||
}
|
||||
fn read_i16be(&mut self) -> io::Result<i16> {
|
||||
self.read_i16::<BigEndian>()
|
||||
}
|
||||
fn read_u32be(&mut self) -> io::Result<u32> {
|
||||
self.read_u32::<BigEndian>()
|
||||
}
|
||||
fn read_i32be(&mut self) -> io::Result<i32> {
|
||||
self.read_i32::<BigEndian>()
|
||||
}
|
||||
fn read_u64be(&mut self) -> io::Result<u64> {
|
||||
self.read_u64::<BigEndian>()
|
||||
}
|
||||
fn read_i64be(&mut self) -> io::Result<i64> {
|
||||
self.read_i64::<BigEndian>()
|
||||
}
|
||||
fn read_uintbe(&mut self, nbytes: usize) -> io::Result<u64> {
|
||||
self.read_uint::<BigEndian>(nbytes)
|
||||
}
|
||||
fn read_intbe(&mut self, nbytes: usize) -> io::Result<i64> {
|
||||
self.read_int::<BigEndian>(nbytes)
|
||||
}
|
||||
fn read_f32be(&mut self) -> io::Result<f32> {
|
||||
self.read_f32::<BigEndian>()
|
||||
}
|
||||
fn read_f64be(&mut self) -> io::Result<f64> {
|
||||
self.read_f64::<BigEndian>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ReadBytesExtShort for T where T: ReadBytesExt {}
|
||||
|
||||
pub trait WriteBytesExtShort: WriteBytesExt {
|
||||
fn write_u16le(&mut self, n: u16) -> io::Result<()> {
|
||||
self.write_u16::<LittleEndian>(n)
|
||||
}
|
||||
fn write_i16le(&mut self, n: i16) -> io::Result<()> {
|
||||
self.write_i16::<LittleEndian>(n)
|
||||
}
|
||||
fn write_u32le(&mut self, n: u32) -> io::Result<()> {
|
||||
self.write_u32::<LittleEndian>(n)
|
||||
}
|
||||
fn write_i32le(&mut self, n: i32) -> io::Result<()> {
|
||||
self.write_i32::<LittleEndian>(n)
|
||||
}
|
||||
fn write_u64le(&mut self, n: u64) -> io::Result<()> {
|
||||
self.write_u64::<LittleEndian>(n)
|
||||
}
|
||||
fn write_i64le(&mut self, n: i64) -> io::Result<()> {
|
||||
self.write_i64::<LittleEndian>(n)
|
||||
}
|
||||
fn write_uintle(&mut self, n: u64, nbytes: usize) -> io::Result<()> {
|
||||
self.write_uint::<LittleEndian>(n, nbytes)
|
||||
}
|
||||
fn write_intle(&mut self, n: i64, nbytes: usize) -> io::Result<()> {
|
||||
self.write_int::<LittleEndian>(n, nbytes)
|
||||
}
|
||||
fn write_f32le(&mut self, n: f32) -> io::Result<()> {
|
||||
self.write_f32::<LittleEndian>(n)
|
||||
}
|
||||
fn write_f64le(&mut self, n: f64) -> io::Result<()> {
|
||||
self.write_f64::<LittleEndian>(n)
|
||||
}
|
||||
fn write_u16be(&mut self, n: u16) -> io::Result<()> {
|
||||
self.write_u16::<BigEndian>(n)
|
||||
}
|
||||
fn write_i16be(&mut self, n: i16) -> io::Result<()> {
|
||||
self.write_i16::<BigEndian>(n)
|
||||
}
|
||||
fn write_u32be(&mut self, n: u32) -> io::Result<()> {
|
||||
self.write_u32::<BigEndian>(n)
|
||||
}
|
||||
fn write_i32be(&mut self, n: i32) -> io::Result<()> {
|
||||
self.write_i32::<BigEndian>(n)
|
||||
}
|
||||
fn write_u64be(&mut self, n: u64) -> io::Result<()> {
|
||||
self.write_u64::<BigEndian>(n)
|
||||
}
|
||||
fn write_i64be(&mut self, n: i64) -> io::Result<()> {
|
||||
self.write_i64::<BigEndian>(n)
|
||||
}
|
||||
fn write_uintbe(&mut self, n: u64, nbytes: usize) -> io::Result<()> {
|
||||
self.write_uint::<BigEndian>(n, nbytes)
|
||||
}
|
||||
fn write_intbe(&mut self, n: i64, nbytes: usize) -> io::Result<()> {
|
||||
self.write_int::<BigEndian>(n, nbytes)
|
||||
}
|
||||
fn write_f32be(&mut self, n: f32) -> io::Result<()> {
|
||||
self.write_f32::<BigEndian>(n)
|
||||
}
|
||||
fn write_f64be(&mut self, n: f64) -> io::Result<()> {
|
||||
self.write_f64::<BigEndian>(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> WriteBytesExtShort for T where T: WriteBytesExt {}
|
|
@ -20,18 +20,18 @@ use std::os::raw::c_void;
|
|||
use std::ffi::CString;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
|
||||
use buffer::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Value<'a> {
|
||||
pub enum Value {
|
||||
Bool(bool),
|
||||
Int(i32),
|
||||
String(Cow<'a, str>),
|
||||
String(String),
|
||||
Fraction(i32, i32),
|
||||
Buffer(Buffer),
|
||||
Array(Vec<Value>),
|
||||
}
|
||||
|
||||
pub struct Caps(*mut c_void);
|
||||
|
@ -47,6 +47,75 @@ const TYPE_BOOLEAN: usize = (5 << 2);
|
|||
const TYPE_INT: usize = (6 << 2);
|
||||
const TYPE_STRING: usize = (16 << 2);
|
||||
|
||||
impl Value {
|
||||
fn to_gvalue(&self) -> GValue {
|
||||
extern "C" {
|
||||
fn g_value_init(value: *mut GValue, gtype: usize);
|
||||
fn g_value_set_boolean(value: *mut GValue, value: i32);
|
||||
fn g_value_set_int(value: *mut GValue, value: i32);
|
||||
fn g_value_set_string(value: *mut GValue, value: *const c_char);
|
||||
fn gst_value_set_fraction(value: *mut GValue, value_n: i32, value_d: i32);
|
||||
fn gst_fraction_get_type() -> usize;
|
||||
fn g_value_set_boxed(value: *mut GValue, boxed: *const c_void);
|
||||
fn gst_buffer_get_type() -> usize;
|
||||
fn gst_value_array_get_type() -> usize;
|
||||
fn gst_value_array_append_and_take_value(value: *mut GValue, element: *mut GValue);
|
||||
}
|
||||
|
||||
let mut gvalue: GValue = unsafe { mem::zeroed() };
|
||||
|
||||
match *self {
|
||||
Value::Bool(v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_BOOLEAN);
|
||||
g_value_set_boolean(&mut gvalue as *mut GValue, if v { 1 } else { 0 });
|
||||
},
|
||||
Value::Int(v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_INT);
|
||||
g_value_set_int(&mut gvalue as *mut GValue, v);
|
||||
},
|
||||
Value::String(ref v) => unsafe {
|
||||
let v_cstr = CString::new(String::from(v.clone())).unwrap();
|
||||
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_STRING);
|
||||
g_value_set_string(&mut gvalue as *mut GValue, v_cstr.as_ptr());
|
||||
},
|
||||
Value::Fraction(v_n, v_d) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, gst_fraction_get_type());
|
||||
gst_value_set_fraction(&mut gvalue as *mut GValue, v_n, v_d);
|
||||
},
|
||||
Value::Buffer(ref buffer) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, gst_buffer_get_type());
|
||||
g_value_set_boxed(&mut gvalue as *mut GValue, buffer.as_ptr());
|
||||
},
|
||||
Value::Array(ref array) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, gst_value_array_get_type());
|
||||
|
||||
for e in array {
|
||||
let mut e_value = e.to_gvalue();
|
||||
gst_value_array_append_and_take_value(&mut gvalue as *mut GValue,
|
||||
&mut e_value as *mut GValue);
|
||||
// Takes ownership, invalidate GValue
|
||||
e_value.typ = 0;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
gvalue
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GValue {
|
||||
fn drop(&mut self) {
|
||||
extern "C" {
|
||||
fn g_value_unset(value: *mut GValue);
|
||||
}
|
||||
|
||||
if self.typ != 0 {
|
||||
unsafe { g_value_unset(self as *mut GValue) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Caps {
|
||||
pub fn new_empty() -> Self {
|
||||
extern "C" {
|
||||
|
@ -64,7 +133,7 @@ impl Caps {
|
|||
Caps(unsafe { gst_caps_new_any() })
|
||||
}
|
||||
|
||||
pub fn new_simple<'a>(name: &str, values: &[(&'a str, &'a Value<'a>)]) -> Self {
|
||||
pub fn new_simple(name: &str, values: &[(&str, &Value)]) -> Self {
|
||||
extern "C" {
|
||||
fn gst_caps_append_structure(caps: *mut c_void, structure: *mut c_void);
|
||||
fn gst_structure_new_empty(name: *const c_char) -> *mut c_void;
|
||||
|
@ -103,54 +172,14 @@ impl Caps {
|
|||
pub fn set_simple(&mut self, values: &[(&str, &Value)]) {
|
||||
extern "C" {
|
||||
fn gst_caps_set_value(caps: *mut c_void, name: *const c_char, value: *const GValue);
|
||||
fn g_value_init(value: *mut GValue, gtype: usize);
|
||||
fn g_value_unset(value: *mut GValue);
|
||||
fn g_value_set_boolean(value: *mut GValue, value: i32);
|
||||
fn g_value_set_int(value: *mut GValue, value: i32);
|
||||
fn g_value_set_string(value: *mut GValue, value: *const c_char);
|
||||
fn gst_value_set_fraction(value: *mut GValue, value_n: i32, value_d: i32);
|
||||
fn gst_fraction_get_type() -> usize;
|
||||
fn g_value_set_boxed(value: *mut GValue, boxed: *const c_void);
|
||||
fn gst_buffer_get_type() -> usize;
|
||||
}
|
||||
|
||||
for value in values {
|
||||
let name_cstr = CString::new(value.0).unwrap();
|
||||
let mut gvalue: GValue = unsafe { mem::zeroed() };
|
||||
let mut gvalue = value.1.to_gvalue();
|
||||
|
||||
match *value.1 {
|
||||
Value::Bool(v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_BOOLEAN);
|
||||
g_value_set_boolean(&mut gvalue as *mut GValue, if v { 1 } else { 0 });
|
||||
gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
|
||||
g_value_unset(&mut gvalue as *mut GValue);
|
||||
},
|
||||
Value::Int(v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_INT);
|
||||
g_value_set_int(&mut gvalue as *mut GValue, v);
|
||||
gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
|
||||
g_value_unset(&mut gvalue as *mut GValue);
|
||||
},
|
||||
Value::String(ref v) => unsafe {
|
||||
let v_cstr = CString::new(String::from((*v).clone())).unwrap();
|
||||
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_STRING);
|
||||
g_value_set_string(&mut gvalue as *mut GValue, v_cstr.as_ptr());
|
||||
gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
|
||||
g_value_unset(&mut gvalue as *mut GValue);
|
||||
},
|
||||
Value::Fraction(v_n, v_d) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, gst_fraction_get_type());
|
||||
gst_value_set_fraction(&mut gvalue as *mut GValue, v_n, v_d);
|
||||
gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
|
||||
g_value_unset(&mut gvalue as *mut GValue);
|
||||
},
|
||||
Value::Buffer(ref buffer) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, gst_buffer_get_type());
|
||||
g_value_set_boxed(&mut gvalue as *mut GValue, buffer.as_ptr());
|
||||
gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
|
||||
g_value_unset(&mut gvalue as *mut GValue);
|
||||
},
|
||||
unsafe {
|
||||
gst_caps_set_value(self.0, name_cstr.as_ptr(), &mut gvalue as *mut GValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,6 +224,16 @@ impl Clone for Caps {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for Caps {
|
||||
fn drop(&mut self) {
|
||||
extern "C" {
|
||||
fn gst_mini_object_unref(mini_object: *mut c_void);
|
||||
}
|
||||
|
||||
unsafe { gst_mini_object_unref(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Caps {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(&self.to_string())
|
||||
|
@ -222,12 +261,14 @@ mod tests {
|
|||
init();
|
||||
|
||||
let caps = Caps::new_simple("foo/bar",
|
||||
vec![("int", &Value::Int(12)),
|
||||
("bool", &Value::Bool(true)),
|
||||
("string", &Value::String("bla".into())),
|
||||
("fraction", &Value::Fraction(1, 2))]);
|
||||
&[("int", &Value::Int(12)),
|
||||
("bool", &Value::Bool(true)),
|
||||
("string", &Value::String("bla".into())),
|
||||
("fraction", &Value::Fraction(1, 2)),
|
||||
("array",
|
||||
&Value::Array(vec![Value::Int(1), Value::Int(2)]))]);
|
||||
assert_eq!(caps.to_string(),
|
||||
"foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, \
|
||||
fraction=(fraction)1/2");
|
||||
fraction=(fraction)1/2, array=(int)< 1, 2 >");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ extern crate bitflags;
|
|||
extern crate slog;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate byteorder;
|
||||
|
||||
#[macro_use]
|
||||
pub mod utils;
|
||||
|
@ -38,3 +39,4 @@ pub mod sink;
|
|||
pub mod demuxer;
|
||||
pub mod log;
|
||||
pub mod caps;
|
||||
pub mod bytes;
|
||||
|
|
Loading…
Reference in a new issue