gst-plugins-rs/gst-plugin/src/demuxer.rs

643 lines
18 KiB
Rust
Raw Normal View History

// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
2016-11-24 14:29:43 +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;
use error::*;
use glib_ffi;
use gst_ffi;
use glib;
use glib::translate::*;
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
BufferForStream(StreamIndex, gst::Buffer),
2016-11-24 14:29:43 +00:00
Eos(Option<StreamIndex>),
}
pub trait Demuxer {
2017-07-31 13:36:35 +00:00
fn start(
&mut self,
upstream_size: Option<u64>,
random_access: bool,
) -> Result<(), ErrorMessage>;
2016-11-24 14:29:43 +00:00
fn stop(&mut self) -> Result<(), ErrorMessage>;
fn seek(&mut self, start: u64, stop: Option<u64>) -> Result<SeekResult, ErrorMessage>;
2017-07-31 13:36:35 +00:00
fn handle_buffer(
&mut self,
buffer: Option<gst::Buffer>,
2017-07-31 13:36:35 +00:00
) -> 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,
pub caps: gst::Caps,
2016-11-24 14:29:43 +00:00
pub stream_id: String,
}
impl Stream {
pub fn new(index: StreamIndex, caps: gst::Caps, stream_id: String) -> Stream {
2016-11-24 14:29:43 +00:00
Stream {
index: index,
caps: caps,
2016-11-24 14:29:43 +00:00
stream_id: stream_id,
}
}
}
pub struct DemuxerWrapper {
raw: *mut gst_ffi::GstElement,
cat: gst::DebugCategory,
2016-11-24 14:29:43 +00:00
demuxer: Mutex<Box<Demuxer>>,
panicked: AtomicBool,
}
impl DemuxerWrapper {
fn new(raw: *mut gst_ffi::GstElement, demuxer: Box<Demuxer>) -> DemuxerWrapper {
2016-11-24 14:29:43 +00:00
DemuxerWrapper {
raw: raw,
cat: gst::DebugCategory::new(
"rsdemux",
gst::DebugColorFlags::empty(),
"Rust demuxer base class",
2017-07-31 13:36:35 +00:00
),
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();
gst_debug!(
self.cat,
// TODO obj: demuxer
2017-07-31 13:36:35 +00:00
"Starting with upstream size {} and random access {}",
upstream_size,
random_access
);
2016-12-27 15:47:39 +00:00
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(..) => {
gst_trace!(
self.cat,
/* TODO obj: demuxer,*/ "Successfully started"
);
2016-12-27 15:47:39 +00:00
true
}
2016-11-24 14:29:43 +00:00
Err(ref msg) => {
gst_error!(
self.cat,
/* TODO obj: demuxer,*/ "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();
gst_debug!(self.cat, /* TODO obj: demuxer,*/ "Stopping");
2016-12-27 15:47:39 +00:00
2016-11-24 14:29:43 +00:00
match demuxer.stop() {
2016-12-27 15:47:39 +00:00
Ok(..) => {
gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Successfully stop");
2016-12-27 15:47:39 +00:00
true
}
2016-11-24 14:29:43 +00:00
Err(ref msg) => {
gst_error!(
self.cat,
/* TODO obj: demuxer,*/ "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();
gst_debug!(
self.cat,
/* TODO obj: demuxer,*/ "Seekable {}",
seekable
);
2016-12-27 15:47:39 +00:00
seekable
2016-11-24 14:29:43 +00:00
}
fn get_position(&self, position: &mut u64) -> glib_ffi::gboolean {
2016-11-24 14:29:43 +00:00
let demuxer = &self.demuxer.lock().unwrap();
match demuxer.get_position() {
None => {
gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Got no position");
2016-11-24 14:29:43 +00:00
*position = u64::MAX;
glib_ffi::GFALSE
2016-11-24 14:29:43 +00:00
}
Some(pos) => {
gst_trace!(
self.cat,
/* TODO obj: demuxer,*/ "Returning position {}",
pos
);
2016-11-24 14:29:43 +00:00
*position = pos;
glib_ffi::GTRUE
2016-11-24 14:29:43 +00:00
}
}
}
fn get_duration(&self, duration: &mut u64) -> glib_ffi::gboolean {
2016-11-24 14:29:43 +00:00
let demuxer = &self.demuxer.lock().unwrap();
match demuxer.get_duration() {
None => {
gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Got no duration");
2016-12-27 15:47:39 +00:00
*duration = u64::MAX;
glib_ffi::GFALSE
2016-11-24 14:29:43 +00:00
}
2016-12-27 15:47:39 +00:00
Some(dur) => {
gst_trace!(
self.cat,
/* TODO obj: demuxer,*/ "Returning duration {}",
dur
);
2016-12-27 15:47:39 +00:00
*duration = dur;
glib_ffi::GTRUE
2016-11-24 14:29:43 +00:00
}
}
}
fn seek(&self, start: u64, stop: u64, offset: &mut u64) -> bool {
extern "C" {
fn gst_rs_demuxer_stream_eos(raw: *mut gst_ffi::GstElement, index: u32);
2016-11-24 14:29:43 +00:00
};
let stop = if stop == u64::MAX { None } else { Some(stop) };
gst_debug!(
self.cat,
/* TODO obj: demuxer,*/ "Seeking to {:?}-{:?}",
start,
stop
);
2016-12-27 15:47:39 +00:00
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) => {
gst_error!(
self.cat,
/* TODO obj: demuxer,*/ "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 => {
gst_debug!(self.cat, /* TODO obj: demuxer,*/ "Seeked too early");
2016-12-27 15:47:39 +00:00
false
}
2016-11-24 14:29:43 +00:00
SeekResult::Ok(off) => {
gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Seeked successfully");
2016-11-24 14:29:43 +00:00
*offset = off;
true
}
SeekResult::Eos => {
gst_debug!(self.cat, /* TODO obj: demuxer,*/ "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
}
}
}
fn handle_buffer(&self, buffer: gst::Buffer) -> gst::FlowReturn {
2016-11-24 14:29:43 +00:00
extern "C" {
fn gst_rs_demuxer_stream_eos(raw: *mut gst_ffi::GstElement, index: u32);
2017-07-31 13:36:35 +00:00
fn gst_rs_demuxer_add_stream(
raw: *mut gst_ffi::GstElement,
2017-07-31 13:36:35 +00:00
index: u32,
caps: *const gst_ffi::GstCaps,
2017-07-31 13:36:35 +00:00
stream_id: *const c_char,
);
fn gst_rs_demuxer_added_all_streams(raw: *mut gst_ffi::GstElement);
// fn gst_rs_demuxer_remove_all_streams(raw: *mut gst_ffi::GstElement);
2017-07-31 13:36:35 +00:00
fn gst_rs_demuxer_stream_format_changed(
raw: *mut gst_ffi::GstElement,
2017-07-31 13:36:35 +00:00
index: u32,
caps: *const gst_ffi::GstCaps,
2017-07-31 13:36:35 +00:00
);
fn gst_rs_demuxer_stream_push_buffer(
raw: *mut gst_ffi::GstElement,
2017-07-31 13:36:35 +00:00
index: u32,
buffer: *mut gst_ffi::GstBuffer,
) -> gst_ffi::GstFlowReturn;
2016-11-24 14:29:43 +00:00
};
let mut res = {
let mut demuxer = &mut self.demuxer.lock().unwrap();
gst_trace!(
self.cat,
/* TODO obj: demuxer,*/ "Handling buffer {:?}",
buffer
);
2016-12-27 15:47:39 +00:00
2016-11-24 14:29:43 +00:00
match demuxer.handle_buffer(Some(buffer)) {
Ok(res) => res,
Err(flow_error) => {
gst_error!(
self.cat,
/* TODO obj: demuxer,*/ "Failed handling buffer: {:?}",
flow_error
);
2016-11-24 14:29:43 +00:00
match flow_error {
2017-07-31 13:36:35 +00:00
FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => {
self.post_message(msg)
}
2016-11-24 14:29:43 +00:00
_ => (),
}
return flow_error.to_native();
}
}
};
// Loop until AllEos, NeedMoreData or error when pushing downstream
loop {
gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Handled {:?}", res);
2016-12-27 15:47:39 +00:00
2016-11-24 14:29:43 +00:00
match res {
HandleBufferResult::NeedMoreData => {
return gst::FlowReturn::Ok;
2016-11-24 14:29:43 +00:00
}
HandleBufferResult::StreamAdded(stream) => unsafe {
gst_rs_demuxer_add_stream(
self.raw,
stream.index,
stream.caps.to_glib_none().0,
stream.stream_id.to_glib_none().0,
);
},
2016-11-24 14:29:43 +00:00
HandleBufferResult::HaveAllStreams => unsafe {
gst_rs_demuxer_added_all_streams(self.raw);
},
HandleBufferResult::StreamChanged(stream) => unsafe {
2017-07-31 13:36:35 +00:00
gst_rs_demuxer_stream_format_changed(
self.raw,
stream.index,
stream.caps.to_glib_none().0,
2017-07-31 13:36:35 +00:00
);
},
2017-07-31 13:36:35 +00:00
HandleBufferResult::StreamsChanged(streams) => for stream in streams {
unsafe {
gst_rs_demuxer_stream_format_changed(
self.raw,
stream.index,
stream.caps.to_glib_none().0,
2017-07-31 13:36:35 +00:00
);
2016-12-04 18:24:44 +00:00
}
2017-07-31 13:36:35 +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())
2016-11-24 14:29:43 +00:00
};
if flow_ret != gst_ffi::GST_FLOW_OK {
return from_glib(flow_ret);
2016-11-24 14:29:43 +00:00
}
}
HandleBufferResult::Eos(index) => {
let index = index.unwrap_or(u32::MAX);
unsafe {
gst_rs_demuxer_stream_eos(self.raw, index);
}
return gst::FlowReturn::Eos;
2016-11-24 14:29:43 +00:00
}
HandleBufferResult::Again => {
// nothing, just call again
}
};
gst_trace!(self.cat, /* TODO obj: demuxer,*/ "Calling again");
2016-12-27 15:47:39 +00:00
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) => {
gst_error!(
self.cat,
/* TODO obj: demuxer,*/ "Failed calling again: {:?}",
flow_error
);
2016-11-24 14:29:43 +00:00
match flow_error {
2017-07-31 13:36:35 +00:00
FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => {
self.post_message(msg)
}
2016-11-24 14:29:43 +00:00
_ => (),
}
return flow_error.to_native();
}
}
}
}
}
fn end_of_stream(&self) {
let mut demuxer = &mut self.demuxer.lock().unwrap();
gst_debug!(self.cat, /* TODO obj: demuxer,*/ "End of stream");
2016-11-24 14:29:43 +00:00
match demuxer.end_of_stream() {
Ok(_) => (),
Err(ref msg) => {
gst_error!(
self.cat,
/* TODO obj: demuxer,*/ "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(&gst::Element::from_glib_borrow(self.raw));
2016-11-24 14:29:43 +00:00
}
}
}
#[no_mangle]
2017-07-31 13:36:35 +00:00
pub unsafe extern "C" fn demuxer_new(
demuxer: *mut gst_ffi::GstElement,
create_instance: fn(&gst::Element) -> Box<Demuxer>,
2017-07-31 13:36:35 +00:00
) -> *mut DemuxerWrapper {
let instance = create_instance(&from_glib_borrow(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]
2017-07-31 13:36:35 +00:00
pub unsafe extern "C" fn demuxer_start(
ptr: *const DemuxerWrapper,
upstream_size: u64,
random_access: glib_ffi::gboolean,
) -> glib_ffi::gboolean {
2016-11-24 14:29:43 +00:00
let wrap: &DemuxerWrapper = &*ptr;
panic_to_error!(
wrap,
&gst::Element::from_glib_borrow(wrap.raw as *mut _),
false,
{ wrap.start(upstream_size, random_access != glib_ffi::GFALSE) }
).to_glib()
2016-11-24 14:29:43 +00:00
}
#[no_mangle]
pub unsafe extern "C" fn demuxer_stop(ptr: *const DemuxerWrapper) -> glib_ffi::gboolean {
2016-11-24 14:29:43 +00:00
let wrap: &DemuxerWrapper = &*ptr;
panic_to_error!(
wrap,
&gst::Element::from_glib_borrow(wrap.raw as *mut _),
glib_ffi::GTRUE,
{
if wrap.stop() {
glib_ffi::GTRUE
} else {
glib_ffi::GFALSE
}
}
)
2016-11-24 14:29:43 +00:00
}
#[no_mangle]
pub unsafe extern "C" fn demuxer_is_seekable(ptr: *const DemuxerWrapper) -> glib_ffi::gboolean {
2016-11-24 14:29:43 +00:00
let wrap: &DemuxerWrapper = &*ptr;
panic_to_error!(
wrap,
&gst::Element::from_glib_borrow(wrap.raw as *mut _),
glib_ffi::GFALSE,
{
if wrap.is_seekable() {
glib_ffi::GTRUE
} else {
glib_ffi::GFALSE
}
}
)
2016-11-24 14:29:43 +00:00
}
#[no_mangle]
2017-07-31 13:36:35 +00:00
pub unsafe extern "C" fn demuxer_get_position(
ptr: *const DemuxerWrapper,
position: *mut u64,
) -> glib_ffi::gboolean {
2016-11-24 14:29:43 +00:00
let wrap: &DemuxerWrapper = &*ptr;
panic_to_error!(
wrap,
&gst::Element::from_glib_borrow(wrap.raw as *mut _),
glib_ffi::GFALSE,
{
let position = &mut *position;
wrap.get_position(position)
}
)
2016-11-24 14:29:43 +00:00
}
#[no_mangle]
2017-07-31 13:36:35 +00:00
pub unsafe extern "C" fn demuxer_get_duration(
ptr: *const DemuxerWrapper,
duration: *mut u64,
) -> glib_ffi::gboolean {
2016-11-24 14:29:43 +00:00
let wrap: &DemuxerWrapper = &*ptr;
panic_to_error!(
wrap,
&gst::Element::from_glib_borrow(wrap.raw as *mut _),
glib_ffi::GFALSE,
{
let duration = &mut *duration;
wrap.get_duration(duration)
}
)
2016-11-24 14:29:43 +00:00
}
#[no_mangle]
2017-07-31 13:36:35 +00:00
pub unsafe extern "C" fn demuxer_seek(
ptr: *mut DemuxerWrapper,
start: u64,
stop: u64,
offset: *mut u64,
) -> glib_ffi::gboolean {
2016-11-24 14:29:43 +00:00
let wrap: &mut DemuxerWrapper = &mut *ptr;
panic_to_error!(
wrap,
&gst::Element::from_glib_borrow(wrap.raw as *mut _),
glib_ffi::GFALSE,
{
let offset = &mut *offset;
2016-11-24 14:29:43 +00:00
if wrap.seek(start, stop, offset) {
glib_ffi::GTRUE
} else {
glib_ffi::GFALSE
}
}
)
2016-11-24 14:29:43 +00:00
}
#[no_mangle]
2017-07-31 13:36:35 +00:00
pub unsafe extern "C" fn demuxer_handle_buffer(
ptr: *mut DemuxerWrapper,
buffer: *mut gst_ffi::GstBuffer,
) -> gst_ffi::GstFlowReturn {
2016-11-24 14:29:43 +00:00
let wrap: &mut DemuxerWrapper = &mut *ptr;
panic_to_error!(
wrap,
&gst::Element::from_glib_borrow(wrap.raw as *mut _),
gst::FlowReturn::Error,
{ wrap.handle_buffer(from_glib_full(buffer)) }
).to_glib()
2016-11-24 14:29:43 +00:00
}
#[no_mangle]
pub unsafe extern "C" fn demuxer_end_of_stream(ptr: *mut DemuxerWrapper) {
let wrap: &mut DemuxerWrapper = &mut *ptr;
panic_to_error!(
wrap,
&gst::Element::from_glib_borrow(wrap.raw as *mut _),
(),
{
wrap.end_of_stream();
}
)
2016-11-24 14:29:43 +00:00
}
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,
pub create_instance: fn(&gst::Element) -> Box<Demuxer>,
pub input_caps: &'a gst::Caps,
pub output_caps: &'a gst::Caps,
2016-12-23 16:10:38 +00:00
}
pub fn demuxer_register(plugin: &gst::Plugin, demuxer_info: &DemuxerInfo) {
2016-12-23 16:10:38 +00:00
extern "C" {
2017-07-31 13:36:35 +00:00
fn gst_rs_demuxer_register(
plugin: *const gst_ffi::GstPlugin,
2017-07-31 13:36:35 +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,
input_caps: *const gst_ffi::GstCaps,
output_caps: *const gst_ffi::GstCaps,
) -> glib_ffi::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 {
2017-07-31 13:36:35 +00:00
gst_rs_demuxer_register(
plugin.to_glib_none().0,
2017-07-31 13:36:35 +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,
demuxer_info.input_caps.to_glib_none().0,
demuxer_info.output_caps.to_glib_none().0,
2017-07-31 13:36:35 +00:00
);
2016-12-23 16:10:38 +00:00
}
}