2017-02-16 15:52:27 +00:00
|
|
|
// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
|
2016-11-24 14:29:43 +00:00
|
|
|
//
|
2017-02-16 15:52:27 +00:00
|
|
|
// 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.
|
2016-11-24 14:29:43 +00:00
|
|
|
|
|
|
|
use libc::c_char;
|
|
|
|
use std::os::raw::c_void;
|
|
|
|
use std::ffi::CString;
|
|
|
|
|
|
|
|
use std::panic::{self, AssertUnwindSafe};
|
|
|
|
|
|
|
|
use std::sync::Mutex;
|
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
|
|
|
|
|
|
use std::u32;
|
|
|
|
use std::u64;
|
|
|
|
|
2016-12-27 15:47:39 +00:00
|
|
|
use slog::*;
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
use utils::*;
|
|
|
|
use error::*;
|
|
|
|
use buffer::*;
|
2017-02-03 14:34:17 +00:00
|
|
|
use miniobject::*;
|
2016-12-27 15:47:39 +00:00
|
|
|
use log::*;
|
2016-12-30 11:11:30 +00:00
|
|
|
use caps::Caps;
|
2016-12-23 16:10:38 +00:00
|
|
|
use plugin::Plugin;
|
2016-11-24 14:29:43 +00:00
|
|
|
|
2017-04-09 21:29:07 +00:00
|
|
|
use glib;
|
|
|
|
use gst;
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
pub type StreamIndex = u32;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum SeekResult {
|
|
|
|
TooEarly,
|
|
|
|
Ok(u64),
|
|
|
|
Eos,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum HandleBufferResult {
|
|
|
|
NeedMoreData,
|
|
|
|
Again,
|
|
|
|
// NeedDataFromOffset(u64),
|
|
|
|
StreamAdded(Stream),
|
|
|
|
HaveAllStreams,
|
|
|
|
StreamChanged(Stream),
|
|
|
|
// StreamsAdded(Vec<Stream>), // Implies HaveAllStreams
|
2016-12-04 18:24:44 +00:00
|
|
|
StreamsChanged(Vec<Stream>),
|
2016-11-24 14:29:43 +00:00
|
|
|
// TODO need something to replace/add new streams
|
|
|
|
// TODO should probably directly implement the GstStreams new world order
|
2017-02-03 14:34:17 +00:00
|
|
|
BufferForStream(StreamIndex, GstRc<Buffer>),
|
2016-11-24 14:29:43 +00:00
|
|
|
Eos(Option<StreamIndex>),
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait Demuxer {
|
|
|
|
fn start(&mut self,
|
|
|
|
upstream_size: Option<u64>,
|
|
|
|
random_access: bool)
|
|
|
|
-> Result<(), ErrorMessage>;
|
|
|
|
fn stop(&mut self) -> Result<(), ErrorMessage>;
|
|
|
|
|
|
|
|
fn seek(&mut self, start: u64, stop: Option<u64>) -> Result<SeekResult, ErrorMessage>;
|
2017-02-03 14:34:17 +00:00
|
|
|
fn handle_buffer(&mut self,
|
|
|
|
buffer: Option<GstRc<Buffer>>)
|
|
|
|
-> Result<HandleBufferResult, FlowError>;
|
2016-11-24 14:29:43 +00:00
|
|
|
fn end_of_stream(&mut self) -> Result<(), ErrorMessage>;
|
|
|
|
|
|
|
|
fn is_seekable(&self) -> bool;
|
|
|
|
fn get_position(&self) -> Option<u64>;
|
|
|
|
fn get_duration(&self) -> Option<u64>;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Stream {
|
|
|
|
pub index: StreamIndex,
|
2017-02-03 14:34:17 +00:00
|
|
|
pub caps: GstRc<Caps>,
|
2016-11-24 14:29:43 +00:00
|
|
|
pub stream_id: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Stream {
|
2017-02-03 14:34:17 +00:00
|
|
|
pub fn new(index: StreamIndex, caps: GstRc<Caps>, stream_id: String) -> Stream {
|
2016-11-24 14:29:43 +00:00
|
|
|
Stream {
|
|
|
|
index: index,
|
2016-12-30 11:11:30 +00:00
|
|
|
caps: caps,
|
2016-11-24 14:29:43 +00:00
|
|
|
stream_id: stream_id,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct DemuxerWrapper {
|
2017-04-09 21:29:07 +00:00
|
|
|
raw: *mut gst::GstElement,
|
2016-12-27 15:47:39 +00:00
|
|
|
logger: Logger,
|
2016-11-24 14:29:43 +00:00
|
|
|
demuxer: Mutex<Box<Demuxer>>,
|
|
|
|
panicked: AtomicBool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DemuxerWrapper {
|
2017-04-09 21:29:07 +00:00
|
|
|
fn new(raw: *mut gst::GstElement, demuxer: Box<Demuxer>) -> DemuxerWrapper {
|
2016-11-24 14:29:43 +00:00
|
|
|
DemuxerWrapper {
|
|
|
|
raw: raw,
|
2016-12-27 15:47:39 +00:00
|
|
|
logger: Logger::root(GstDebugDrain::new(Some(unsafe { &Element::new(raw) }),
|
|
|
|
"rsdemux",
|
|
|
|
0,
|
|
|
|
"Rust demuxer base class"),
|
|
|
|
None),
|
2016-11-24 14:29:43 +00:00
|
|
|
demuxer: Mutex::new(demuxer),
|
|
|
|
panicked: AtomicBool::new(false),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn start(&self, upstream_size: u64, random_access: bool) -> bool {
|
|
|
|
let demuxer = &mut self.demuxer.lock().unwrap();
|
|
|
|
|
2016-12-27 15:47:39 +00:00
|
|
|
debug!(self.logger,
|
|
|
|
"Starting with upstream size {} and random access {}",
|
|
|
|
upstream_size,
|
|
|
|
random_access);
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
let upstream_size = if upstream_size == u64::MAX {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(upstream_size)
|
|
|
|
};
|
|
|
|
|
|
|
|
match demuxer.start(upstream_size, random_access) {
|
2016-12-27 15:47:39 +00:00
|
|
|
Ok(..) => {
|
|
|
|
trace!(self.logger, "Successfully started");
|
|
|
|
true
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
Err(ref msg) => {
|
2016-12-27 15:47:39 +00:00
|
|
|
error!(self.logger, "Failed to start: {:?}", msg);
|
2016-11-24 14:29:43 +00:00
|
|
|
self.post_message(msg);
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
fn stop(&self) -> bool {
|
|
|
|
let demuxer = &mut self.demuxer.lock().unwrap();
|
|
|
|
|
2016-12-27 15:47:39 +00:00
|
|
|
debug!(self.logger, "Stopping");
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
match demuxer.stop() {
|
2016-12-27 15:47:39 +00:00
|
|
|
Ok(..) => {
|
|
|
|
trace!(self.logger, "Successfully stop");
|
|
|
|
true
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
Err(ref msg) => {
|
2016-12-27 15:47:39 +00:00
|
|
|
error!(self.logger, "Failed to stop: {:?}", msg);
|
2016-11-24 14:29:43 +00:00
|
|
|
self.post_message(msg);
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_seekable(&self) -> bool {
|
|
|
|
let demuxer = &self.demuxer.lock().unwrap();
|
|
|
|
|
2016-12-27 15:47:39 +00:00
|
|
|
let seekable = demuxer.is_seekable();
|
|
|
|
debug!(self.logger, "Seekable {}", seekable);
|
|
|
|
|
|
|
|
seekable
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-09 21:29:07 +00:00
|
|
|
fn get_position(&self, position: &mut u64) -> glib::gboolean {
|
2016-11-24 14:29:43 +00:00
|
|
|
let demuxer = &self.demuxer.lock().unwrap();
|
|
|
|
|
|
|
|
match demuxer.get_position() {
|
|
|
|
None => {
|
2016-12-27 15:47:39 +00:00
|
|
|
trace!(self.logger, "Got no position");
|
2016-11-24 14:29:43 +00:00
|
|
|
*position = u64::MAX;
|
2017-04-09 21:29:07 +00:00
|
|
|
glib::GFALSE
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
Some(pos) => {
|
2016-12-27 15:47:39 +00:00
|
|
|
trace!(self.logger, "Returning position {}", pos);
|
2016-11-24 14:29:43 +00:00
|
|
|
*position = pos;
|
2017-04-09 21:29:07 +00:00
|
|
|
glib::GTRUE
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-04-09 21:29:07 +00:00
|
|
|
fn get_duration(&self, duration: &mut u64) -> glib::gboolean {
|
2016-11-24 14:29:43 +00:00
|
|
|
let demuxer = &self.demuxer.lock().unwrap();
|
|
|
|
|
|
|
|
match demuxer.get_duration() {
|
|
|
|
None => {
|
2016-12-27 15:47:39 +00:00
|
|
|
trace!(self.logger, "Got no duration");
|
|
|
|
*duration = u64::MAX;
|
2017-04-09 21:29:07 +00:00
|
|
|
glib::GFALSE
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
2016-12-27 15:47:39 +00:00
|
|
|
Some(dur) => {
|
|
|
|
trace!(self.logger, "Returning duration {}", dur);
|
|
|
|
*duration = dur;
|
2017-04-09 21:29:07 +00:00
|
|
|
glib::GTRUE
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn seek(&self, start: u64, stop: u64, offset: &mut u64) -> bool {
|
|
|
|
extern "C" {
|
2017-04-09 21:29:07 +00:00
|
|
|
fn gst_rs_demuxer_stream_eos(raw: *mut gst::GstElement, index: u32);
|
2016-11-24 14:29:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let stop = if stop == u64::MAX { None } else { Some(stop) };
|
|
|
|
|
2016-12-27 15:47:39 +00:00
|
|
|
debug!(self.logger, "Seeking to {:?}-{:?}", start, stop);
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
let res = {
|
|
|
|
let mut demuxer = &mut self.demuxer.lock().unwrap();
|
|
|
|
|
|
|
|
match demuxer.seek(start, stop) {
|
|
|
|
Ok(res) => res,
|
|
|
|
Err(ref msg) => {
|
2016-12-27 15:47:39 +00:00
|
|
|
error!(self.logger, "Failed to seek: {:?}", msg);
|
2016-11-24 14:29:43 +00:00
|
|
|
self.post_message(msg);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
match res {
|
2016-12-27 15:47:39 +00:00
|
|
|
SeekResult::TooEarly => {
|
|
|
|
debug!(self.logger, "Seeked too early");
|
|
|
|
false
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
SeekResult::Ok(off) => {
|
2016-12-27 15:47:39 +00:00
|
|
|
trace!(self.logger, "Seeked successfully");
|
2016-11-24 14:29:43 +00:00
|
|
|
*offset = off;
|
|
|
|
true
|
|
|
|
}
|
|
|
|
SeekResult::Eos => {
|
2016-12-27 15:47:39 +00:00
|
|
|
debug!(self.logger, "Seeked after EOS");
|
2016-11-24 14:29:43 +00:00
|
|
|
*offset = u64::MAX;
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
gst_rs_demuxer_stream_eos(self.raw, u32::MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-03 14:34:17 +00:00
|
|
|
fn handle_buffer(&self, buffer: GstRc<Buffer>) -> GstFlowReturn {
|
2016-11-24 14:29:43 +00:00
|
|
|
extern "C" {
|
2017-04-09 21:29:07 +00:00
|
|
|
fn gst_rs_demuxer_stream_eos(raw: *mut gst::GstElement, index: u32);
|
|
|
|
fn gst_rs_demuxer_add_stream(raw: *mut gst::GstElement,
|
2016-11-24 14:29:43 +00:00
|
|
|
index: u32,
|
2017-04-09 21:29:07 +00:00
|
|
|
caps: *const gst::GstCaps,
|
2016-11-24 14:29:43 +00:00
|
|
|
stream_id: *const c_char);
|
2017-04-09 21:29:07 +00:00
|
|
|
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_stream_format_changed(raw: *mut gst::GstElement,
|
2016-11-24 14:29:43 +00:00
|
|
|
index: u32,
|
2017-04-09 21:29:07 +00:00
|
|
|
caps: *const gst::GstCaps);
|
|
|
|
fn gst_rs_demuxer_stream_push_buffer(raw: *mut gst::GstElement,
|
2016-11-24 14:29:43 +00:00
|
|
|
index: u32,
|
2017-04-09 21:29:07 +00:00
|
|
|
buffer: *mut gst::GstBuffer)
|
2016-11-24 14:29:43 +00:00
|
|
|
-> GstFlowReturn;
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut res = {
|
|
|
|
let mut demuxer = &mut self.demuxer.lock().unwrap();
|
|
|
|
|
2016-12-27 15:47:39 +00:00
|
|
|
trace!(self.logger, "Handling buffer {:?}", buffer);
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
match demuxer.handle_buffer(Some(buffer)) {
|
|
|
|
Ok(res) => res,
|
|
|
|
Err(flow_error) => {
|
2016-12-27 15:47:39 +00:00
|
|
|
error!(self.logger, "Failed handling buffer: {:?}", flow_error);
|
2016-11-24 14:29:43 +00:00
|
|
|
match flow_error {
|
|
|
|
FlowError::NotNegotiated(ref msg) |
|
|
|
|
FlowError::Error(ref msg) => self.post_message(msg),
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
return flow_error.to_native();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Loop until AllEos, NeedMoreData or error when pushing downstream
|
|
|
|
loop {
|
2016-12-27 15:47:39 +00:00
|
|
|
trace!(self.logger, "Handled {:?}", res);
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
match res {
|
|
|
|
HandleBufferResult::NeedMoreData => {
|
|
|
|
return GstFlowReturn::Ok;
|
|
|
|
}
|
|
|
|
HandleBufferResult::StreamAdded(stream) => {
|
|
|
|
let stream_id_cstr = CString::new(stream.stream_id.as_bytes()).unwrap();
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
gst_rs_demuxer_add_stream(self.raw,
|
|
|
|
stream.index,
|
2016-12-30 11:11:30 +00:00
|
|
|
stream.caps.as_ptr(),
|
2016-11-24 14:29:43 +00:00
|
|
|
stream_id_cstr.as_ptr());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
HandleBufferResult::HaveAllStreams => unsafe {
|
|
|
|
gst_rs_demuxer_added_all_streams(self.raw);
|
|
|
|
},
|
2016-12-30 11:11:30 +00:00
|
|
|
HandleBufferResult::StreamChanged(stream) => unsafe {
|
|
|
|
gst_rs_demuxer_stream_format_changed(self.raw,
|
|
|
|
stream.index,
|
|
|
|
stream.caps.as_ptr());
|
|
|
|
},
|
2016-12-04 18:24:44 +00:00
|
|
|
HandleBufferResult::StreamsChanged(streams) => {
|
|
|
|
for stream in streams {
|
|
|
|
unsafe {
|
|
|
|
gst_rs_demuxer_stream_format_changed(self.raw,
|
|
|
|
stream.index,
|
2016-12-30 11:11:30 +00:00
|
|
|
stream.caps.as_ptr());
|
2016-12-04 18:24:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
HandleBufferResult::BufferForStream(index, buffer) => {
|
|
|
|
let flow_ret = unsafe {
|
|
|
|
gst_rs_demuxer_stream_push_buffer(self.raw, index, buffer.into_ptr())
|
|
|
|
};
|
|
|
|
if flow_ret != GstFlowReturn::Ok {
|
|
|
|
return flow_ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
HandleBufferResult::Eos(index) => {
|
|
|
|
let index = index.unwrap_or(u32::MAX);
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
gst_rs_demuxer_stream_eos(self.raw, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
return GstFlowReturn::Eos;
|
|
|
|
}
|
|
|
|
HandleBufferResult::Again => {
|
|
|
|
// nothing, just call again
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-12-27 15:47:39 +00:00
|
|
|
trace!(self.logger, "Calling again");
|
|
|
|
|
2016-11-24 14:29:43 +00:00
|
|
|
res = {
|
|
|
|
let mut demuxer = &mut self.demuxer.lock().unwrap();
|
|
|
|
match demuxer.handle_buffer(None) {
|
|
|
|
Ok(res) => res,
|
|
|
|
Err(flow_error) => {
|
2016-12-27 15:47:39 +00:00
|
|
|
error!(self.logger, "Failed calling again: {:?}", flow_error);
|
2016-11-24 14:29:43 +00:00
|
|
|
match flow_error {
|
|
|
|
FlowError::NotNegotiated(ref msg) |
|
|
|
|
FlowError::Error(ref msg) => self.post_message(msg),
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
return flow_error.to_native();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn end_of_stream(&self) {
|
|
|
|
let mut demuxer = &mut self.demuxer.lock().unwrap();
|
|
|
|
|
2016-12-27 15:47:39 +00:00
|
|
|
debug!(self.logger, "End of stream");
|
2016-11-24 14:29:43 +00:00
|
|
|
match demuxer.end_of_stream() {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(ref msg) => {
|
2016-12-27 15:47:39 +00:00
|
|
|
error!(self.logger, "Failed end of stream: {:?}", msg);
|
2016-11-24 14:29:43 +00:00
|
|
|
self.post_message(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn post_message(&self, msg: &ErrorMessage) {
|
|
|
|
unsafe {
|
|
|
|
msg.post(self.raw);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2017-04-09 21:29:07 +00:00
|
|
|
pub unsafe extern "C" fn demuxer_new(demuxer: *mut gst::GstElement,
|
2016-12-25 11:28:17 +00:00
|
|
|
create_instance: fn(Element) -> Box<Demuxer>)
|
|
|
|
-> *mut DemuxerWrapper {
|
|
|
|
let instance = create_instance(Element::new(demuxer));
|
2016-12-25 11:16:12 +00:00
|
|
|
Box::into_raw(Box::new(DemuxerWrapper::new(demuxer, instance)))
|
2016-11-24 14:29:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "C" fn demuxer_drop(ptr: *mut DemuxerWrapper) {
|
|
|
|
let _ = Box::from_raw(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "C" fn demuxer_start(ptr: *const DemuxerWrapper,
|
|
|
|
upstream_size: u64,
|
2017-04-09 21:29:07 +00:00
|
|
|
random_access: glib::gboolean)
|
|
|
|
-> glib::gboolean {
|
2016-11-24 14:29:43 +00:00
|
|
|
let wrap: &DemuxerWrapper = &*ptr;
|
|
|
|
|
2017-04-09 21:29:07 +00:00
|
|
|
panic_to_error!(wrap, glib::GFALSE, {
|
|
|
|
if wrap.start(upstream_size, random_access != glib::GFALSE) {
|
|
|
|
glib::GTRUE
|
|
|
|
} else {
|
|
|
|
glib::GFALSE
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2017-04-09 21:29:07 +00:00
|
|
|
pub unsafe extern "C" fn demuxer_stop(ptr: *const DemuxerWrapper) -> glib::gboolean {
|
2016-11-24 14:29:43 +00:00
|
|
|
let wrap: &DemuxerWrapper = &*ptr;
|
|
|
|
|
2017-04-09 21:29:07 +00:00
|
|
|
panic_to_error!(wrap, glib::GTRUE, {
|
|
|
|
if wrap.stop() {
|
|
|
|
glib::GTRUE
|
|
|
|
} else {
|
|
|
|
glib::GFALSE
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
2017-04-09 21:29:07 +00:00
|
|
|
pub unsafe extern "C" fn demuxer_is_seekable(ptr: *const DemuxerWrapper) -> glib::gboolean {
|
2016-11-24 14:29:43 +00:00
|
|
|
let wrap: &DemuxerWrapper = &*ptr;
|
|
|
|
|
2017-04-09 21:29:07 +00:00
|
|
|
panic_to_error!(wrap, glib::GFALSE, {
|
|
|
|
if wrap.is_seekable() {
|
|
|
|
glib::GTRUE
|
|
|
|
} else {
|
|
|
|
glib::GFALSE
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "C" fn demuxer_get_position(ptr: *const DemuxerWrapper,
|
|
|
|
position: *mut u64)
|
2017-04-09 21:29:07 +00:00
|
|
|
-> glib::gboolean {
|
2016-11-24 14:29:43 +00:00
|
|
|
let wrap: &DemuxerWrapper = &*ptr;
|
|
|
|
|
2017-04-09 21:29:07 +00:00
|
|
|
panic_to_error!(wrap, glib::GFALSE, {
|
2016-11-24 14:29:43 +00:00
|
|
|
let position = &mut *position;
|
|
|
|
wrap.get_position(position)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "C" fn demuxer_get_duration(ptr: *const DemuxerWrapper,
|
|
|
|
duration: *mut u64)
|
2017-04-09 21:29:07 +00:00
|
|
|
-> glib::gboolean {
|
2016-11-24 14:29:43 +00:00
|
|
|
let wrap: &DemuxerWrapper = &*ptr;
|
|
|
|
|
2017-04-09 21:29:07 +00:00
|
|
|
panic_to_error!(wrap, glib::GFALSE, {
|
2016-11-24 14:29:43 +00:00
|
|
|
let duration = &mut *duration;
|
|
|
|
wrap.get_duration(duration)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "C" fn demuxer_seek(ptr: *mut DemuxerWrapper,
|
|
|
|
start: u64,
|
|
|
|
stop: u64,
|
|
|
|
offset: *mut u64)
|
2017-04-09 21:29:07 +00:00
|
|
|
-> glib::gboolean {
|
2016-11-24 14:29:43 +00:00
|
|
|
|
|
|
|
let wrap: &mut DemuxerWrapper = &mut *ptr;
|
|
|
|
|
2017-04-09 21:29:07 +00:00
|
|
|
panic_to_error!(wrap, glib::GFALSE, {
|
2016-11-24 14:29:43 +00:00
|
|
|
let offset = &mut *offset;
|
|
|
|
|
2017-04-09 21:29:07 +00:00
|
|
|
if wrap.seek(start, stop, offset) {
|
|
|
|
glib::GTRUE
|
|
|
|
} else {
|
|
|
|
glib::GFALSE
|
|
|
|
}
|
2016-11-24 14:29:43 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "C" fn demuxer_handle_buffer(ptr: *mut DemuxerWrapper,
|
2017-04-09 21:29:07 +00:00
|
|
|
buffer: *mut gst::GstBuffer)
|
2016-11-24 14:29:43 +00:00
|
|
|
-> GstFlowReturn {
|
|
|
|
let wrap: &mut DemuxerWrapper = &mut *ptr;
|
|
|
|
|
|
|
|
panic_to_error!(wrap, GstFlowReturn::Error, {
|
2017-02-03 14:34:17 +00:00
|
|
|
let buffer = GstRc::new_from_owned_ptr(buffer);
|
2016-11-24 14:29:43 +00:00
|
|
|
wrap.handle_buffer(buffer)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "C" fn demuxer_end_of_stream(ptr: *mut DemuxerWrapper) {
|
|
|
|
let wrap: &mut DemuxerWrapper = &mut *ptr;
|
|
|
|
|
|
|
|
panic_to_error!(wrap, (), {
|
|
|
|
wrap.end_of_stream();
|
|
|
|
})
|
|
|
|
}
|
2016-12-23 16:10:38 +00:00
|
|
|
|
|
|
|
pub struct DemuxerInfo<'a> {
|
|
|
|
pub name: &'a str,
|
|
|
|
pub long_name: &'a str,
|
|
|
|
pub description: &'a str,
|
|
|
|
pub classification: &'a str,
|
|
|
|
pub author: &'a str,
|
|
|
|
pub rank: i32,
|
2016-12-25 11:16:12 +00:00
|
|
|
pub create_instance: fn(Element) -> Box<Demuxer>,
|
2016-12-30 17:02:31 +00:00
|
|
|
pub input_caps: &'a Caps,
|
|
|
|
pub output_caps: &'a Caps,
|
2016-12-23 16:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn demuxer_register(plugin: &Plugin, demuxer_info: &DemuxerInfo) {
|
|
|
|
extern "C" {
|
2017-04-09 21:29:07 +00:00
|
|
|
fn gst_rs_demuxer_register(plugin: *const gst::GstPlugin,
|
2016-12-23 16:10:38 +00:00
|
|
|
name: *const c_char,
|
|
|
|
long_name: *const c_char,
|
|
|
|
description: *const c_char,
|
|
|
|
classification: *const c_char,
|
|
|
|
author: *const c_char,
|
|
|
|
rank: i32,
|
|
|
|
create_instance: *const c_void,
|
2017-04-09 21:29:07 +00:00
|
|
|
input_caps: *const gst::GstCaps,
|
|
|
|
output_caps: *const gst::GstCaps)
|
|
|
|
-> glib::gboolean;
|
2016-12-23 16:10:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let cname = CString::new(demuxer_info.name).unwrap();
|
|
|
|
let clong_name = CString::new(demuxer_info.long_name).unwrap();
|
|
|
|
let cdescription = CString::new(demuxer_info.description).unwrap();
|
|
|
|
let cclassification = CString::new(demuxer_info.classification).unwrap();
|
|
|
|
let cauthor = CString::new(demuxer_info.author).unwrap();
|
|
|
|
|
|
|
|
unsafe {
|
2016-12-25 11:16:12 +00:00
|
|
|
gst_rs_demuxer_register(plugin.as_ptr(),
|
2016-12-23 16:10:38 +00:00
|
|
|
cname.as_ptr(),
|
|
|
|
clong_name.as_ptr(),
|
|
|
|
cdescription.as_ptr(),
|
|
|
|
cclassification.as_ptr(),
|
|
|
|
cauthor.as_ptr(),
|
|
|
|
demuxer_info.rank,
|
|
|
|
demuxer_info.create_instance as *const c_void,
|
2016-12-30 17:02:31 +00:00
|
|
|
demuxer_info.input_caps.as_ptr(),
|
|
|
|
demuxer_info.output_caps.as_ptr());
|
2016-12-23 16:10:38 +00:00
|
|
|
}
|
|
|
|
}
|