use gstreamer as gst;
use gstreamer::prelude::*;
use gstreamer_base as gst_base;
use anyhow::Error;
use once_cell::sync::Lazy;
use std::cell::RefCell;
use gstreamer_video;
use gstreamer::{FlowError, FlowSuccess};
use gstreamer_base::BaseTransform;
use glib::subclass::TypeData;
use std::ptr::NonNull;
use gstreamer_base::*;
use glib;
use glib::Cast;
use std::mem;
use glib::ObjectExt;
use gstreamer_video::VideoInfo;
glib::wrapper! {
pub struct Processor(ObjectSubclass<imp::Processor>) @extends gst_base::BaseTransform, gst::Element, gst::Object;
}
impl Processor {
pub fn create(f : fn(&mut[u8]) -> bool) -> Result<Self, String> {
let proc : Self = glib::Object::new(&[("name", &Some("Processor"))])
.map_err(|e| format!("{}", e))?;
proc.set_property("func", &(f as u64))
.map_err(|e| format!("{}", e) )?;
Ok(proc)
}
}
pub static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
gst::DebugCategory::new(
"Processor",
gst::DebugColorFlags::empty(),
Some("Processor"),
)
});
mod imp {
use super::*;
use gstreamer_base::subclass::prelude::*;
use glib::subclass::prelude::ObjectSubclass;
#[derive(Default)]
pub struct Processor{ processor : RefCell<Option<fn(&mut[u8])->bool>> }
#[glib::object_subclass]
impl ObjectSubclass for Processor {
const NAME: &'static str = "Processor";
type Type = super::Processor;
type ParentType = gst_base::BaseTransform;
fn new() -> Self {
Self { processor : RefCell::new(None) }
}
}
impl ObjectImpl for Processor {
fn properties() -> &'static [glib::ParamSpec] {
use once_cell::sync::Lazy;
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![glib::ParamSpec::new_uint64(
"func",
"func",
"func",
0,
u64::max_value(),
0,
glib::ParamFlags::READWRITE,
)]
});
PROPERTIES.as_ref()
}
fn set_property(&self, obj: &Self::Type, id: usize, value: &glib::Value, pspec : &glib::ParamSpec) {
match pspec.name() {
"func" => {
if let Ok(val) = value.get::<u64>() {
unsafe {
if val == 0 {
panic!("Invalid function pointer");
}
let fn_ptr = mem::transmute::<u64, fn(&mut[u8])->bool>(val);
*(self.processor.borrow_mut()) = Some(fn_ptr);
}
} else {
println!("Invalid cast to u64");
}
},
_ => {
println!("Invalid property");
}
}
}
}
impl ElementImpl for Processor {
fn metadata() -> Option<&'static gst::subclass::ElementMetadata> {
static ELEMENT_METADATA: Lazy<gst::subclass::ElementMetadata> = Lazy::new(|| {
gst::subclass::ElementMetadata::new(
"General-purpose buffer byte processor",
"Filter/Video",
"General-purpose byte processor",
"Diego Lima",
)
});
Some(&*ELEMENT_METADATA)
}
fn pad_templates() -> &'static [gst::PadTemplate] {
static PAD_TEMPLATES: Lazy<Vec<gst::PadTemplate>> = Lazy::new(|| {
let caps = gst::Caps::new_simple("video/x-raw",&[
("format", &gstreamer_video::VideoFormat::Gray8.to_str()),
("width", &gstreamer::IntRange::<i32>::new(0, 3000)),
("height", &gstreamer::IntRange::<i32>::new(0, 3000)),
("framerate", &gstreamer::FractionRange::new(
gstreamer::Fraction::new(1, 1), gstreamer::Fraction::new(3000, 1),),
),],);
vec![
gst::PadTemplate::new(
"src",
gst::PadDirection::Src,
gst::PadPresence::Always,
&caps,
)
.unwrap(),
gst::PadTemplate::new(
"sink",
gst::PadDirection::Sink,
gst::PadPresence::Always,
&caps,
)
.unwrap(),
]
});
PAD_TEMPLATES.as_ref()
}
}
impl BaseTransformImpl for Processor {
const MODE: gst_base::subclass::BaseTransformMode =
gst_base::subclass::BaseTransformMode::AlwaysInPlace;
const PASSTHROUGH_ON_SAME_CAPS: bool = false;
const TRANSFORM_IP_ON_PASSTHROUGH: bool = false;
fn transform_ip(
&self,
element: &Self::Type,
buf: &mut gst::BufferRef,
) -> Result<gst::FlowSuccess, gst::FlowError> {
if let Ok(mut buf_8bit) = buf.map_writable() {
if let Some(processor) = *self.processor.borrow() {
match (processor)(buf_8bit.as_mut_slice()) {
true => Ok(FlowSuccess::Ok),
false => Err(FlowError::Error)
}
} else {
println!("No function bound to processor");
Err(FlowError::Error)
}
} else {
println!("Could not map into a writable buffer");
Err(FlowError::Error)
}
}
}
unsafe impl Send for Processor {}
unsafe impl Sync for Processor {}
}