在 Rust 中,有没有一种方法可以将 `gstreamer::Bin` 子类化,这样我仍然拥有它的原始方法?

In Rust, is there a way to subclass `gstreamer::Bin` such that I still have its original methods?

我正在尝试子类化 gstreamer::Bin 以覆盖它的 Bin::handle_message 方法,目的是拦截流结束消息,丢弃它们并发出它们被丢弃的信号(使用默认 Bin::handle_message 不是流结束消息时的行为)。

问题是,我仍然需要它的原始方法(如 Bin::addBin::add_pad 等),因为我需要叠加在原始 gstreamer::Bin 之上的唯一行为是像前面提到的消息拦截。

我提到我仍然需要它的原始方法,因为当我尝试遵循 this 示例时,我编写的结果 CustomBin 不满足 IsA<Bin>,因此,没有资格全面实施 gstreamer::GstBinExt,这反过来又使其没有原始的 gstreamer::Bin 方法。

我也遇到了 this 示例,但最终我不想为我想要动态添加和从我的管道中删除的每组元素重新实现消息拦截行为。我也不需要将其注册为适当的元素,我只需要在我自己的箱子中使用它,以及其中定义的管道。

作为参考,我将在下面附上我实现这一目标的尝试。

我错过了什么?


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
    }
}

您的 CustomBin 结构是类型的内部实现,而不是 glib::Object(或 gst::Bin)本身。如果您将它与例如Java 那么这就是所有私有字段和受保护的虚拟方法。

这足以创建一个新实例并将其用作其任何父实例 类

let obj: glib::Object = glib::Object::new(CustomBin::get_type(), &[("name", "bla")]).unwrap();
let bin: gst::Bin = obj.downcast::<gst::Bin>().unwrap();

请注意上面的 objbin 不是您的 CustomBin 结构。

要在 CustomBin 周围创建 public Rust API,您可以使用 glib_wrapper! macro. You can find an example of that here。不要只看那些突出显示的行,还要看它上面的所有代码。