diff --git a/examples/src/bin/rtsp-server-subclass.rs b/examples/src/bin/rtsp-server-subclass.rs index 80f12f9d7..c4f646050 100644 --- a/examples/src/bin/rtsp-server-subclass.rs +++ b/examples/src/bin/rtsp-server-subclass.rs @@ -98,6 +98,7 @@ mod media_factory { // up the class data impl ObjectSubclass for Factory { const NAME: &'static str = "RsRTSPMediaFactory"; + type Type = super::Factory; type ParentType = gst_rtsp_server::RTSPMediaFactory; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; @@ -114,12 +115,8 @@ mod media_factory { // Implementation of glib::Object virtual methods impl ObjectImpl for Factory { - fn constructed(&self, obj: &glib::Object) { - self.parent_constructed(obj); - - let factory = obj - .downcast_ref::() - .unwrap(); + fn constructed(&self, factory: &Self::Type) { + self.parent_constructed(factory); // All media created by this factory are our custom media type. This would // not require a media factory subclass and can also be called on the normal @@ -199,6 +196,7 @@ mod media { // up the class data impl ObjectSubclass for Media { const NAME: &'static str = "RsRTSPMedia"; + type Type = super::Media; type ParentType = gst_rtsp_server::RTSPMedia; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; @@ -266,6 +264,7 @@ mod server { // up the class data impl ObjectSubclass for Server { const NAME: &'static str = "RsRTSPServer"; + type Type = super::Server; type ParentType = gst_rtsp_server::RTSPServer; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; @@ -353,6 +352,7 @@ mod client { // up the class data impl ObjectSubclass for Client { const NAME: &'static str = "RsRTSPClient"; + type Type = super::Client; type ParentType = gst_rtsp_server::RTSPClient; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; diff --git a/examples/src/bin/subclass.rs b/examples/src/bin/subclass.rs index d06b43a75..5d7ecdd50 100644 --- a/examples/src/bin/subclass.rs +++ b/examples/src/bin/subclass.rs @@ -62,6 +62,7 @@ mod fir_filter { // up the class data impl ObjectSubclass for FirFilter { const NAME: &'static str = "RsFirFilter"; + type Type = super::FirFilter; type ParentType = gst_base::BaseTransform; type Instance = gst::subclass::ElementInstanceStruct; type Class = subclass::simple::ClassStruct; @@ -88,7 +89,7 @@ mod fir_filter { // will automatically instantiate pads for them. // // Our element here can only handle F32 mono audio. - fn class_init(klass: &mut subclass::simple::ClassStruct) { + fn class_init(klass: &mut Self::Class) { // Set the element specific metadata. This information is what // is visible from gst-inspect-1.0 and can also be programatically // retrieved from the gst::Registry after initial registration diff --git a/gstreamer/src/subclass/clock.rs b/gstreamer/src/subclass/clock.rs index a0961aef0..96133252b 100644 --- a/gstreamer/src/subclass/clock.rs +++ b/gstreamer/src/subclass/clock.rs @@ -81,7 +81,7 @@ pub trait ClockImplExt { fn wake_id(&self, id: &ClockId) where Self: ObjectSubclass, - ::ParentType: IsA; + ::Type: IsA; } impl ClockImplExt for T { @@ -199,7 +199,7 @@ impl ClockImplExt for T { fn wake_id(&self, id: &ClockId) where Self: ObjectSubclass, - ::ParentType: IsA, + ::Type: IsA, { let clock = self.get_instance(); diff --git a/gstreamer/src/subclass/element.rs b/gstreamer/src/subclass/element.rs index f9ab509a5..df2997cc7 100644 --- a/gstreamer/src/subclass/element.rs +++ b/gstreamer/src/subclass/element.rs @@ -549,145 +549,175 @@ mod tests { use glib::subclass; use std::sync::atomic; - struct TestElement { - srcpad: ::Pad, - sinkpad: ::Pad, - n_buffers: atomic::AtomicU32, - reached_playing: atomic::AtomicBool, + pub mod imp { + use super::*; + + pub struct TestElement { + pub(super) srcpad: ::Pad, + pub(super) sinkpad: ::Pad, + pub(super) n_buffers: atomic::AtomicU32, + pub(super) reached_playing: atomic::AtomicBool, + } + + impl TestElement { + fn sink_chain( + &self, + _pad: &::Pad, + _element: &::Element, + buffer: ::Buffer, + ) -> Result<::FlowSuccess, ::FlowError> { + self.n_buffers.fetch_add(1, atomic::Ordering::SeqCst); + self.srcpad.push(buffer) + } + + fn sink_event(&self, _pad: &::Pad, _element: &::Element, event: ::Event) -> bool { + self.srcpad.push_event(event) + } + + fn sink_query( + &self, + _pad: &::Pad, + _element: &::Element, + query: &mut ::QueryRef, + ) -> bool { + self.srcpad.peer_query(query) + } + + fn src_event(&self, _pad: &::Pad, _element: &::Element, event: ::Event) -> bool { + self.sinkpad.push_event(event) + } + + fn src_query( + &self, + _pad: &::Pad, + _element: &::Element, + query: &mut ::QueryRef, + ) -> bool { + self.sinkpad.peer_query(query) + } + } + + impl ObjectSubclass for TestElement { + const NAME: &'static str = "TestElement"; + type Type = super::TestElement; + type ParentType = ::Element; + type Instance = ::subclass::ElementInstanceStruct; + type Class = subclass::simple::ClassStruct; + + glib_object_subclass!(); + + fn with_class(klass: &subclass::simple::ClassStruct) -> Self { + let templ = klass.get_pad_template("sink").unwrap(); + let sinkpad = ::Pad::builder_with_template(&templ, Some("sink")) + .chain_function(|pad, parent, buffer| { + TestElement::catch_panic_pad_function( + parent, + || Err(::FlowError::Error), + |identity, element| identity.sink_chain(pad, element, buffer), + ) + }) + .event_function(|pad, parent, event| { + TestElement::catch_panic_pad_function( + parent, + || false, + |identity, element| identity.sink_event(pad, element, event), + ) + }) + .query_function(|pad, parent, query| { + TestElement::catch_panic_pad_function( + parent, + || false, + |identity, element| identity.sink_query(pad, element, query), + ) + }) + .build(); + + let templ = klass.get_pad_template("src").unwrap(); + let srcpad = ::Pad::builder_with_template(&templ, Some("src")) + .event_function(|pad, parent, event| { + TestElement::catch_panic_pad_function( + parent, + || false, + |identity, element| identity.src_event(pad, element, event), + ) + }) + .query_function(|pad, parent, query| { + TestElement::catch_panic_pad_function( + parent, + || false, + |identity, element| identity.src_query(pad, element, query), + ) + }) + .build(); + + Self { + n_buffers: atomic::AtomicU32::new(0), + reached_playing: atomic::AtomicBool::new(false), + srcpad, + sinkpad, + } + } + + fn class_init(klass: &mut subclass::simple::ClassStruct) { + klass.set_metadata( + "Test Element", + "Generic", + "Does nothing", + "Sebastian Dröge ", + ); + + let caps = ::Caps::new_any(); + let src_pad_template = + ::PadTemplate::new("src", ::PadDirection::Src, ::PadPresence::Always, &caps) + .unwrap(); + klass.add_pad_template(src_pad_template); + + let sink_pad_template = + ::PadTemplate::new("sink", ::PadDirection::Sink, ::PadPresence::Always, &caps) + .unwrap(); + klass.add_pad_template(sink_pad_template); + } + } + + impl ObjectImpl for TestElement { + fn constructed(&self, element: &Self::Type) { + self.parent_constructed(element); + + element.add_pad(&self.sinkpad).unwrap(); + element.add_pad(&self.srcpad).unwrap(); + } + } + + impl ElementImpl for TestElement { + fn change_state( + &self, + element: &::Element, + transition: ::StateChange, + ) -> Result<::StateChangeSuccess, ::StateChangeError> { + let res = self.parent_change_state(element, transition)?; + + if transition == ::StateChange::PausedToPlaying { + self.reached_playing.store(true, atomic::Ordering::SeqCst); + } + + Ok(res) + } + } } + glib_wrapper! { + pub struct TestElement(ObjectSubclass) @extends ::Element, ::Object; + } + + unsafe impl Send for TestElement {} + unsafe impl Sync for TestElement {} + impl TestElement { - fn sink_chain( - &self, - _pad: &::Pad, - _element: &::Element, - buffer: ::Buffer, - ) -> Result<::FlowSuccess, ::FlowError> { - self.n_buffers.fetch_add(1, atomic::Ordering::SeqCst); - self.srcpad.push(buffer) - } - - fn sink_event(&self, _pad: &::Pad, _element: &::Element, event: ::Event) -> bool { - self.srcpad.push_event(event) - } - - fn sink_query(&self, _pad: &::Pad, _element: &::Element, query: &mut ::QueryRef) -> bool { - self.srcpad.peer_query(query) - } - - fn src_event(&self, _pad: &::Pad, _element: &::Element, event: ::Event) -> bool { - self.sinkpad.push_event(event) - } - - fn src_query(&self, _pad: &::Pad, _element: &::Element, query: &mut ::QueryRef) -> bool { - self.sinkpad.peer_query(query) - } - } - - impl ObjectSubclass for TestElement { - const NAME: &'static str = "TestElement"; - type ParentType = ::Element; - type Instance = ::subclass::ElementInstanceStruct; - type Class = subclass::simple::ClassStruct; - - glib_object_subclass!(); - - fn with_class(klass: &subclass::simple::ClassStruct) -> Self { - let templ = klass.get_pad_template("sink").unwrap(); - let sinkpad = ::Pad::builder_with_template(&templ, Some("sink")) - .chain_function(|pad, parent, buffer| { - TestElement::catch_panic_pad_function( - parent, - || Err(::FlowError::Error), - |identity, element| identity.sink_chain(pad, element, buffer), - ) - }) - .event_function(|pad, parent, event| { - TestElement::catch_panic_pad_function( - parent, - || false, - |identity, element| identity.sink_event(pad, element, event), - ) - }) - .query_function(|pad, parent, query| { - TestElement::catch_panic_pad_function( - parent, - || false, - |identity, element| identity.sink_query(pad, element, query), - ) - }) - .build(); - - let templ = klass.get_pad_template("src").unwrap(); - let srcpad = ::Pad::builder_with_template(&templ, Some("src")) - .event_function(|pad, parent, event| { - TestElement::catch_panic_pad_function( - parent, - || false, - |identity, element| identity.src_event(pad, element, event), - ) - }) - .query_function(|pad, parent, query| { - TestElement::catch_panic_pad_function( - parent, - || false, - |identity, element| identity.src_query(pad, element, query), - ) - }) - .build(); - - Self { - n_buffers: atomic::AtomicU32::new(0), - reached_playing: atomic::AtomicBool::new(false), - srcpad, - sinkpad, - } - } - - fn class_init(klass: &mut subclass::simple::ClassStruct) { - klass.set_metadata( - "Test Element", - "Generic", - "Does nothing", - "Sebastian Dröge ", - ); - - let caps = ::Caps::new_any(); - let src_pad_template = - ::PadTemplate::new("src", ::PadDirection::Src, ::PadPresence::Always, &caps) - .unwrap(); - klass.add_pad_template(src_pad_template); - - let sink_pad_template = - ::PadTemplate::new("sink", ::PadDirection::Sink, ::PadPresence::Always, &caps) - .unwrap(); - klass.add_pad_template(sink_pad_template); - } - } - - impl ObjectImpl for TestElement { - fn constructed(&self, obj: &glib::Object) { - self.parent_constructed(obj); - - let element = obj.downcast_ref::<::Element>().unwrap(); - element.add_pad(&self.sinkpad).unwrap(); - element.add_pad(&self.srcpad).unwrap(); - } - } - - impl ElementImpl for TestElement { - fn change_state( - &self, - element: &::Element, - transition: ::StateChange, - ) -> Result<::StateChangeSuccess, ::StateChangeError> { - let res = self.parent_change_state(element, transition)?; - - if transition == ::StateChange::PausedToPlaying { - self.reached_playing.store(true, atomic::Ordering::SeqCst); - } - - Ok(res) + pub fn new(name: Option<&str>) -> Self { + glib::Object::new(TestElement::static_type(), &[("name", &name)]) + .unwrap() + .downcast::() + .unwrap() } } @@ -695,10 +725,7 @@ mod tests { fn test_element_subclass() { ::init().unwrap(); - let element = glib::Object::new(TestElement::get_type(), &[("name", &"test")]) - .unwrap() - .downcast::<::Element>() - .unwrap(); + let element = TestElement::new(Some("test")); assert_eq!(element.get_name(), "test"); @@ -713,8 +740,10 @@ mod tests { src.set_property("num-buffers", &100i32).unwrap(); - pipeline.add_many(&[&src, &element, &sink]).unwrap(); - ::Element::link_many(&[&src, &element, &sink]).unwrap(); + pipeline + .add_many(&[&src, &element.upcast_ref(), &sink]) + .unwrap(); + ::Element::link_many(&[&src, &element.upcast_ref(), &sink]).unwrap(); pipeline.set_state(::State::Playing).unwrap(); let bus = pipeline.get_bus().unwrap(); @@ -724,7 +753,7 @@ mod tests { pipeline.set_state(::State::Null).unwrap(); - let imp = TestElement::from_instance(&element); + let imp = imp::TestElement::from_instance(&element); assert_eq!(imp.n_buffers.load(atomic::Ordering::SeqCst), 100); assert_eq!(imp.reached_playing.load(atomic::Ordering::SeqCst), true); } diff --git a/gstreamer/src/subclass/pad.rs b/gstreamer/src/subclass/pad.rs index 63b38ce4e..89629ed6a 100644 --- a/gstreamer/src/subclass/pad.rs +++ b/gstreamer/src/subclass/pad.rs @@ -93,38 +93,62 @@ mod tests { use glib::subclass; use std::sync::atomic; - struct TestPad { - linked: atomic::AtomicBool, - unlinked: atomic::AtomicBool, - } + pub mod imp { + use super::*; - impl ObjectSubclass for TestPad { - const NAME: &'static str = "TestPad"; - type ParentType = ::Pad; - type Instance = subclass::simple::InstanceStruct; - type Class = subclass::simple::ClassStruct; + pub struct TestPad { + pub(super) linked: atomic::AtomicBool, + pub(super) unlinked: atomic::AtomicBool, + } - glib_object_subclass!(); + impl ObjectSubclass for TestPad { + const NAME: &'static str = "TestPad"; + type Type = super::TestPad; + type ParentType = ::Pad; + type Instance = subclass::simple::InstanceStruct; + type Class = subclass::simple::ClassStruct; - fn new() -> Self { - Self { - linked: atomic::AtomicBool::new(false), - unlinked: atomic::AtomicBool::new(false), + glib_object_subclass!(); + + fn new() -> Self { + Self { + linked: atomic::AtomicBool::new(false), + unlinked: atomic::AtomicBool::new(false), + } + } + } + + impl ObjectImpl for TestPad {} + + impl PadImpl for TestPad { + fn linked(&self, pad: &Pad, peer: &Pad) { + self.linked.store(true, atomic::Ordering::SeqCst); + self.parent_linked(pad, peer) + } + + fn unlinked(&self, pad: &Pad, peer: &Pad) { + self.unlinked.store(true, atomic::Ordering::SeqCst); + self.parent_unlinked(pad, peer) } } } - impl ObjectImpl for TestPad {} + glib_wrapper! { + pub struct TestPad(ObjectSubclass) @extends ::Pad, ::Object; + } - impl PadImpl for TestPad { - fn linked(&self, pad: &Pad, peer: &Pad) { - self.linked.store(true, atomic::Ordering::SeqCst); - self.parent_linked(pad, peer) - } + unsafe impl Send for TestPad {} + unsafe impl Sync for TestPad {} - fn unlinked(&self, pad: &Pad, peer: &Pad) { - self.unlinked.store(true, atomic::Ordering::SeqCst); - self.parent_unlinked(pad, peer) + impl TestPad { + pub fn new(name: &str, direction: ::PadDirection) -> Self { + glib::Object::new( + TestPad::static_type(), + &[("name", &name), ("direction", &direction)], + ) + .unwrap() + .downcast::() + .unwrap() } } @@ -132,13 +156,7 @@ mod tests { fn test_pad_subclass() { ::init().unwrap(); - let pad = glib::Object::new( - TestPad::get_type(), - &[("name", &"test"), ("direction", &::PadDirection::Src)], - ) - .unwrap() - .downcast::<::Pad>() - .unwrap(); + let pad = TestPad::new("test", ::PadDirection::Src); assert_eq!(pad.get_name(), "test"); @@ -146,7 +164,7 @@ mod tests { pad.link(&otherpad).unwrap(); pad.unlink(&otherpad).unwrap(); - let imp = TestPad::from_instance(&pad); + let imp = imp::TestPad::from_instance(&pad); assert!(imp.linked.load(atomic::Ordering::SeqCst)); assert!(imp.unlinked.load(atomic::Ordering::SeqCst)); }