gstreamer_player/subclass/
player_video_renderer.rs
1use glib::{prelude::*, subclass::prelude::*, translate::*};
4
5use crate::{ffi, Player, PlayerVideoRenderer};
6
7pub trait PlayerVideoRendererImpl: ObjectImpl {
8 fn create_video_sink(&self, player: &Player) -> gst::Element;
9}
10
11unsafe impl<T: PlayerVideoRendererImpl> IsImplementable<T> for PlayerVideoRenderer {
12 fn interface_init(iface: &mut glib::Interface<Self>) {
13 let iface = iface.as_mut();
14
15 iface.create_video_sink = Some(video_renderer_create_video_sink::<T>);
16 }
17}
18
19mod sealed {
20 pub trait Sealed {}
21 impl<T: super::PlayerVideoRendererImplExt> Sealed for T {}
22}
23
24pub trait PlayerVideoRendererImplExt: sealed::Sealed + ObjectSubclass {
25 fn parent_create_video_sink(&self, player: &Player) -> gst::Element {
26 unsafe {
27 let type_data = Self::type_data();
28 let parent_iface = type_data.as_ref().parent_interface::<PlayerVideoRenderer>()
29 as *const ffi::GstPlayerVideoRendererInterface;
30
31 let func = (*parent_iface)
32 .create_video_sink
33 .expect("no parent \"create_video_sink\" implementation");
34 let ret = func(
35 self.obj()
36 .unsafe_cast_ref::<PlayerVideoRenderer>()
37 .to_glib_none()
38 .0,
39 player.to_glib_none().0,
40 );
41 from_glib_none(ret)
42 }
43 }
44}
45
46impl<T: PlayerVideoRendererImpl> PlayerVideoRendererImplExt for T {}
47
48unsafe extern "C" fn video_renderer_create_video_sink<T: PlayerVideoRendererImpl>(
49 video_renderer: *mut ffi::GstPlayerVideoRenderer,
50 player: *mut ffi::GstPlayer,
51) -> *mut gst::ffi::GstElement {
52 static VIDEO_SINK_QUARK: std::sync::OnceLock<glib::Quark> = std::sync::OnceLock::new();
53
54 let video_sink_quark =
55 VIDEO_SINK_QUARK.get_or_init(|| glib::Quark::from_str("gstreamer-rs-player-video-sink"));
56
57 let instance = &*(video_renderer as *mut T::Instance);
58 let imp = instance.imp();
59
60 let sink = imp.create_video_sink(&from_glib_borrow::<_, Player>(player));
61
62 let sink_ptr: *mut gst::ffi::GstElement = sink.to_glib_none().0;
63
64 let old_sink_ptr = glib::gobject_ffi::g_object_get_qdata(
65 video_renderer as *mut _,
66 video_sink_quark.into_glib(),
67 ) as *mut gst::ffi::GstElement;
68 if !old_sink_ptr.is_null() && old_sink_ptr != sink_ptr {
69 panic!("Video sink must not change");
70 }
71
72 unsafe extern "C" fn unref(ptr: glib::ffi::gpointer) {
73 glib::gobject_ffi::g_object_unref(ptr as *mut _);
74 }
75
76 glib::gobject_ffi::g_object_set_qdata_full(
77 video_renderer as *mut _,
78 video_sink_quark.into_glib(),
79 glib::gobject_ffi::g_object_ref(sink_ptr as *mut _) as *mut _,
80 Some(unref),
81 );
82
83 sink_ptr
84}