From 993c6e006a13534fe3fa602d1926163385059e1e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 23 Feb 2012 11:33:27 +0100 Subject: [PATCH] playsink: Proxy the XOverlay interface --- gst/playback/gstplaysink.c | 267 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 251 insertions(+), 16 deletions(-) diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index 7e5bb57..ae6f1fc 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "gstplaysink.h" #include "gststreamsynchronizer.h" @@ -205,6 +206,15 @@ struct _GstPlaySink gboolean volume_changed; /* volume/mute changed while no audiochain */ gboolean mute_changed; /* ... has been created yet */ gint64 av_offset; + + /* xoverlay proxy interface */ + GstXOverlay *xoverlay_element; /* protected with LOCK */ + gboolean xoverlay_handle_set; + guintptr xoverlay_handle; + gboolean xoverlay_render_rectangle_set; + gint xoverlay_x, xoverlay_y, xoverlay_width, xoverlay_height; + gboolean xoverlay_handle_events_set; + gboolean xoverlay_handle_events; }; struct _GstPlaySinkClass @@ -327,14 +337,28 @@ gst_play_marshal_BUFFER__BOXED (GClosure * closure, /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */ +static void gst_play_sink_implements_interface_init (gpointer g_iface, + gpointer g_iface_data); +static void gst_play_sink_xoverlay_init (gpointer g_iface, + gpointer g_iface_data); static void _do_init (GType type) { + static const GInterfaceInfo impl_info = { + gst_play_sink_implements_interface_init, + NULL, NULL + }; static const GInterfaceInfo svol_info = { NULL, NULL, NULL }; + static const GInterfaceInfo xov_info = { + gst_play_sink_xoverlay_init, + NULL, NULL + }; + g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, &impl_info); g_type_add_interface_static (type, GST_TYPE_STREAM_VOLUME, &svol_info); + g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xov_info); } G_DEFINE_TYPE_WITH_CODE (GstPlaySink, gst_play_sink, GST_TYPE_BIN, @@ -450,6 +474,7 @@ gst_play_sink_class_init (GstPlaySinkClass * klass) g_param_spec_object ("audio-sink", "Audio Sink", "the audio output element to use (NULL = default sink)", GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * GstPlaySink:text-sink: * @@ -1395,6 +1420,34 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) gst_object_ref_sink (bin); gst_bin_add (bin, chain->sink); + /* Get the XOverlay element */ + { + GstXOverlay *xoverlay = NULL; + + GST_OBJECT_LOCK (playsink); + if (playsink->xoverlay_element) + gst_object_unref (playsink->xoverlay_element); + playsink->xoverlay_element = + GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin), + GST_TYPE_X_OVERLAY)); + if (playsink->xoverlay_element) + xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); + GST_OBJECT_UNLOCK (playsink); + + if (xoverlay) { + if (playsink->xoverlay_handle_set) + gst_x_overlay_set_window_handle (xoverlay, playsink->xoverlay_handle); + if (playsink->xoverlay_handle_events_set) + gst_x_overlay_handle_events (xoverlay, + playsink->xoverlay_handle_events); + if (playsink->xoverlay_render_rectangle_set) + gst_x_overlay_set_render_rectangle (xoverlay, + playsink->xoverlay_x, playsink->xoverlay_y, + playsink->xoverlay_width, playsink->xoverlay_height); + gst_object_unref (xoverlay); + } + } + /* decouple decoder from sink, this improves playback quite a lot since the * decoder can continue while the sink blocks for synchronisation. We don't * need a lot of buffers as this consumes a lot of memory and we don't want @@ -1482,6 +1535,7 @@ no_sinks: free_chain ((GstPlayChain *) chain); return NULL; } + link_failed: { GST_ELEMENT_ERROR (playsink, CORE, PAD, @@ -1515,8 +1569,35 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) if (ret == GST_STATE_CHANGE_FAILURE) return FALSE; - /* find ts-offset element */ + /* Get the XOverlay element */ + { + GstXOverlay *xoverlay = NULL; + + GST_OBJECT_LOCK (playsink); + if (playsink->xoverlay_element) + gst_object_unref (playsink->xoverlay_element); + playsink->xoverlay_element = + GST_X_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin), + GST_TYPE_X_OVERLAY)); + if (playsink->xoverlay_element) + xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); + GST_OBJECT_UNLOCK (playsink); + + if (xoverlay) { + if (playsink->xoverlay_handle_set) + gst_x_overlay_set_window_handle (xoverlay, playsink->xoverlay_handle); + if (playsink->xoverlay_handle_events_set) + gst_x_overlay_handle_events (xoverlay, + playsink->xoverlay_handle_events); + if (playsink->xoverlay_render_rectangle_set) + gst_x_overlay_set_render_rectangle (xoverlay, + playsink->xoverlay_x, playsink->xoverlay_y, + playsink->xoverlay_width, playsink->xoverlay_height); + gst_object_unref (xoverlay); + } + } + /* find ts-offset element */ gst_object_replace ((GstObject **) & chain->ts_offset, (GstObject *) gst_play_sink_find_property_sinks (playsink, chain->sink, "ts-offset", G_TYPE_INT64)); @@ -2270,6 +2351,12 @@ gst_play_sink_reconfigure (GstPlaySink * playsink) need_text = TRUE; } + GST_OBJECT_LOCK (playsink); + if (playsink->xoverlay_element) + gst_object_unref (playsink->xoverlay_element); + playsink->xoverlay_element = NULL; + GST_OBJECT_UNLOCK (playsink); + if (((flags & GST_PLAY_FLAG_VIDEO) || (flags & GST_PLAY_FLAG_NATIVE_VIDEO)) && playsink->video_pad) { /* we have video and we are requested to show it */ @@ -3428,6 +3515,43 @@ gst_play_sink_handle_message (GstBin * bin, GstMessage * message) GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message); break; } + case GST_MESSAGE_ELEMENT:{ + if (gst_structure_has_name (message->structure, "prepare-xwindow-id")) { + GstXOverlay *xoverlay; + + GST_OBJECT_LOCK (playsink); + if (playsink->xoverlay_element + && GST_OBJECT_CAST (playsink->xoverlay_element) != + GST_MESSAGE_SRC (message)) { + gst_object_unref (playsink->xoverlay_element); + playsink->xoverlay_element = NULL; + } + + if (!playsink->xoverlay_element) + playsink->xoverlay_element = + GST_X_OVERLAY (gst_object_ref (GST_MESSAGE_SRC (message))); + xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); + GST_OBJECT_UNLOCK (playsink); + + GST_DEBUG_OBJECT (playsink, "Got prepare-xwindow-id message"); + + if (playsink->xoverlay_handle_set) + gst_x_overlay_set_window_handle (playsink->xoverlay_element, + playsink->xoverlay_handle); + if (playsink->xoverlay_handle_events_set) + gst_x_overlay_handle_events (playsink->xoverlay_element, + playsink->xoverlay_handle_events); + if (playsink->xoverlay_render_rectangle_set) + gst_x_overlay_set_render_rectangle (playsink->xoverlay_element, + playsink->xoverlay_x, playsink->xoverlay_y, + playsink->xoverlay_width, playsink->xoverlay_height); + + gst_object_unref (xoverlay); + gst_message_unref (message); + gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (playsink)); + } + break; + } default: GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message); break; @@ -3443,7 +3567,6 @@ static gboolean gst_play_sink_send_event_to_sink (GstPlaySink * playsink, GstEvent * event) { gboolean res = TRUE; - if (playsink->textchain && playsink->textchain->sink) { gst_event_ref (event); if ((res = gst_element_send_event (playsink->textchain->chain.bin, event))) { @@ -3484,9 +3607,7 @@ gst_play_sink_send_event (GstElement * element, GstEvent * event) gboolean res = FALSE; GstEventType event_type = GST_EVENT_TYPE (event); GstPlaySink *playsink; - playsink = GST_PLAY_SINK_CAST (element); - switch (event_type) { case GST_EVENT_SEEK: GST_DEBUG_OBJECT (element, "Sending event to a sink"); @@ -3498,10 +3619,8 @@ gst_play_sink_send_event (GstElement * element, GstEvent * event) guint64 amount; gdouble rate; gboolean flush, intermediate; - gst_event_parse_step (event, &format, &amount, &rate, &flush, &intermediate); - if (format == GST_FORMAT_BUFFERS) { /* for buffers, we will try to step video frames, for other formats we * send the step to all sinks */ @@ -3527,11 +3646,8 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret; GstStateChangeReturn bret; - GstPlaySink *playsink; - playsink = GST_PLAY_SINK (element); - switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: playsink->need_async_start = TRUE; @@ -3559,7 +3675,6 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) GstPad *opad = GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (playsink->audio_pad))); - if (gst_pad_is_blocked (opad)) { gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb, gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); @@ -3599,6 +3714,13 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) gst_object_unref (playsink->videochain->ts_offset); playsink->videochain->ts_offset = NULL; } + + GST_OBJECT_LOCK (playsink); + if (playsink->xoverlay_element) + gst_object_unref (playsink->xoverlay_element); + playsink->xoverlay_element = NULL; + GST_OBJECT_UNLOCK (playsink); + ret = GST_STATE_CHANGE_SUCCESS; break; default: @@ -3708,7 +3830,6 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) if (playsink->textchain && playsink->textchain->sink) gst_bin_remove (GST_BIN_CAST (playsink->textchain->chain.bin), playsink->textchain->sink); - if (playsink->audio_sink != NULL) gst_element_set_state (playsink->audio_sink, GST_STATE_NULL); if (playsink->video_sink != NULL) @@ -3717,7 +3838,6 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) gst_element_set_state (playsink->visualisation, GST_STATE_NULL); if (playsink->text_sink != NULL) gst_element_set_state (playsink->text_sink, GST_STATE_NULL); - free_chain ((GstPlayChain *) playsink->videodeinterlacechain); playsink->videodeinterlacechain = NULL; free_chain ((GstPlayChain *) playsink->videochain); @@ -3734,7 +3854,6 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) break; } return ret; - /* ERRORS */ activate_failed: { @@ -3749,7 +3868,6 @@ gst_play_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * spec) { GstPlaySink *playsink = GST_PLAY_SINK (object); - switch (prop_id) { case PROP_FLAGS: gst_play_sink_set_flags (playsink, g_value_get_flags (value)); @@ -3796,7 +3914,6 @@ gst_play_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * spec) { GstPlaySink *playsink = GST_PLAY_SINK (object); - switch (prop_id) { case PROP_FLAGS: g_value_set_flags (value, gst_play_sink_get_flags (playsink)); @@ -3841,11 +3958,129 @@ gst_play_sink_get_property (GObject * object, guint prop_id, } } +static void +gst_play_sink_xoverlay_expose (GstXOverlay * overlay) +{ + GstPlaySink *playsink = GST_PLAY_SINK (overlay); + GstXOverlay *xoverlay; + + GST_OBJECT_LOCK (playsink); + if (playsink->xoverlay_element) + xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); + else + xoverlay = NULL; + GST_OBJECT_UNLOCK (playsink); + + if (xoverlay) { + gst_x_overlay_expose (xoverlay); + gst_object_unref (xoverlay); + } +} + +static void +gst_play_sink_xoverlay_handle_events (GstXOverlay * overlay, + gboolean handle_events) +{ + GstPlaySink *playsink = GST_PLAY_SINK (overlay); + GstXOverlay *xoverlay; + + GST_OBJECT_LOCK (playsink); + if (playsink->xoverlay_element) + xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); + else + xoverlay = NULL; + GST_OBJECT_UNLOCK (playsink); + + playsink->xoverlay_handle_events_set = TRUE; + playsink->xoverlay_handle_events = handle_events; + + if (xoverlay) { + gst_x_overlay_handle_events (xoverlay, handle_events); + gst_object_unref (xoverlay); + } +} + +static void +gst_play_sink_xoverlay_set_render_rectangle (GstXOverlay * overlay, gint x, + gint y, gint width, gint height) +{ + GstPlaySink *playsink = GST_PLAY_SINK (overlay); + GstXOverlay *xoverlay; + + GST_OBJECT_LOCK (playsink); + if (playsink->xoverlay_element) + xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); + else + xoverlay = NULL; + GST_OBJECT_UNLOCK (playsink); + + playsink->xoverlay_render_rectangle_set = TRUE; + playsink->xoverlay_x = x; + playsink->xoverlay_y = y; + playsink->xoverlay_width = width; + playsink->xoverlay_height = height; + + if (xoverlay) { + gst_x_overlay_set_render_rectangle (xoverlay, x, y, width, height); + gst_object_unref (xoverlay); + } +} + +static void +gst_play_sink_xoverlay_set_window_handle (GstXOverlay * overlay, + guintptr handle) +{ + GstPlaySink *playsink = GST_PLAY_SINK (overlay); + GstXOverlay *xoverlay; + + GST_OBJECT_LOCK (playsink); + if (playsink->xoverlay_element) + xoverlay = GST_X_OVERLAY (gst_object_ref (playsink->xoverlay_element)); + else + xoverlay = NULL; + GST_OBJECT_UNLOCK (playsink); + + playsink->xoverlay_handle_set = TRUE; + playsink->xoverlay_handle = handle; + + if (xoverlay) { + gst_x_overlay_set_window_handle (xoverlay, handle); + gst_object_unref (xoverlay); + } +} + +static void +gst_play_sink_xoverlay_init (gpointer g_iface, gpointer g_iface_data) +{ + GstXOverlayClass *iface = (GstXOverlayClass *) g_iface; + iface->expose = gst_play_sink_xoverlay_expose; + iface->handle_events = gst_play_sink_xoverlay_handle_events; + iface->set_render_rectangle = gst_play_sink_xoverlay_set_render_rectangle; + iface->set_window_handle = gst_play_sink_xoverlay_set_window_handle; +} + +static gboolean +gst_play_sink_implements_interface_supported (GstImplementsInterface * iface, + GType type) +{ + if (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_STREAM_VOLUME) + return TRUE; + else + return FALSE; +} + +static void +gst_play_sink_implements_interface_init (gpointer g_iface, + gpointer g_iface_data) +{ + GstImplementsInterfaceClass *iface = (GstImplementsInterfaceClass *) g_iface; + iface->supported = gst_play_sink_implements_interface_supported; +} + gboolean gst_play_sink_plugin_init (GstPlugin * plugin) { GST_DEBUG_CATEGORY_INIT (gst_play_sink_debug, "playsink", 0, "play bin"); - return gst_element_register (plugin, "playsink", GST_RANK_NONE, GST_TYPE_PLAY_SINK); } -- 2.7.4