我正在尝试将gstreamer::Bin
子类化以覆盖其Bin::handle_message
方法,目的是拦截流结束消息、丢弃它们并发出它们已被丢弃的信号(如果它们不是流结束消息,则使用默认的Bin::handle_message
行为(。
问题是,我仍然需要它的原始方法(如Bin::add
、Bin::add_pad
等(,因为我唯一需要堆叠在原始gstreamer::Bin
之上的行为就是前面提到的消息拦截。
我提到我仍然需要它的原始方法,因为当我试图遵循这个例子时,我编写的CustomBin
不满足IsA<Bin>
,因此不符合gstreamer::GstBinExt
的一揽子实现,这反过来又使它没有原始的gstreamer::Bin
方法。
我也遇到过这个例子,但最终我不想为我想从管道中动态添加和删除的每一组元素重新实现消息拦截行为。我也不需要将其注册为适当的元素,我只需要在我自己的机箱中使用它,以及在其中定义的管道。
作为参考,我将在下面附上我实现这一目标的尝试。
我错过了什么?
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();
请注意,上面的obj
和bin
不是您的CustomBin
结构。
要围绕CustomBin
创建公共Rust API,您需要使用glib_wrapper!
宏。你可以在这里找到一个例子。不要只看那些突出显示的行,还要看上面的所有代码