summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gst/playback/gstplaysink.c353
1 files changed, 336 insertions, 17 deletions
diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c
index 3322ea49a..b59ae8ae9 100644
--- a/gst/playback/gstplaysink.c
+++ b/gst/playback/gstplaysink.c
@@ -216,6 +216,11 @@ struct _GstPlaySink
gint xoverlay_x, xoverlay_y, xoverlay_width, xoverlay_height;
gboolean xoverlay_handle_events_set;
gboolean xoverlay_handle_events;
+
+ /* colorbalance proxy interface */
+ GstColorBalance *colorbalance_element;
+ GList *colorbalance_channels; /* CONTRAST, BRIGHTNESS, HUE, SATURATION */
+ gint colorbalance_values[4];
};
struct _GstPlaySinkClass
@@ -344,6 +349,9 @@ static void gst_play_sink_xoverlay_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)
{
@@ -362,11 +370,16 @@ _do_init (GType type)
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_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_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,
@@ -553,6 +566,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;
@@ -570,6 +585,46 @@ gst_play_sink_init (GstPlaySink * playsink)
g_static_rec_mutex_init (&playsink->lock);
GST_OBJECT_FLAG_SET (playsink, GST_ELEMENT_IS_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
@@ -661,6 +716,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);
}
@@ -1314,32 +1374,117 @@ static void
iterate_color_balance_elements (gpointer data, gpointer user_data)
{
gboolean valid = is_valid_color_balance_element (data);
- gboolean *valid_out = user_data;
-
- *valid_out = *valid_out && valid;
+ GstColorBalance **cb_out = user_data;
+
+ 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 (data));
+ } else if (!*cb_out) {
+ *cb_out = GST_COLOR_BALANCE (gst_object_ref (data));
+ }
+ }
gst_object_unref (data);
}
-static gboolean
-has_color_balance_element (GstElement * element)
+static GstColorBalance *
+find_color_balance_element (GstElement * element)
{
GstIterator *it;
- gboolean valid = FALSE;
+ GstColorBalance *cb = NULL;
- if (GST_IS_COLOR_BALANCE (element))
- return is_valid_color_balance_element (element);
+ if (GST_IS_COLOR_BALANCE (element)
+ && is_valid_color_balance_element (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,
- &valid) == GST_ITERATOR_RESYNC)
+ &cb) == GST_ITERATOR_RESYNC)
gst_iterator_resync (it);
gst_iterator_free (it);
- return valid;
+ 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_disconnect_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_connect (balance, "value-changed",
+ G_CALLBACK (colorbalance_value_changed_cb), playsink);
}
/* make the element (bin) that contains the elements needed to perform
@@ -1475,17 +1620,34 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
head = prev = chain->queue;
}
+ 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)
- || (!has_color_balance_element (chain->sink)
+ || (!playsink->colorbalance_element
&& (playsink->flags & GST_PLAY_FLAG_SOFT_COLORBALANCE))) {
gboolean use_converters = !(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO);
- gboolean use_balance = !has_color_balance_element (chain->sink)
+ 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",
"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",
@@ -1497,6 +1659,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,
@@ -1632,10 +1796,30 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
if (elem)
g_object_set (elem, "force-aspect-ratio", TRUE, NULL);
- if (chain->conv)
- g_object_set (chain->conv, "use-balance",
- !has_color_balance_element (chain->sink)
- && (playsink->flags & GST_PLAY_FLAG_SOFT_COLORBALANCE), 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;
}
@@ -2363,6 +2547,13 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
if (playsink->xoverlay_element)
gst_object_unref (playsink->xoverlay_element);
playsink->xoverlay_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)
@@ -3727,6 +3918,13 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
if (playsink->xoverlay_element)
gst_object_unref (playsink->xoverlay_element);
playsink->xoverlay_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;
@@ -4072,7 +4270,7 @@ gst_play_sink_implements_interface_supported (GstImplementsInterface * iface,
GType type)
{
if (type == GST_TYPE_X_OVERLAY || type == GST_TYPE_STREAM_VOLUME ||
- type == GST_TYPE_NAVIGATION)
+ type == GST_TYPE_NAVIGATION || type == GST_TYPE_COLOR_BALANCE)
return TRUE;
else
return FALSE;
@@ -4122,6 +4320,127 @@ gst_play_sink_navigation_init (gpointer g_iface, gpointer g_iface_data)
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)
+{
+ GstColorBalanceClass *iface = (GstColorBalanceClass *) 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)
{