mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
playsink: Proxy the XOverlay interface
This commit is contained in:
parent
b8343b4a14
commit
993c6e006a
1 changed files with 251 additions and 16 deletions
|
@ -34,6 +34,7 @@
|
|||
#include <gst/video/video.h>
|
||||
#include <gst/interfaces/streamvolume.h>
|
||||
#include <gst/interfaces/colorbalance.h>
|
||||
#include <gst/interfaces/xoverlay.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue