2021-04-09 12:38:02 +00:00
|
|
|
//
|
|
|
|
// Copyright (C) 2021 Bilal Elmoussaoui <bil.elmoussaoui@gmail.com>
|
|
|
|
// Copyright (C) 2021 Jordan Petridis <jordan@centricular.com>
|
|
|
|
// Copyright (C) 2021 Sebastian Dröge <sebastian@centricular.com>
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0.
|
|
|
|
// If a copy of the MPL was not distributed with this file, You can obtain one at
|
|
|
|
// <https://mozilla.org/MPL/2.0/>.
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
|
|
use gtk::glib;
|
|
|
|
use gtk::glib::prelude::*;
|
|
|
|
use gtk::subclass::prelude::*;
|
|
|
|
|
|
|
|
use fragile::Fragile;
|
|
|
|
|
|
|
|
use std::sync::{mpsc, MutexGuard};
|
|
|
|
|
|
|
|
mod frame;
|
|
|
|
mod imp;
|
|
|
|
mod paintable;
|
|
|
|
|
|
|
|
use frame::Frame;
|
2022-10-27 17:50:40 +00:00
|
|
|
use paintable::Paintable;
|
2021-04-09 12:38:02 +00:00
|
|
|
|
|
|
|
enum SinkEvent {
|
|
|
|
FrameChanged,
|
|
|
|
}
|
|
|
|
|
|
|
|
glib::wrapper! {
|
|
|
|
pub struct PaintableSink(ObjectSubclass<imp::PaintableSink>)
|
|
|
|
@extends gst_video::VideoSink, gst_base::BaseSink, gst::Element, gst::Object;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PaintableSink {
|
|
|
|
pub fn new(name: Option<&str>) -> Self {
|
2022-10-07 18:07:48 +00:00
|
|
|
glib::Object::new(&[("name", &name)])
|
2021-04-09 12:38:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn pending_frame(&self) -> Option<Frame> {
|
2022-01-17 18:09:18 +00:00
|
|
|
let imp = self.imp();
|
|
|
|
imp.pending_frame.lock().unwrap().take()
|
2021-04-09 12:38:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn initialize_paintable(
|
|
|
|
&self,
|
|
|
|
paintable_storage: &mut MutexGuard<Option<Fragile<SinkPaintable>>>,
|
|
|
|
) {
|
2022-02-21 17:43:46 +00:00
|
|
|
gst::debug!(imp::CAT, obj: self, "Initializing paintable");
|
2021-04-09 12:38:02 +00:00
|
|
|
|
|
|
|
let context = glib::MainContext::default();
|
|
|
|
|
|
|
|
// The channel for the SinkEvents
|
|
|
|
let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
|
|
|
|
|
|
|
// This is an one time channel we send into the closure, so we can block until the paintable has been
|
|
|
|
// created.
|
|
|
|
let (send, recv) = mpsc::channel();
|
|
|
|
context.invoke(glib::clone!(
|
2022-02-04 11:51:31 +00:00
|
|
|
@weak self as sink =>
|
2021-04-09 12:38:02 +00:00
|
|
|
move || {
|
|
|
|
let paintable = Fragile::new(SinkPaintable::new());
|
|
|
|
send.send(paintable).expect("Somehow we dropped the receiver");
|
2022-02-04 11:51:31 +00:00
|
|
|
|
|
|
|
receiver.attach(
|
|
|
|
None,
|
|
|
|
glib::clone!(
|
|
|
|
@weak sink => @default-return glib::Continue(false),
|
|
|
|
move |action| sink.do_action(action)
|
|
|
|
),
|
|
|
|
);
|
2021-04-09 12:38:02 +00:00
|
|
|
}
|
|
|
|
));
|
|
|
|
|
|
|
|
let paintable = recv.recv().expect("Somehow we dropped the sender");
|
|
|
|
|
|
|
|
**paintable_storage = Some(paintable);
|
|
|
|
|
2022-01-17 18:09:18 +00:00
|
|
|
let imp = self.imp();
|
|
|
|
*imp.sender.lock().unwrap() = Some(sender);
|
2021-04-09 12:38:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn do_action(&self, action: SinkEvent) -> glib::Continue {
|
2022-01-17 18:09:18 +00:00
|
|
|
let imp = self.imp();
|
|
|
|
let paintable = imp.paintable.lock().unwrap().clone();
|
2021-04-09 12:38:02 +00:00
|
|
|
let paintable = match paintable {
|
|
|
|
Some(paintable) => paintable,
|
|
|
|
None => return glib::Continue(false),
|
|
|
|
};
|
|
|
|
|
|
|
|
match action {
|
|
|
|
SinkEvent::FrameChanged => {
|
2022-02-21 17:43:46 +00:00
|
|
|
gst::trace!(imp::CAT, obj: self, "Frame changed");
|
2021-04-09 12:38:02 +00:00
|
|
|
paintable.get().handle_frame_changed(self.pending_frame())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glib::Continue(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-31 13:12:11 +00:00
|
|
|
impl Default for PaintableSink {
|
|
|
|
fn default() -> Self {
|
|
|
|
PaintableSink::new(None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-09 12:38:02 +00:00
|
|
|
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
|
|
|
gst::Element::register(
|
|
|
|
Some(plugin),
|
|
|
|
"gtk4paintablesink",
|
|
|
|
gst::Rank::None,
|
|
|
|
PaintableSink::static_type(),
|
|
|
|
)
|
|
|
|
}
|