gstreamer-rs/gstreamer-editing-services/src/subclass/formatter.rs
Bilal Elmoussaoui 4ebec84f5e Adapt to no longer renamed ffi crates
Allows us to set all the crates in the main workspace file, so changing
their versions or branch is much simpler and reduce the amount of noise
in the diff

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1450>
2024-06-02 11:20:55 +02:00

353 lines
10 KiB
Rust

// Take a look at the license at the top of the repository in the LICENSE file.
use crate::{ffi, prelude::*, Formatter};
use glib::{subclass::prelude::*, translate::*};
pub trait FormatterImpl: FormatterImplExt + ObjectImpl + Send + Sync {
fn can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
self.parent_can_load_uri(uri)
}
fn load_from_uri(&self, timeline: &crate::Timeline, uri: &str) -> Result<(), glib::Error> {
self.parent_load_from_uri(timeline, uri)
}
fn save_to_uri(
&self,
timeline: &crate::Timeline,
uri: &str,
overwrite: bool,
) -> Result<(), glib::Error> {
self.parent_save_to_uri(timeline, uri, overwrite)
}
}
mod sealed {
pub trait Sealed {}
impl<T: super::FormatterImplExt> Sealed for T {}
}
pub trait FormatterImplExt: sealed::Sealed + ObjectSubclass {
fn parent_can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
let f = (*parent_class)
.can_load_uri
.expect("Missing parent function `can_load_uri`");
let mut error = std::ptr::null_mut();
let res = f(
self.obj()
.unsafe_cast_ref::<crate::Formatter>()
.to_glib_none()
.0,
uri.to_glib_none().0,
&mut error,
);
if res == glib::ffi::GFALSE {
if error.is_null() {
Err(glib::Error::new(
gst::CoreError::Failed,
"Can load uri failed",
))
} else {
Err(from_glib_full(error))
}
} else {
Ok(())
}
}
}
fn parent_load_from_uri(
&self,
timeline: &crate::Timeline,
uri: &str,
) -> Result<(), glib::Error> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
let f = (*parent_class)
.load_from_uri
.expect("Missing parent function `load_from_uri`");
let mut error = std::ptr::null_mut();
let res = f(
self.obj()
.unsafe_cast_ref::<crate::Formatter>()
.to_glib_none()
.0,
timeline
.unsafe_cast_ref::<crate::Timeline>()
.to_glib_none()
.0,
uri.to_glib_none().0,
&mut error,
);
if res == glib::ffi::GFALSE {
if error.is_null() {
Err(glib::Error::new(
gst::CoreError::Failed,
"Load from uri failed",
))
} else {
Err(from_glib_full(error))
}
} else {
Ok(())
}
}
}
fn parent_save_to_uri(
&self,
timeline: &crate::Timeline,
uri: &str,
overwrite: bool,
) -> Result<(), glib::Error> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GESFormatterClass;
let f = (*parent_class)
.save_to_uri
.expect("Missing parent function `save_to_uri`");
let mut error = std::ptr::null_mut();
let res = f(
self.obj()
.unsafe_cast_ref::<crate::Formatter>()
.to_glib_none()
.0,
timeline
.unsafe_cast_ref::<crate::Timeline>()
.to_glib_none()
.0,
uri.to_glib_none().0,
overwrite.into_glib(),
&mut error,
);
if res == glib::ffi::GFALSE {
if error.is_null() {
Err(glib::Error::new(
gst::CoreError::Failed,
"Save to uri failed",
))
} else {
Err(from_glib_full(error))
}
} else {
Ok(())
}
}
}
}
impl<T: FormatterImpl> FormatterImplExt for T {}
unsafe impl<T: FormatterImpl> IsSubclassable<T> for Formatter {
fn class_init(klass: &mut glib::Class<Self>) {
Self::parent_class_init::<T>(klass);
let klass = klass.as_mut();
klass.can_load_uri = Some(formatter_can_load_uri::<T>);
klass.load_from_uri = Some(formatter_load_from_uri::<T>);
klass.save_to_uri = Some(formatter_save_to_uri::<T>);
}
}
unsafe extern "C" fn formatter_can_load_uri<T: FormatterImpl>(
ptr: *mut ffi::GESFormatter,
uri: *const libc::c_char,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
match imp.can_load_uri(glib::GString::from_glib_borrow(uri).as_str()) {
Err(err) => {
if !error.is_null() {
*error = err.into_glib_ptr();
}
glib::ffi::GFALSE
}
Ok(_) => glib::ffi::GTRUE,
}
}
unsafe extern "C" fn formatter_load_from_uri<T: FormatterImpl>(
ptr: *mut ffi::GESFormatter,
timeline: *mut ffi::GESTimeline,
uri: *const libc::c_char,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let timeline = from_glib_borrow(timeline);
match imp.load_from_uri(&timeline, glib::GString::from_glib_borrow(uri).as_str()) {
Err(err) => {
if !error.is_null() {
*error = err.into_glib_ptr();
}
glib::ffi::GFALSE
}
Ok(_) => glib::ffi::GTRUE,
}
}
unsafe extern "C" fn formatter_save_to_uri<T: FormatterImpl>(
ptr: *mut ffi::GESFormatter,
timeline: *mut ffi::GESTimeline,
uri: *const libc::c_char,
overwrite: glib::ffi::gboolean,
error: *mut *mut glib::ffi::GError,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let timeline = from_glib_borrow(timeline);
match imp.save_to_uri(
&timeline,
glib::GString::from_glib_borrow(uri).as_str(),
from_glib(overwrite),
) {
Err(err) => {
if !error.is_null() {
*error = err.into_glib_ptr();
}
glib::ffi::GFALSE
}
Ok(_) => glib::ffi::GTRUE,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Formatter;
pub mod imp {
use super::*;
#[derive(Default)]
pub struct SimpleFormatter;
#[glib::object_subclass]
impl ObjectSubclass for SimpleFormatter {
const NAME: &'static str = "SimpleFormatter";
type Type = super::SimpleFormatter;
type ParentType = Formatter;
}
impl ObjectImpl for SimpleFormatter {}
impl FormatterImpl for SimpleFormatter {
fn can_load_uri(&self, uri: &str) -> Result<(), glib::Error> {
if uri.starts_with("ges:test") {
Ok(())
} else {
self.parent_can_load_uri(uri)
}
}
fn load_from_uri(
&self,
timeline: &crate::Timeline,
_uri: &str,
) -> Result<(), glib::Error> {
timeline.append_layer();
Ok(())
}
fn save_to_uri(
&self,
timeline: &crate::Timeline,
uri: &str,
_overwrite: bool,
) -> Result<(), glib::Error> {
unsafe { timeline.set_data("saved", uri.to_string()) };
Ok(())
}
}
}
glib::wrapper! {
pub struct SimpleFormatter(ObjectSubclass<imp::SimpleFormatter>) @extends Formatter, gst::Object;
}
impl SimpleFormatter {
pub fn new() -> Self {
glib::Object::builder().build()
}
}
impl Default for SimpleFormatter {
fn default() -> Self {
Self::new()
}
}
#[test]
fn test_formatter_subclass() {
crate::init().unwrap();
let formatter = SimpleFormatter::new();
formatter
.can_load_uri("ges:test:")
.expect("We can load anything...");
assert!(formatter.can_load_uri("nottest").is_err());
let timeline = crate::Timeline::new();
assert_eq!(timeline.layers().len(), 0);
#[allow(deprecated)]
formatter
.load_from_uri(&timeline, "test")
.expect("We can load anything...");
assert_eq!(timeline.layers().len(), 1);
unsafe {
assert_eq!(timeline.data::<Option<String>>("saved"), None);
}
#[allow(deprecated)]
formatter
.save_to_uri(&timeline, "test", false)
.expect("We can save anything...");
unsafe {
assert_eq!(
timeline.data::<String>("saved").unwrap().as_ref(),
&"test".to_string()
);
}
Formatter::register(
SimpleFormatter::static_type(),
"SimpleFormatter",
None,
None,
None,
1.0,
gst::Rank::PRIMARY,
);
let proj = crate::Project::new(Some("ges:test:"));
let timeline = proj
.extract()
.unwrap()
.downcast::<crate::Timeline>()
.unwrap();
assert_eq!(timeline.layers().len(), 1);
let proj = crate::Project::new(Some("ges:notest:"));
assert!(proj.extract().is_err());
}
}