playsink: Proxy the XOverlay interface

This commit is contained in:
Sebastian Dröge 2012-02-23 11:33:27 +01:00
parent b8343b4a14
commit 993c6e006a

View file

@ -34,6 +34,7 @@
#include <gst/video/video.h> #include <gst/video/video.h>
#include <gst/interfaces/streamvolume.h> #include <gst/interfaces/streamvolume.h>
#include <gst/interfaces/colorbalance.h> #include <gst/interfaces/colorbalance.h>
#include <gst/interfaces/xoverlay.h>
#include "gstplaysink.h" #include "gstplaysink.h"
#include "gststreamsynchronizer.h" #include "gststreamsynchronizer.h"
@ -205,6 +206,15 @@ struct _GstPlaySink
gboolean volume_changed; /* volume/mute changed while no audiochain */ gboolean volume_changed; /* volume/mute changed while no audiochain */
gboolean mute_changed; /* ... has been created yet */ gboolean mute_changed; /* ... has been created yet */
gint64 av_offset; 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 struct _GstPlaySinkClass
@ -327,14 +337,28 @@ gst_play_marshal_BUFFER__BOXED (GClosure * closure,
/* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */ /* 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 static void
_do_init (GType type) _do_init (GType type)
{ {
static const GInterfaceInfo impl_info = {
gst_play_sink_implements_interface_init,
NULL, NULL
};
static const GInterfaceInfo svol_info = { static const GInterfaceInfo svol_info = {
NULL, NULL, NULL 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_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, 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", g_param_spec_object ("audio-sink", "Audio Sink",
"the audio output element to use (NULL = default sink)", "the audio output element to use (NULL = default sink)",
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/** /**
* GstPlaySink:text-sink: * GstPlaySink:text-sink:
* *
@ -1395,6 +1420,34 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
gst_object_ref_sink (bin); gst_object_ref_sink (bin);
gst_bin_add (bin, chain->sink); 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 /* decouple decoder from sink, this improves playback quite a lot since the
* decoder can continue while the sink blocks for synchronisation. We don't * 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 * 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); free_chain ((GstPlayChain *) chain);
return NULL; return NULL;
} }
link_failed: link_failed:
{ {
GST_ELEMENT_ERROR (playsink, CORE, PAD, 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) if (ret == GST_STATE_CHANGE_FAILURE)
return FALSE; 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_object_replace ((GstObject **) & chain->ts_offset, (GstObject *)
gst_play_sink_find_property_sinks (playsink, chain->sink, "ts-offset", gst_play_sink_find_property_sinks (playsink, chain->sink, "ts-offset",
G_TYPE_INT64)); G_TYPE_INT64));
@ -2270,6 +2351,12 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
need_text = TRUE; 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) if (((flags & GST_PLAY_FLAG_VIDEO)
|| (flags & GST_PLAY_FLAG_NATIVE_VIDEO)) && playsink->video_pad) { || (flags & GST_PLAY_FLAG_NATIVE_VIDEO)) && playsink->video_pad) {
/* we have video and we are requested to show it */ /* 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); GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message);
break; 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: default:
GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message); GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message);
break; break;
@ -3443,7 +3567,6 @@ static gboolean
gst_play_sink_send_event_to_sink (GstPlaySink * playsink, GstEvent * event) gst_play_sink_send_event_to_sink (GstPlaySink * playsink, GstEvent * event)
{ {
gboolean res = TRUE; gboolean res = TRUE;
if (playsink->textchain && playsink->textchain->sink) { if (playsink->textchain && playsink->textchain->sink) {
gst_event_ref (event); gst_event_ref (event);
if ((res = gst_element_send_event (playsink->textchain->chain.bin, 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; gboolean res = FALSE;
GstEventType event_type = GST_EVENT_TYPE (event); GstEventType event_type = GST_EVENT_TYPE (event);
GstPlaySink *playsink; GstPlaySink *playsink;
playsink = GST_PLAY_SINK_CAST (element); playsink = GST_PLAY_SINK_CAST (element);
switch (event_type) { switch (event_type) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
GST_DEBUG_OBJECT (element, "Sending event to a sink"); GST_DEBUG_OBJECT (element, "Sending event to a sink");
@ -3498,10 +3619,8 @@ gst_play_sink_send_event (GstElement * element, GstEvent * event)
guint64 amount; guint64 amount;
gdouble rate; gdouble rate;
gboolean flush, intermediate; gboolean flush, intermediate;
gst_event_parse_step (event, &format, &amount, &rate, &flush, gst_event_parse_step (event, &format, &amount, &rate, &flush,
&intermediate); &intermediate);
if (format == GST_FORMAT_BUFFERS) { if (format == GST_FORMAT_BUFFERS) {
/* for buffers, we will try to step video frames, for other formats we /* for buffers, we will try to step video frames, for other formats we
* send the step to all sinks */ * send the step to all sinks */
@ -3527,11 +3646,8 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
{ {
GstStateChangeReturn ret; GstStateChangeReturn ret;
GstStateChangeReturn bret; GstStateChangeReturn bret;
GstPlaySink *playsink; GstPlaySink *playsink;
playsink = GST_PLAY_SINK (element); playsink = GST_PLAY_SINK (element);
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED: case GST_STATE_CHANGE_READY_TO_PAUSED:
playsink->need_async_start = TRUE; playsink->need_async_start = TRUE;
@ -3559,7 +3675,6 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
GstPad *opad = GstPad *opad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(playsink->audio_pad))); (playsink->audio_pad)));
if (gst_pad_is_blocked (opad)) { if (gst_pad_is_blocked (opad)) {
gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb, gst_pad_set_blocked_async_full (opad, FALSE, sinkpad_blocked_cb,
gst_object_ref (playsink), (GDestroyNotify) gst_object_unref); 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); gst_object_unref (playsink->videochain->ts_offset);
playsink->videochain->ts_offset = NULL; 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; ret = GST_STATE_CHANGE_SUCCESS;
break; break;
default: default:
@ -3708,7 +3830,6 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
if (playsink->textchain && playsink->textchain->sink) if (playsink->textchain && playsink->textchain->sink)
gst_bin_remove (GST_BIN_CAST (playsink->textchain->chain.bin), gst_bin_remove (GST_BIN_CAST (playsink->textchain->chain.bin),
playsink->textchain->sink); playsink->textchain->sink);
if (playsink->audio_sink != NULL) if (playsink->audio_sink != NULL)
gst_element_set_state (playsink->audio_sink, GST_STATE_NULL); gst_element_set_state (playsink->audio_sink, GST_STATE_NULL);
if (playsink->video_sink != 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); gst_element_set_state (playsink->visualisation, GST_STATE_NULL);
if (playsink->text_sink != NULL) if (playsink->text_sink != NULL)
gst_element_set_state (playsink->text_sink, GST_STATE_NULL); gst_element_set_state (playsink->text_sink, GST_STATE_NULL);
free_chain ((GstPlayChain *) playsink->videodeinterlacechain); free_chain ((GstPlayChain *) playsink->videodeinterlacechain);
playsink->videodeinterlacechain = NULL; playsink->videodeinterlacechain = NULL;
free_chain ((GstPlayChain *) playsink->videochain); free_chain ((GstPlayChain *) playsink->videochain);
@ -3734,7 +3854,6 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
break; break;
} }
return ret; return ret;
/* ERRORS */ /* ERRORS */
activate_failed: activate_failed:
{ {
@ -3749,7 +3868,6 @@ gst_play_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * spec) const GValue * value, GParamSpec * spec)
{ {
GstPlaySink *playsink = GST_PLAY_SINK (object); GstPlaySink *playsink = GST_PLAY_SINK (object);
switch (prop_id) { switch (prop_id) {
case PROP_FLAGS: case PROP_FLAGS:
gst_play_sink_set_flags (playsink, g_value_get_flags (value)); 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) GValue * value, GParamSpec * spec)
{ {
GstPlaySink *playsink = GST_PLAY_SINK (object); GstPlaySink *playsink = GST_PLAY_SINK (object);
switch (prop_id) { switch (prop_id) {
case PROP_FLAGS: case PROP_FLAGS:
g_value_set_flags (value, gst_play_sink_get_flags (playsink)); 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 gboolean
gst_play_sink_plugin_init (GstPlugin * plugin) gst_play_sink_plugin_init (GstPlugin * plugin)
{ {
GST_DEBUG_CATEGORY_INIT (gst_play_sink_debug, "playsink", 0, "play bin"); GST_DEBUG_CATEGORY_INIT (gst_play_sink_debug, "playsink", 0, "play bin");
return gst_element_register (plugin, "playsink", GST_RANK_NONE, return gst_element_register (plugin, "playsink", GST_RANK_NONE,
GST_TYPE_PLAY_SINK); GST_TYPE_PLAY_SINK);
} }