mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-12-20 00:56:30 +00:00
Implement a minimal GstCaps binding and use it in the demuxer
This commit is contained in:
parent
ec0539de0a
commit
e26cdc9187
5 changed files with 282 additions and 71 deletions
|
@ -29,6 +29,8 @@ use gst_plugin::adapter::*;
|
|||
use gst_plugin::utils;
|
||||
use gst_plugin::utils::Element;
|
||||
use gst_plugin::log::*;
|
||||
use gst_plugin::caps::Caps;
|
||||
use gst_plugin::caps;
|
||||
|
||||
use slog::*;
|
||||
|
||||
|
@ -134,29 +136,46 @@ impl AudioFormat {
|
|||
}
|
||||
|
||||
fn to_string(&self) -> Option<String> {
|
||||
let mut format = match self.format {
|
||||
self.to_caps().map(|c| c.to_string())
|
||||
}
|
||||
|
||||
fn to_caps(&self) -> Option<Caps> {
|
||||
let mut caps = match self.format {
|
||||
flavors::SoundFormat::MP3 |
|
||||
flavors::SoundFormat::MP3_8KHZ => {
|
||||
Some(String::from("audio/mpeg, mpegversion=(int) 1, layer=(int) 3"))
|
||||
Some(Caps::new_simple("audio/mpeg",
|
||||
vec![("mpegversion", &caps::Value::Int(1)),
|
||||
("layer", &caps::Value::Int(3))]))
|
||||
}
|
||||
flavors::SoundFormat::PCM_BE |
|
||||
flavors::SoundFormat::PCM_LE => {
|
||||
if self.rate != 0 && self.channels != 0 {
|
||||
// Assume little-endian for "PCM_NE", it's probably more common and we have no
|
||||
// way to know what the endianness of the system creating the stream was
|
||||
Some(format!("audio/x-raw, layout=(string) interleaved, \
|
||||
format=(string) {}",
|
||||
if self.width == 8 { "U8" } else { "S16LE" }))
|
||||
Some(Caps::new_simple("audio/x-raw",
|
||||
vec![("layout",
|
||||
&caps::Value::String("interleaved".into())),
|
||||
("format",
|
||||
&caps::Value::String(if self.width == 8 {
|
||||
"U8".into()
|
||||
} else {
|
||||
"S16LE".into()
|
||||
}))]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
flavors::SoundFormat::ADPCM => Some(String::from("audio/x-adpcm, layout=(string) swf")),
|
||||
flavors::SoundFormat::ADPCM => {
|
||||
Some(Caps::new_simple("audio/x-adpcm",
|
||||
vec![("layout", &caps::Value::String("swf".into()))]))
|
||||
}
|
||||
flavors::SoundFormat::NELLYMOSER_16KHZ_MONO |
|
||||
flavors::SoundFormat::NELLYMOSER_8KHZ_MONO |
|
||||
flavors::SoundFormat::NELLYMOSER => Some(String::from("audio/x-nellymoser")),
|
||||
flavors::SoundFormat::PCM_ALAW => Some(String::from("audio/x-alaw")),
|
||||
flavors::SoundFormat::PCM_ULAW => Some(String::from("audio/x-mulaw")),
|
||||
flavors::SoundFormat::NELLYMOSER => {
|
||||
Some(Caps::new_simple("audio/x-nellymoser", vec![]))
|
||||
}
|
||||
flavors::SoundFormat::PCM_ALAW => Some(Caps::new_simple("audio/x-alaw", vec![])),
|
||||
flavors::SoundFormat::PCM_ULAW => Some(Caps::new_simple("audio/x-mulaw", vec![])),
|
||||
flavors::SoundFormat::AAC => {
|
||||
// TODO: This requires getting the codec config from the stream
|
||||
None
|
||||
|
@ -172,13 +191,15 @@ impl AudioFormat {
|
|||
};
|
||||
|
||||
if self.rate != 0 {
|
||||
format.as_mut().map(|f| f.push_str(&format!(", rate=(int) {}", self.rate)));
|
||||
caps.as_mut()
|
||||
.map(|c| c.set_simple(vec![("rate", &caps::Value::Int(self.rate as i32))]));
|
||||
}
|
||||
if self.channels != 0 {
|
||||
format.as_mut().map(|f| f.push_str(&format!(", channels=(int) {}", self.channels)));
|
||||
caps.as_mut()
|
||||
.map(|c| c.set_simple(vec![("channels", &caps::Value::Int(self.channels as i32))]));
|
||||
}
|
||||
|
||||
format
|
||||
caps
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,12 +257,19 @@ impl VideoFormat {
|
|||
}
|
||||
|
||||
fn to_string(&self) -> Option<String> {
|
||||
let mut format = match self.format {
|
||||
flavors::CodecId::H263 => Some(String::from("video/x-flash-video, flvversion=(int) 1")),
|
||||
flavors::CodecId::SCREEN => Some(String::from("video/x-flash-screen")),
|
||||
flavors::CodecId::VP6 => Some(String::from("video/x-vp6-flash")),
|
||||
flavors::CodecId::VP6A => Some(String::from("video/x-vp6-alpha")),
|
||||
flavors::CodecId::SCREEN2 => Some(String::from("video/x-flash-screen2")),
|
||||
self.to_caps().map(|caps| caps.to_string())
|
||||
}
|
||||
|
||||
fn to_caps(&self) -> Option<Caps> {
|
||||
let mut caps = match self.format {
|
||||
flavors::CodecId::H263 => {
|
||||
Some(Caps::new_simple("video/x-flash-video",
|
||||
vec![("flvversion", &caps::Value::Int(1))]))
|
||||
}
|
||||
flavors::CodecId::SCREEN => Some(Caps::new_simple("video/x-flash-screen", vec![])),
|
||||
flavors::CodecId::VP6 => Some(Caps::new_simple("video/x-vp6-flash", vec![])),
|
||||
flavors::CodecId::VP6A => Some(Caps::new_simple("video/x-vp6-flash-alpha", vec![])),
|
||||
flavors::CodecId::SCREEN2 => Some(Caps::new_simple("video/x-flash-screen2", vec![])),
|
||||
flavors::CodecId::H264 => {
|
||||
// TODO: Need codec_data from the stream
|
||||
None
|
||||
|
@ -253,26 +281,31 @@ impl VideoFormat {
|
|||
};
|
||||
|
||||
if let (Some(width), Some(height)) = (self.width, self.height) {
|
||||
format.as_mut()
|
||||
.map(|f| f.push_str(&format!(", width=(int) {}, height=(int) {}", width, height)));
|
||||
caps.as_mut().map(|c| {
|
||||
c.set_simple(vec![("width", &caps::Value::Int(width as i32)),
|
||||
("height", &caps::Value::Int(height as i32))])
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(par) = self.pixel_aspect_ratio {
|
||||
if par.0 != 0 && par.1 != 0 {
|
||||
format.as_mut().map(|f| {
|
||||
f.push_str(&format!(", pixel-aspect-ratio=(fraction) {}/{}", par.0, par.1))
|
||||
caps.as_mut().map(|c| {
|
||||
c.set_simple(vec![("pixel-aspect-ratio",
|
||||
&caps::Value::Fraction(par.0 as i32, par.1 as i32))])
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(fps) = self.framerate {
|
||||
if fps.1 != 0 {
|
||||
format.as_mut()
|
||||
.map(|f| f.push_str(&format!(", framerate=(fraction) {}/{}", fps.0, fps.1)));
|
||||
caps.as_mut().map(|c| {
|
||||
c.set_simple(vec![("framerate",
|
||||
&caps::Value::Fraction(fps.0 as i32, fps.1 as i32))])
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
format
|
||||
caps
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,21 +481,17 @@ impl FlvDemux {
|
|||
let mut streams = Vec::new();
|
||||
|
||||
if audio_changed {
|
||||
if let Some(format) = streaming_state.audio
|
||||
if let Some(caps) = streaming_state.audio
|
||||
.as_ref()
|
||||
.and_then(|a| a.to_string()) {
|
||||
streams.push(Stream::new(AUDIO_STREAM_ID,
|
||||
format,
|
||||
String::from("audio")));
|
||||
.and_then(|a| a.to_caps()) {
|
||||
streams.push(Stream::new(AUDIO_STREAM_ID, caps, String::from("audio")));
|
||||
}
|
||||
}
|
||||
if video_changed {
|
||||
if let Some(format) = streaming_state.video
|
||||
if let Some(caps) = streaming_state.video
|
||||
.as_ref()
|
||||
.and_then(|v| v.to_string()) {
|
||||
streams.push(Stream::new(VIDEO_STREAM_ID,
|
||||
format,
|
||||
String::from("video")));
|
||||
.and_then(|v| v.to_caps()) {
|
||||
streams.push(Stream::new(VIDEO_STREAM_ID, caps, String::from("video")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,10 +524,10 @@ impl FlvDemux {
|
|||
debug!(logger, "Got new audio format: {:?}", new_audio_format);
|
||||
let new_stream = streaming_state.audio == None;
|
||||
|
||||
let format = new_audio_format.to_string();
|
||||
if let Some(format) = format {
|
||||
let caps = new_audio_format.to_caps();
|
||||
if let Some(caps) = caps {
|
||||
streaming_state.audio = Some(new_audio_format);
|
||||
let stream = Stream::new(AUDIO_STREAM_ID, format, String::from("audio"));
|
||||
let stream = Stream::new(AUDIO_STREAM_ID, caps, String::from("audio"));
|
||||
if new_stream {
|
||||
return Ok(HandleBufferResult::StreamAdded(stream));
|
||||
} else {
|
||||
|
@ -564,10 +593,10 @@ impl FlvDemux {
|
|||
|
||||
let new_stream = streaming_state.video == None;
|
||||
|
||||
let format = new_video_format.to_string();
|
||||
if let Some(format) = format {
|
||||
let caps = new_video_format.to_caps();
|
||||
if let Some(caps) = caps {
|
||||
streaming_state.video = Some(new_video_format);
|
||||
let stream = Stream::new(VIDEO_STREAM_ID, format, String::from("video"));
|
||||
let stream = Stream::new(VIDEO_STREAM_ID, caps, String::from("video"));
|
||||
if new_stream {
|
||||
return Ok(HandleBufferResult::StreamAdded(stream));
|
||||
} else {
|
||||
|
|
191
gst-plugin/src/caps.rs
Normal file
191
gst-plugin/src/caps.rs
Normal file
|
@ -0,0 +1,191 @@
|
|||
// 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.
|
||||
|
||||
use libc::c_char;
|
||||
use std::os::raw::c_void;
|
||||
use std::ffi::CString;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Value<'a> {
|
||||
Bool(bool),
|
||||
Int(i32),
|
||||
String(Cow<'a, str>),
|
||||
Fraction(i32, i32),
|
||||
}
|
||||
|
||||
pub struct Caps(*mut c_void);
|
||||
|
||||
#[repr(C)]
|
||||
struct GValue {
|
||||
typ: usize,
|
||||
data: [u64; 2],
|
||||
}
|
||||
|
||||
// See gtype.h
|
||||
const TYPE_BOOLEAN: usize = (5 << 2);
|
||||
const TYPE_INT: usize = (6 << 2);
|
||||
const TYPE_STRING: usize = (16 << 2);
|
||||
|
||||
impl Caps {
|
||||
pub fn new_simple(name: &str, values: Vec<(&str, &Value)>) -> Self {
|
||||
extern "C" {
|
||||
fn gst_caps_new_empty() -> *mut c_void;
|
||||
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;
|
||||
}
|
||||
|
||||
let mut caps = Caps(unsafe { gst_caps_new_empty() });
|
||||
|
||||
let name_cstr = CString::new(name).unwrap();
|
||||
let structure = unsafe { gst_structure_new_empty(name_cstr.as_ptr()) };
|
||||
|
||||
unsafe {
|
||||
gst_caps_append_structure(caps.0, structure);
|
||||
}
|
||||
|
||||
caps.set_simple(values);
|
||||
|
||||
caps
|
||||
}
|
||||
|
||||
pub fn set_simple(&mut self, values: Vec<(&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;
|
||||
}
|
||||
|
||||
for value in values {
|
||||
let name_cstr = CString::new(value.0).unwrap();
|
||||
let mut gvalue: GValue = unsafe { mem::zeroed() };
|
||||
|
||||
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);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
extern "C" {
|
||||
fn gst_caps_to_string(caps: *mut c_void) -> *mut c_char;
|
||||
}
|
||||
|
||||
unsafe { CStr::from_ptr(gst_caps_to_string(self.0)).to_string_lossy().into_owned() }
|
||||
}
|
||||
|
||||
pub unsafe fn as_ptr(&self) -> *const c_void {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn make_writable(self: Caps) -> Caps {
|
||||
extern "C" {
|
||||
fn gst_mini_object_make_writable(obj: *mut c_void) -> *mut c_void;
|
||||
}
|
||||
|
||||
let raw = unsafe { gst_mini_object_make_writable(self.0) };
|
||||
|
||||
Caps(raw)
|
||||
}
|
||||
|
||||
pub fn copy(&self) -> Caps {
|
||||
extern "C" {
|
||||
fn gst_mini_object_copy(obj: *const c_void) -> *mut c_void;
|
||||
}
|
||||
unsafe { Caps(gst_mini_object_copy(self.0)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Caps {
|
||||
fn clone(&self) -> Self {
|
||||
extern "C" {
|
||||
fn gst_mini_object_ref(mini_object: *mut c_void) -> *mut c_void;
|
||||
}
|
||||
|
||||
unsafe { Caps(gst_mini_object_ref(self.0)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Caps {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::ptr;
|
||||
use std::os::raw::c_void;
|
||||
|
||||
fn init() {
|
||||
extern "C" {
|
||||
fn gst_init(argc: *mut c_void, argv: *mut c_void);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
gst_init(ptr::null_mut(), ptr::null_mut());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simple() {
|
||||
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))]);
|
||||
assert_eq!(caps.to_string(),
|
||||
"foo/bar, int=(int)12, bool=(boolean)true, string=(string)bla, \
|
||||
fraction=(fraction)1/2");
|
||||
}
|
||||
}
|
|
@ -381,18 +381,18 @@ gst_rs_demuxer_loop (GstRsDemuxer * demuxer)
|
|||
|
||||
void
|
||||
gst_rs_demuxer_add_stream (GstRsDemuxer * demuxer, guint32 index,
|
||||
const gchar * format, const gchar * stream_id)
|
||||
GstCaps * caps, const gchar * stream_id)
|
||||
{
|
||||
GstPad *pad;
|
||||
GstPadTemplate *templ;
|
||||
GstCaps *caps;
|
||||
GstEvent *event;
|
||||
gchar *name, *full_stream_id;
|
||||
|
||||
g_assert (demuxer->srcpads[index] == NULL);
|
||||
|
||||
GST_DEBUG_OBJECT (demuxer, "Adding stream %u with format %s and stream id %s",
|
||||
index, format, stream_id);
|
||||
GST_DEBUG_OBJECT (demuxer,
|
||||
"Adding stream %u with format %" GST_PTR_FORMAT " and stream id %s",
|
||||
index, caps, stream_id);
|
||||
|
||||
templ =
|
||||
gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (demuxer),
|
||||
|
@ -414,9 +414,7 @@ gst_rs_demuxer_add_stream (GstRsDemuxer * demuxer, guint32 index,
|
|||
g_free (full_stream_id);
|
||||
gst_pad_push_event (pad, event);
|
||||
|
||||
caps = gst_caps_from_string (format);
|
||||
event = gst_event_new_caps (caps);
|
||||
gst_caps_unref (caps);
|
||||
gst_pad_push_event (pad, event);
|
||||
|
||||
event = gst_event_new_segment (&demuxer->segment);
|
||||
|
@ -438,18 +436,16 @@ gst_rs_demuxer_added_all_streams (GstRsDemuxer * demuxer)
|
|||
|
||||
void
|
||||
gst_rs_demuxer_stream_format_changed (GstRsDemuxer * demuxer, guint32 index,
|
||||
const gchar * format)
|
||||
GstCaps * caps)
|
||||
{
|
||||
GstCaps *caps;
|
||||
GstEvent *event;
|
||||
|
||||
g_assert (demuxer->srcpads[index] != NULL);
|
||||
|
||||
GST_DEBUG_OBJECT (demuxer, "Format changed for stream %u: %s", index, format);
|
||||
GST_DEBUG_OBJECT (demuxer, "Format changed for stream %u: %" GST_PTR_FORMAT,
|
||||
index, caps);
|
||||
|
||||
caps = gst_caps_from_string (format);
|
||||
event = gst_event_new_caps (caps);
|
||||
gst_caps_unref (caps);
|
||||
|
||||
gst_pad_push_event (demuxer->srcpads[index], event);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ use utils::*;
|
|||
use error::*;
|
||||
use buffer::*;
|
||||
use log::*;
|
||||
use caps::Caps;
|
||||
use plugin::Plugin;
|
||||
|
||||
pub type StreamIndex = u32;
|
||||
|
@ -79,15 +80,15 @@ pub trait Demuxer {
|
|||
#[derive(Debug)]
|
||||
pub struct Stream {
|
||||
pub index: StreamIndex,
|
||||
pub format: String,
|
||||
pub caps: Caps,
|
||||
pub stream_id: String,
|
||||
}
|
||||
|
||||
impl Stream {
|
||||
pub fn new(index: StreamIndex, format: String, stream_id: String) -> Stream {
|
||||
pub fn new(index: StreamIndex, caps: Caps, stream_id: String) -> Stream {
|
||||
Stream {
|
||||
index: index,
|
||||
format: format,
|
||||
caps: caps,
|
||||
stream_id: stream_id,
|
||||
}
|
||||
}
|
||||
|
@ -254,13 +255,13 @@ impl DemuxerWrapper {
|
|||
fn gst_rs_demuxer_stream_eos(raw: *mut c_void, index: u32);
|
||||
fn gst_rs_demuxer_add_stream(raw: *mut c_void,
|
||||
index: u32,
|
||||
format: *const c_char,
|
||||
caps: *const c_void,
|
||||
stream_id: *const c_char);
|
||||
fn gst_rs_demuxer_added_all_streams(raw: *mut c_void);
|
||||
// fn gst_rs_demuxer_remove_all_streams(raw: *mut c_void);
|
||||
fn gst_rs_demuxer_stream_format_changed(raw: *mut c_void,
|
||||
index: u32,
|
||||
format: *const c_char);
|
||||
caps: *const c_void);
|
||||
fn gst_rs_demuxer_stream_push_buffer(raw: *mut c_void,
|
||||
index: u32,
|
||||
buffer: *mut c_void)
|
||||
|
@ -295,36 +296,29 @@ impl DemuxerWrapper {
|
|||
return GstFlowReturn::Ok;
|
||||
}
|
||||
HandleBufferResult::StreamAdded(stream) => {
|
||||
let format_cstr = CString::new(stream.format.as_bytes()).unwrap();
|
||||
let stream_id_cstr = CString::new(stream.stream_id.as_bytes()).unwrap();
|
||||
|
||||
unsafe {
|
||||
gst_rs_demuxer_add_stream(self.raw,
|
||||
stream.index,
|
||||
format_cstr.as_ptr(),
|
||||
stream.caps.as_ptr(),
|
||||
stream_id_cstr.as_ptr());
|
||||
}
|
||||
}
|
||||
HandleBufferResult::HaveAllStreams => unsafe {
|
||||
gst_rs_demuxer_added_all_streams(self.raw);
|
||||
},
|
||||
HandleBufferResult::StreamChanged(stream) => {
|
||||
let format_cstr = CString::new(stream.format.as_bytes()).unwrap();
|
||||
|
||||
unsafe {
|
||||
gst_rs_demuxer_stream_format_changed(self.raw,
|
||||
stream.index,
|
||||
format_cstr.as_ptr());
|
||||
}
|
||||
}
|
||||
HandleBufferResult::StreamChanged(stream) => unsafe {
|
||||
gst_rs_demuxer_stream_format_changed(self.raw,
|
||||
stream.index,
|
||||
stream.caps.as_ptr());
|
||||
},
|
||||
HandleBufferResult::StreamsChanged(streams) => {
|
||||
for stream in streams {
|
||||
let format_cstr = CString::new(stream.format.as_bytes()).unwrap();
|
||||
|
||||
unsafe {
|
||||
gst_rs_demuxer_stream_format_changed(self.raw,
|
||||
stream.index,
|
||||
format_cstr.as_ptr());
|
||||
stream.caps.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,3 +37,4 @@ pub mod source;
|
|||
pub mod sink;
|
||||
pub mod demuxer;
|
||||
pub mod log;
|
||||
pub mod caps;
|
||||
|
|
Loading…
Reference in a new issue