Reputation: 137
I am trying to subclass gstreamer::Bin
to override its Bin::handle_message
method, with the intention of intercepting end-of-stream messages, dropping them and signalling that they were dropped (using the default Bin::handle_message
behaviour if they're not end-of-stream messages).
The thing is, I still need its original methods (like Bin::add
, Bin::add_pad
and such) because the only behaviour that I need stacked on top of the original gstreamer::Bin
is the message interception like previously mentioned.
I mention that I still need its original methods because when I tried to follow this example, the resulting CustomBin
that I wrote did not satisfy IsA<Bin>
, and, thus, was not eligible for the blanket implementation of gstreamer::GstBinExt
, which in turn made it not have the original gstreamer::Bin
methods.
I also came across this example, but ultimately I do not want to reimplement the message interception behaviour for every set of elements that I want to dynamically add and remove from my pipeline. I also don't need to register it as an element proper, I just need to use it within my own crate, and the pipelines defined in it.
For reference, I am going to attach below my attempt of achieving this.
What am I missing?
pub struct CustomBin {
eos_guard: Mutex<Option<Sender<()>>>,
}
impl Default for CustomBin {
fn default() -> Self {
Self {
eos_guard: Mutex::new(None),
}
}
}
impl ObjectImpl for CustomBin {
glib_object_impl!();
}
impl ElementImpl for CustomBin {}
impl BinImpl for CustomBin {
fn handle_message(&self, bin: &Bin, message: Message) {
if let MessageView::Eos(_) = message.view() {
if let Some(sender) = self.eos_guard.lock().unwrap().take() {
sender.send(()).unwrap_or(());
} else {
self.parent_handle_message(bin, message);
}
} else {
self.parent_handle_message(bin, message);
}
}
}
impl ObjectSubclass for CustomBin {
const NAME: &'static str = "GstCustomBin";
type ParentType = Bin;
type Instance = ElementInstanceStruct<Self>;
type Class = ClassStruct<Self>;
glib_object_subclass!();
fn new() -> Self {
Self::default()
}
}
impl CustomBin {
pub fn install_eos_guard(&self) -> Receiver<()> {
let mut eos_guard = self.eos_guard.lock().unwrap();
let (sender, receiver) = channel();
if eos_guard.is_some() {
panic!("End-of-stream guard was already installed");
} else {
eos_guard.replace(sender);
}
receiver
}
}
Upvotes: 1
Views: 482
Reputation: 2143
Your CustomBin
struct is the internal implementation of the type and not a glib::Object
(or gst::Bin
) by itself. If you compare it with e.g. Java then this is all the private fields and protected virtual methods.
This is sufficient to create a new instance and also to use it as any of its parent classes
let obj: glib::Object = glib::Object::new(CustomBin::get_type(), &[("name", "bla")]).unwrap();
let bin: gst::Bin = obj.downcast::<gst::Bin>().unwrap();
Note that obj
and bin
above are not your CustomBin
struct.
To create a public Rust API around your CustomBin
you would use the glib_wrapper!
macro. You can find an example of that here. Don't look only at those highlighted lines but also all the code above it.
Upvotes: 2