X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gst%2Fplayback%2Fgstplaysink.c;fp=gst%2Fplayback%2Fgstplaysink.c;h=c365378545ada445690b5e01253a7a59400f3fa7;hb=f7939bb43fca241472a61d394f2457f5978dd5ab;hp=e53b49cee1a2a5f3c8a30de16dbdb281c564a3db;hpb=502c12f8274ba97e96c8b2501550201199fdb49c;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index e53b49c..c365378 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -28,6 +28,10 @@ #include #include #include +#include +#include +#include +#include #include "gstplaysink.h" #include "gststreamsynchronizer.h" @@ -40,7 +44,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_play_sink_debug); #define VOLUME_MAX_DOUBLE 10.0 #define DEFAULT_FLAGS GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \ - GST_PLAY_FLAG_SOFT_VOLUME + GST_PLAY_FLAG_SOFT_VOLUME | GST_PLAY_FLAG_SOFT_COLORBALANCE #define GST_PLAY_CHAIN(c) ((GstPlayChain *)(c)) @@ -202,6 +206,20 @@ struct _GstPlaySink gboolean volume_changed; /* volume/mute changed while no audiochain */ gboolean mute_changed; /* ... has been created yet */ gint64 av_offset; + + /* videooverlay proxy interface */ + GstVideoOverlay *overlay_element; /* protected with LOCK */ + gboolean overlay_handle_set; + guintptr overlay_handle; + gboolean overlay_render_rectangle_set; + gint overlay_x, overlay_y, overlay_width, overlay_height; + gboolean overlay_handle_events_set; + gboolean overlay_handle_events; + + /* colorbalance proxy interface */ + GstColorBalance *colorbalance_element; + GList *colorbalance_channels; /* CONTRAST, BRIGHTNESS, HUE, SATURATION */ + gint colorbalance_values[4]; }; struct _GstPlaySinkClass @@ -324,7 +342,40 @@ gst_play_marshal_SAMPLE__BOXED (GClosure * closure, /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */ -G_DEFINE_TYPE (GstPlaySink, gst_play_sink, GST_TYPE_BIN); +static void gst_play_sink_overlay_init (gpointer g_iface, + gpointer g_iface_data); +static void gst_play_sink_navigation_init (gpointer g_iface, + gpointer g_iface_data); +static void gst_play_sink_colorbalance_init (gpointer g_iface, + gpointer g_iface_data); + +static void +_do_init (GType type) +{ + static const GInterfaceInfo svol_info = { + NULL, NULL, NULL + }; + static const GInterfaceInfo ov_info = { + gst_play_sink_overlay_init, + NULL, NULL + }; + static const GInterfaceInfo nav_info = { + gst_play_sink_navigation_init, + NULL, NULL + }; + static const GInterfaceInfo col_info = { + gst_play_sink_colorbalance_init, + NULL, NULL + }; + + g_type_add_interface_static (type, GST_TYPE_STREAM_VOLUME, &svol_info); + g_type_add_interface_static (type, GST_TYPE_VIDEO_OVERLAY, &ov_info); + g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &nav_info); + g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE, &col_info); +} + +G_DEFINE_TYPE_WITH_CODE (GstPlaySink, gst_play_sink, GST_TYPE_BIN, + _do_init (g_define_type_id)); static void gst_play_sink_class_init (GstPlaySinkClass * klass) @@ -434,6 +485,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: * @@ -505,6 +557,8 @@ gst_play_sink_class_init (GstPlaySinkClass * klass) static void gst_play_sink_init (GstPlaySink * playsink) { + GstColorBalanceChannel *channel; + /* init groups */ playsink->video_sink = NULL; playsink->audio_sink = NULL; @@ -522,6 +576,46 @@ gst_play_sink_init (GstPlaySink * playsink) g_rec_mutex_init (&playsink->lock); GST_OBJECT_FLAG_SET (playsink, GST_ELEMENT_FLAG_SINK); + + channel = + GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, + NULL)); + channel->label = g_strdup ("CONTRAST"); + channel->min_value = -1000; + channel->max_value = 1000; + playsink->colorbalance_channels = + g_list_append (playsink->colorbalance_channels, channel); + playsink->colorbalance_values[0] = 0; + + channel = + GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, + NULL)); + channel->label = g_strdup ("BRIGHTNESS"); + channel->min_value = -1000; + channel->max_value = 1000; + playsink->colorbalance_channels = + g_list_append (playsink->colorbalance_channels, channel); + playsink->colorbalance_values[1] = 0; + + channel = + GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, + NULL)); + channel->label = g_strdup ("HUE"); + channel->min_value = -1000; + channel->max_value = 1000; + playsink->colorbalance_channels = + g_list_append (playsink->colorbalance_channels, channel); + playsink->colorbalance_values[2] = 0; + + channel = + GST_COLOR_BALANCE_CHANNEL (g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, + NULL)); + channel->label = g_strdup ("SATURATION"); + channel->min_value = -1000; + channel->max_value = 1000; + playsink->colorbalance_channels = + g_list_append (playsink->colorbalance_channels, channel); + playsink->colorbalance_values[3] = 0; } static void @@ -613,6 +707,11 @@ gst_play_sink_dispose (GObject * object) playsink->stream_synchronizer = NULL; + g_list_foreach (playsink->colorbalance_channels, (GFunc) gst_object_unref, + NULL); + g_list_free (playsink->colorbalance_channels); + playsink->colorbalance_channels = NULL; + G_OBJECT_CLASS (gst_play_sink_parent_class)->dispose (object); } @@ -1231,6 +1330,149 @@ link_failed: } } +static gboolean +is_valid_color_balance_element (GstColorBalance * bal) +{ + gboolean have_brightness = FALSE; + gboolean have_contrast = FALSE; + gboolean have_hue = FALSE; + gboolean have_saturation = FALSE; + const GList *channels, *l; + + channels = gst_color_balance_list_channels (bal); + for (l = channels; l; l = l->next) { + GstColorBalanceChannel *ch = l->data; + + if (g_strrstr (ch->label, "BRIGHTNESS")) + have_brightness = TRUE; + else if (g_strrstr (ch->label, "CONTRAST")) + have_contrast = TRUE; + else if (g_strrstr (ch->label, "HUE")) + have_hue = TRUE; + else if (g_strrstr (ch->label, "SATURATION")) + have_saturation = TRUE; + } + + return have_brightness && have_contrast && have_hue && have_saturation; +} + +static void +iterate_color_balance_elements (const GValue * item, gpointer user_data) +{ + gboolean valid; + GstColorBalance *cb, **cb_out = user_data; + + cb = GST_COLOR_BALANCE (g_value_get_object (item)); + valid = is_valid_color_balance_element (cb); + if (valid) { + if (*cb_out + && gst_color_balance_get_balance_type (*cb_out) == + GST_COLOR_BALANCE_SOFTWARE) { + gst_object_unref (*cb_out); + *cb_out = GST_COLOR_BALANCE (gst_object_ref (cb)); + } else if (!*cb_out) { + *cb_out = GST_COLOR_BALANCE (gst_object_ref (cb)); + } + } +} + +static GstColorBalance * +find_color_balance_element (GstElement * element) +{ + GstIterator *it; + GstColorBalance *cb = NULL; + + if (GST_IS_COLOR_BALANCE (element) + && is_valid_color_balance_element (GST_COLOR_BALANCE (element))) + return GST_COLOR_BALANCE (gst_object_ref (element)); + else if (!GST_IS_BIN (element)) + return FALSE; + + it = gst_bin_iterate_all_by_interface (GST_BIN (element), + GST_TYPE_COLOR_BALANCE); + while (gst_iterator_foreach (it, iterate_color_balance_elements, + &cb) == GST_ITERATOR_RESYNC) + gst_iterator_resync (it); + gst_iterator_free (it); + + return cb; +} + +static void +colorbalance_value_changed_cb (GstColorBalance * balance, + GstColorBalanceChannel * channel, gint value, GstPlaySink * playsink) +{ + GList *l; + gint i; + + for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) { + GstColorBalanceChannel *proxy = l->data; + + if (g_strrstr (channel->label, proxy->label)) { + gdouble new_val; + + /* Convert to [0, 1] range */ + new_val = + ((gdouble) value - + (gdouble) channel->min_value) / ((gdouble) channel->max_value - + (gdouble) channel->min_value); + /* Convert to proxy range */ + new_val = + proxy->min_value + new_val * ((gdouble) proxy->max_value - + (gdouble) proxy->min_value); + playsink->colorbalance_values[i] = (gint) (0.5 + new_val); + + gst_color_balance_value_changed (GST_COLOR_BALANCE (playsink), proxy, + playsink->colorbalance_values[i]); + break; + } + } +} + +static void +update_colorbalance (GstPlaySink * playsink) +{ + GstColorBalance *balance = NULL; + GList *l; + gint i; + + GST_OBJECT_LOCK (playsink); + if (playsink->colorbalance_element) { + balance = + GST_COLOR_BALANCE (gst_object_ref (playsink->colorbalance_element)); + } + GST_OBJECT_UNLOCK (playsink); + if (!balance) + return; + + g_signal_handlers_block_by_func (balance, + G_CALLBACK (colorbalance_value_changed_cb), playsink); + + for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) { + GstColorBalanceChannel *proxy = l->data; + GstColorBalanceChannel *channel = NULL; + const GList *channels, *k; + + channels = gst_color_balance_list_channels (balance); + for (k = channels; k; k = k->next) { + GstColorBalanceChannel *tmp = k->data; + + if (g_strrstr (tmp->label, proxy->label)) { + channel = tmp; + break; + } + } + + g_assert (channel); + + gst_color_balance_set_value (balance, channel, + playsink->colorbalance_values[i]); + } + + g_signal_handlers_unblock_by_func (balance, + G_CALLBACK (colorbalance_value_changed_cb), playsink); +} + /* make the element (bin) that contains the elements needed to perform * video display. * @@ -1298,6 +1540,13 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) chain->async = TRUE; } + /* Make sure the aspect ratio is kept */ + elem = + gst_play_sink_find_property_sinks (playsink, chain->sink, + "force-aspect-ratio", G_TYPE_BOOLEAN); + if (elem) + g_object_set (elem, "force-aspect-ratio", TRUE, NULL); + /* find ts-offset element */ gst_object_replace ((GstObject **) & chain->ts_offset, (GstObject *) gst_play_sink_find_property_sinks (playsink, chain->sink, "ts-offset", @@ -1310,6 +1559,34 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) gst_object_ref_sink (bin); gst_bin_add (bin, chain->sink); + /* Get the VideoOverlay element */ + { + GstVideoOverlay *overlay = NULL; + + GST_OBJECT_LOCK (playsink); + if (playsink->overlay_element) + gst_object_unref (playsink->overlay_element); + playsink->overlay_element = + GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin), + GST_TYPE_VIDEO_OVERLAY)); + if (playsink->overlay_element) + overlay = GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + GST_OBJECT_UNLOCK (playsink); + + if (overlay) { + if (playsink->overlay_handle_set) + gst_video_overlay_set_window_handle (overlay, playsink->overlay_handle); + if (playsink->overlay_handle_events_set) + gst_video_overlay_handle_events (overlay, + playsink->overlay_handle_events); + if (playsink->overlay_render_rectangle_set) + gst_video_overlay_set_render_rectangle (overlay, + playsink->overlay_x, playsink->overlay_y, + playsink->overlay_width, playsink->overlay_height); + gst_object_unref (overlay); + } + } + /* 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 @@ -1329,10 +1606,34 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) head = prev = chain->queue; } - if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) { + GST_OBJECT_LOCK (playsink); + if (playsink->colorbalance_element) { + g_signal_handlers_disconnect_by_func (playsink->colorbalance_element, + G_CALLBACK (colorbalance_value_changed_cb), playsink); + gst_object_unref (playsink->colorbalance_element); + } + playsink->colorbalance_element = find_color_balance_element (chain->sink); + GST_OBJECT_UNLOCK (playsink); + + if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO) + || (!playsink->colorbalance_element + && (playsink->flags & GST_PLAY_FLAG_SOFT_COLORBALANCE))) { + gboolean use_converters = !(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO); + gboolean use_balance = !playsink->colorbalance_element + && (playsink->flags & GST_PLAY_FLAG_SOFT_COLORBALANCE); + GST_DEBUG_OBJECT (playsink, "creating videoconverter"); chain->conv = - g_object_new (GST_TYPE_PLAY_SINK_VIDEO_CONVERT, "name", "vconv", NULL); + g_object_new (GST_TYPE_PLAY_SINK_VIDEO_CONVERT, "name", "vconv", + "use-converters", use_converters, "use-balance", use_balance, NULL); + + GST_OBJECT_LOCK (playsink); + if (use_balance && GST_PLAY_SINK_VIDEO_CONVERT (chain->conv)->balance) + playsink->colorbalance_element = + GST_COLOR_BALANCE (gst_object_ref (GST_PLAY_SINK_VIDEO_CONVERT + (chain->conv)->balance)); + GST_OBJECT_UNLOCK (playsink); + gst_bin_add (bin, chain->conv); if (prev) { if (!gst_element_link_pads_full (prev, "src", chain->conv, "sink", @@ -1344,6 +1645,8 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) prev = chain->conv; } + update_colorbalance (playsink); + if (prev) { GST_DEBUG_OBJECT (playsink, "linking to sink"); if (!gst_element_link_pads_full (prev, "src", chain->sink, NULL, @@ -1390,6 +1693,7 @@ no_sinks: free_chain ((GstPlayChain *) chain); return NULL; } + link_failed: { GST_ELEMENT_ERROR (playsink, CORE, PAD, @@ -1423,8 +1727,35 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) if (ret == GST_STATE_CHANGE_FAILURE) return FALSE; - /* find ts-offset element */ + /* Get the VideoOverlay element */ + { + GstVideoOverlay *overlay = NULL; + + GST_OBJECT_LOCK (playsink); + if (playsink->overlay_element) + gst_object_unref (playsink->overlay_element); + playsink->overlay_element = + GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (chain->chain.bin), + GST_TYPE_VIDEO_OVERLAY)); + if (playsink->overlay_element) + overlay = GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + GST_OBJECT_UNLOCK (playsink); + + if (overlay) { + if (playsink->overlay_handle_set) + gst_video_overlay_set_window_handle (overlay, playsink->overlay_handle); + if (playsink->overlay_handle_events_set) + gst_video_overlay_handle_events (overlay, + playsink->overlay_handle_events); + if (playsink->overlay_render_rectangle_set) + gst_video_overlay_set_render_rectangle (overlay, + playsink->overlay_x, playsink->overlay_y, + playsink->overlay_width, playsink->overlay_height); + gst_object_unref (overlay); + } + } + /* 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)); @@ -1443,6 +1774,39 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) GST_DEBUG_OBJECT (playsink, "no async property on the sink"); chain->async = TRUE; } + + /* Make sure the aspect ratio is kept */ + elem = + gst_play_sink_find_property_sinks (playsink, chain->sink, + "force-aspect-ratio", G_TYPE_BOOLEAN); + if (elem) + g_object_set (elem, "force-aspect-ratio", TRUE, NULL); + + GST_OBJECT_LOCK (playsink); + if (playsink->colorbalance_element) { + g_signal_handlers_disconnect_by_func (playsink->colorbalance_element, + G_CALLBACK (colorbalance_value_changed_cb), playsink); + gst_object_unref (playsink->colorbalance_element); + } + playsink->colorbalance_element = find_color_balance_element (chain->sink); + GST_OBJECT_UNLOCK (playsink); + + if (chain->conv) { + gboolean use_balance = !playsink->colorbalance_element + && (playsink->flags & GST_PLAY_FLAG_SOFT_COLORBALANCE); + + g_object_set (chain->conv, "use-balance", use_balance, NULL); + + GST_OBJECT_LOCK (playsink); + if (use_balance && GST_PLAY_SINK_VIDEO_CONVERT (chain->conv)->balance) + playsink->colorbalance_element = + GST_COLOR_BALANCE (gst_object_ref (GST_PLAY_SINK_VIDEO_CONVERT + (chain->conv)->balance)); + GST_OBJECT_UNLOCK (playsink); + } + + update_colorbalance (playsink); + return TRUE; } @@ -1801,10 +2165,10 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw) } if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_AUDIO) || (!have_volume - && playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME)) { + && (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME))) { gboolean use_converters = !(playsink->flags & GST_PLAY_FLAG_NATIVE_AUDIO); gboolean use_volume = - !have_volume && playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME; + !have_volume && (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME); GST_DEBUG_OBJECT (playsink, "creating audioconvert with use-converters %d, use-volume %d", use_converters, use_volume); @@ -1821,7 +2185,7 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw) } prev = chain->conv; - if (!have_volume && playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) { + if (!have_volume && (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME)) { GstPlaySinkAudioConvert *conv = GST_PLAY_SINK_AUDIO_CONVERT_CAST (chain->conv); @@ -1974,13 +2338,14 @@ setup_audio_chain (GstPlaySink * playsink, gboolean raw) GST_PLAY_SINK_AUDIO_CONVERT_CAST (chain->conv); /* no volume, we need to add a volume element when we can */ - g_object_set (chain->conv, "use-volume", TRUE, NULL); + g_object_set (chain->conv, "use-volume", + ! !(playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME), NULL); GST_DEBUG_OBJECT (playsink, "the sink has no volume property"); /* Disconnect signals */ disconnect_chain (chain, playsink); - if (conv->volume) { + if (conv->volume && (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME)) { chain->volume = conv->volume; chain->mute = chain->volume; @@ -2164,6 +2529,19 @@ gst_play_sink_reconfigure (GstPlaySink * playsink) need_text = TRUE; } + GST_OBJECT_LOCK (playsink); + if (playsink->overlay_element) + gst_object_unref (playsink->overlay_element); + playsink->overlay_element = NULL; + + if (playsink->colorbalance_element) { + g_signal_handlers_disconnect_by_func (playsink->colorbalance_element, + G_CALLBACK (colorbalance_value_changed_cb), playsink); + gst_object_unref (playsink->colorbalance_element); + } + playsink->colorbalance_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 */ @@ -3355,6 +3733,44 @@ 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_is_video_overlay_prepare_window_handle_message (message)) { + GstVideoOverlay *overlay; + + GST_OBJECT_LOCK (playsink); + if (playsink->overlay_element + && GST_OBJECT_CAST (playsink->overlay_element) != + GST_MESSAGE_SRC (message)) { + gst_object_unref (playsink->overlay_element); + playsink->overlay_element = NULL; + } + + if (!playsink->overlay_element) + playsink->overlay_element = + GST_VIDEO_OVERLAY (gst_object_ref (GST_MESSAGE_SRC (message))); + overlay = + GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + GST_OBJECT_UNLOCK (playsink); + + GST_DEBUG_OBJECT (playsink, "Got prepare-xwindow-id message"); + + if (playsink->overlay_handle_set) + gst_video_overlay_set_window_handle (playsink->overlay_element, + playsink->overlay_handle); + if (playsink->overlay_handle_events_set) + gst_video_overlay_handle_events (playsink->overlay_element, + playsink->overlay_handle_events); + if (playsink->overlay_render_rectangle_set) + gst_video_overlay_set_render_rectangle (playsink->overlay_element, + playsink->overlay_x, playsink->overlay_y, + playsink->overlay_width, playsink->overlay_height); + + gst_object_unref (overlay); + gst_message_unref (message); + gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (playsink)); + } + break; + } default: GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message); break; @@ -3370,7 +3786,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))) { @@ -3411,9 +3826,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"); @@ -3425,10 +3838,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 */ @@ -3454,11 +3865,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; @@ -3493,6 +3901,20 @@ 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->overlay_element) + gst_object_unref (playsink->overlay_element); + playsink->overlay_element = NULL; + + if (playsink->colorbalance_element) { + g_signal_handlers_disconnect_by_func (playsink->colorbalance_element, + G_CALLBACK (colorbalance_value_changed_cb), playsink); + gst_object_unref (playsink->colorbalance_element); + } + playsink->colorbalance_element = NULL; + GST_OBJECT_UNLOCK (playsink); + ret = GST_STATE_CHANGE_SUCCESS; break; default: @@ -3602,7 +4024,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) @@ -3611,7 +4032,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); @@ -3628,7 +4048,6 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition) break; } return ret; - /* ERRORS */ activate_failed: { @@ -3643,7 +4062,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)); @@ -3690,7 +4108,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)); @@ -3735,12 +4152,273 @@ gst_play_sink_get_property (GObject * object, guint prop_id, } } +static void +gst_play_sink_overlay_expose (GstVideoOverlay * overlay) +{ + GstPlaySink *playsink = GST_PLAY_SINK (overlay); + GstVideoOverlay *overlay_element; + + GST_OBJECT_LOCK (playsink); + if (playsink->overlay_element) + overlay_element = + GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + else + overlay_element = NULL; + GST_OBJECT_UNLOCK (playsink); + + if (overlay_element) { + gst_video_overlay_expose (overlay_element); + gst_object_unref (overlay_element); + } +} + +static void +gst_play_sink_overlay_handle_events (GstVideoOverlay * overlay, + gboolean handle_events) +{ + GstPlaySink *playsink = GST_PLAY_SINK (overlay); + GstVideoOverlay *overlay_element; + + GST_OBJECT_LOCK (playsink); + if (playsink->overlay_element) + overlay_element = + GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + else + overlay_element = NULL; + GST_OBJECT_UNLOCK (playsink); + + playsink->overlay_handle_events_set = TRUE; + playsink->overlay_handle_events = handle_events; + + if (overlay_element) { + gst_video_overlay_handle_events (overlay_element, handle_events); + gst_object_unref (overlay_element); + } +} + +static void +gst_play_sink_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x, + gint y, gint width, gint height) +{ + GstPlaySink *playsink = GST_PLAY_SINK (overlay); + GstVideoOverlay *overlay_element; + + GST_OBJECT_LOCK (playsink); + if (playsink->overlay_element) + overlay_element = + GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + else + overlay_element = NULL; + GST_OBJECT_UNLOCK (playsink); + + playsink->overlay_render_rectangle_set = TRUE; + playsink->overlay_x = x; + playsink->overlay_y = y; + playsink->overlay_width = width; + playsink->overlay_height = height; + + if (overlay_element) { + gst_video_overlay_set_render_rectangle (overlay_element, x, y, width, + height); + gst_object_unref (overlay_element); + } +} + +static void +gst_play_sink_overlay_set_window_handle (GstVideoOverlay * overlay, + guintptr handle) +{ + GstPlaySink *playsink = GST_PLAY_SINK (overlay); + GstVideoOverlay *overlay_element; + + GST_OBJECT_LOCK (playsink); + if (playsink->overlay_element) + overlay_element = + GST_VIDEO_OVERLAY (gst_object_ref (playsink->overlay_element)); + else + overlay_element = NULL; + GST_OBJECT_UNLOCK (playsink); + + playsink->overlay_handle_set = TRUE; + playsink->overlay_handle = handle; + + if (overlay_element) { + gst_video_overlay_set_window_handle (overlay_element, handle); + gst_object_unref (overlay_element); + } +} + +static void +gst_play_sink_overlay_init (gpointer g_iface, gpointer g_iface_data) +{ + GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface; + iface->expose = gst_play_sink_overlay_expose; + iface->handle_events = gst_play_sink_overlay_handle_events; + iface->set_render_rectangle = gst_play_sink_overlay_set_render_rectangle; + iface->set_window_handle = gst_play_sink_overlay_set_window_handle; +} + +static void +gst_play_sink_navigation_send_event (GstNavigation * navigation, + GstStructure * structure) +{ + GstPlaySink *playsink = GST_PLAY_SINK (navigation); + GstBin *bin = NULL; + + GST_PLAY_SINK_LOCK (playsink); + if (playsink->videochain && playsink->videochain->chain.bin) + bin = GST_BIN (gst_object_ref (playsink->videochain->chain.bin)); + GST_PLAY_SINK_UNLOCK (playsink); + + if (bin) { + GstElement *nav = gst_bin_get_by_interface (bin, GST_TYPE_NAVIGATION); + + if (nav) { + gst_navigation_send_event (GST_NAVIGATION (nav), structure); + structure = NULL; + gst_object_unref (nav); + } + + gst_object_unref (bin); + } + + if (structure) + gst_structure_free (structure); +} + +static void +gst_play_sink_navigation_init (gpointer g_iface, gpointer g_iface_data) +{ + GstNavigationInterface *iface = (GstNavigationInterface *) g_iface; + + iface->send_event = gst_play_sink_navigation_send_event; +} + +static const GList * +gst_play_sink_colorbalance_list_channels (GstColorBalance * balance) +{ + GstPlaySink *playsink = GST_PLAY_SINK (balance); + + return playsink->colorbalance_channels; +} + +static void +gst_play_sink_colorbalance_set_value (GstColorBalance * balance, + GstColorBalanceChannel * proxy, gint value) +{ + GstPlaySink *playsink = GST_PLAY_SINK (balance); + GList *l; + gint i; + GstColorBalance *balance_element = NULL; + + GST_OBJECT_LOCK (playsink); + if (playsink->colorbalance_element) + balance_element = + GST_COLOR_BALANCE (gst_object_ref (playsink->colorbalance_element)); + GST_OBJECT_UNLOCK (playsink); + + for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) { + GstColorBalanceChannel *proxy_tmp = l->data; + gdouble new_val; + + if (proxy_tmp != proxy) + continue; + + playsink->colorbalance_values[i] = value; + + if (balance_element) { + GstColorBalanceChannel *channel = NULL; + const GList *channels, *k; + + channels = gst_color_balance_list_channels (balance_element); + for (k = channels; k; k = k->next) { + GstColorBalanceChannel *tmp = l->data; + + if (g_strrstr (tmp->label, proxy->label)) { + channel = tmp; + break; + } + } + + g_assert (channel); + + /* Convert to [0, 1] range */ + new_val = + ((gdouble) value - + (gdouble) proxy->min_value) / ((gdouble) proxy->max_value - + (gdouble) proxy->min_value); + /* Convert to channel range */ + new_val = + channel->min_value + new_val * ((gdouble) channel->max_value - + (gdouble) channel->min_value); + + gst_color_balance_set_value (balance_element, channel, + (gint) (new_val + 0.5)); + + gst_object_unref (balance_element); + } + + gst_color_balance_value_changed (balance, proxy, value); + break; + } +} + +static gint +gst_play_sink_colorbalance_get_value (GstColorBalance * balance, + GstColorBalanceChannel * proxy) +{ + GstPlaySink *playsink = GST_PLAY_SINK (balance); + GList *l; + gint i; + + for (i = 0, l = playsink->colorbalance_channels; l; l = l->next, i++) { + GstColorBalanceChannel *proxy_tmp = l->data; + + if (proxy_tmp != proxy) + continue; + + return playsink->colorbalance_values[i]; + } + + g_return_val_if_reached (0); +} + +static GstColorBalanceType +gst_play_sink_colorbalance_get_balance_type (GstColorBalance * balance) +{ + GstPlaySink *playsink = GST_PLAY_SINK (balance); + GstColorBalance *balance_element = NULL; + GstColorBalanceType t = GST_COLOR_BALANCE_SOFTWARE; + + GST_OBJECT_LOCK (playsink); + if (playsink->colorbalance_element) + balance_element = + GST_COLOR_BALANCE (gst_object_ref (playsink->colorbalance_element)); + GST_OBJECT_UNLOCK (playsink); + + if (balance_element) { + t = gst_color_balance_get_balance_type (balance_element); + gst_object_unref (balance_element); + } + + return t; +} + +static void +gst_play_sink_colorbalance_init (gpointer g_iface, gpointer g_iface_data) +{ + GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface; + + iface->list_channels = gst_play_sink_colorbalance_list_channels; + iface->set_value = gst_play_sink_colorbalance_set_value; + iface->get_value = gst_play_sink_colorbalance_get_value; + iface->get_balance_type = gst_play_sink_colorbalance_get_balance_type; +} 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); }