From dfa508ffa1ec5031f62735372acf4e21c8c9cf86 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 22 Feb 2012 11:56:59 +0100 Subject: [PATCH] playsink: Add a software color-balance element before the sink if the sink doesn't support changing the color-balance --- gst/playback/gstplay-enum.c | 2 + gst/playback/gstplay-enum.h | 3 +- gst/playback/gstplaybin2.c | 2 +- gst/playback/gstplaysink.c | 37 ++++++++- gst/playback/gstplaysinkaudioconvert.c | 1 - gst/playback/gstplaysinkvideoconvert.c | 147 +++++++++++++++++++++++++++++++-- gst/playback/gstplaysinkvideoconvert.h | 4 + 7 files changed, 180 insertions(+), 16 deletions(-) diff --git a/gst/playback/gstplay-enum.c b/gst/playback/gstplay-enum.c index e337fdf..4fe137d 100644 --- a/gst/playback/gstplay-enum.c +++ b/gst/playback/gstplay-enum.c @@ -65,6 +65,8 @@ gst_play_flags_get_type (void) "buffering"}, {C_FLAGS (GST_PLAY_FLAG_DEINTERLACE), "Deinterlace video if necessary", "deinterlace"}, + {C_FLAGS (GST_PLAY_FLAG_SOFT_COLORBALANCE), "Use software color balance", + "soft-colorbalance"}, {0, NULL, NULL} }; static volatile GType id = 0; diff --git a/gst/playback/gstplay-enum.h b/gst/playback/gstplay-enum.h index 77a34cf..457d90c 100644 --- a/gst/playback/gstplay-enum.h +++ b/gst/playback/gstplay-enum.h @@ -70,7 +70,8 @@ typedef enum { GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6), GST_PLAY_FLAG_DOWNLOAD = (1 << 7), GST_PLAY_FLAG_BUFFERING = (1 << 8), - GST_PLAY_FLAG_DEINTERLACE = (1 << 9) + GST_PLAY_FLAG_DEINTERLACE = (1 << 9), + GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10) } GstPlayFlags; #define GST_TYPE_PLAY_FLAGS (gst_play_flags_get_type()) diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index ce429f1..dde0cb8 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -458,7 +458,7 @@ struct _GstPlayBinClass #define DEFAULT_SUBURI NULL #define DEFAULT_SOURCE NULL #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 DEFAULT_N_VIDEO 0 #define DEFAULT_CURRENT_VIDEO -1 #define DEFAULT_N_AUDIO 0 diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index 5017620..d8f2c3b 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "gstplaysink.h" #include "gststreamsynchronizer.h" @@ -45,7 +46,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)) @@ -1249,6 +1250,22 @@ link_failed: } } +static gboolean +has_color_balance_element (GstElement * element) +{ + GstElement *cb = NULL; + + if (GST_IS_COLOR_BALANCE (element)) + return TRUE; + else if (!GST_IS_BIN (element)) + return FALSE; + + cb = gst_bin_get_by_interface (GST_BIN (element), GST_TYPE_COLOR_BALANCE); + gst_object_unref (cb); + + return (cb != NULL); +} + /* make the element (bin) that contains the elements needed to perform * video display. * @@ -1347,10 +1364,17 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) head = prev = chain->queue; } - if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) { + if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO) + || (!has_color_balance_element (chain->sink) + && (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) + && (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_bin_add (bin, chain->conv); if (prev) { if (!gst_element_link_pads_full (prev, "src", chain->conv, "sink", @@ -1461,6 +1485,12 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async) GST_DEBUG_OBJECT (playsink, "no async property on the sink"); chain->async = TRUE; } + + if (chain->conv) + g_object_set (chain->conv, "use-balance", + !has_color_balance_element (chain->sink) + && (playsink->flags & GST_PLAY_FLAG_SOFT_COLORBALANCE), NULL); + return TRUE; } @@ -3753,7 +3783,6 @@ gst_play_sink_get_property (GObject * object, guint prop_id, } } - gboolean gst_play_sink_plugin_init (GstPlugin * plugin) { diff --git a/gst/playback/gstplaysinkaudioconvert.c b/gst/playback/gstplaysinkaudioconvert.c index a0756bc..77504da 100644 --- a/gst/playback/gstplaysinkaudioconvert.c +++ b/gst/playback/gstplaysinkaudioconvert.c @@ -64,7 +64,6 @@ gst_play_sink_audio_convert_add_conversion_elements (GstPlaySinkAudioConvert * el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin, "audioresample", "resample"); if (el) { - if (prev) { if (!gst_element_link_pads_full (prev, "src", el, "sink", GST_PAD_LINK_CHECK_TEMPLATE_CAPS)) diff --git a/gst/playback/gstplaysinkvideoconvert.c b/gst/playback/gstplaysinkvideoconvert.c index 72a9aff..85a5d2b 100644 --- a/gst/playback/gstplaysinkvideoconvert.c +++ b/gst/playback/gstplaysinkvideoconvert.c @@ -34,6 +34,13 @@ GST_DEBUG_CATEGORY_STATIC (gst_play_sink_video_convert_debug); G_DEFINE_TYPE (GstPlaySinkVideoConvert, gst_play_sink_video_convert, GST_TYPE_PLAY_SINK_CONVERT_BIN); +enum +{ + PROP_0, + PROP_USE_CONVERTERS, + PROP_USE_BALANCE, +}; + static gboolean gst_play_sink_video_convert_add_conversion_elements (GstPlaySinkVideoConvert * self) @@ -41,22 +48,51 @@ gst_play_sink_video_convert_add_conversion_elements (GstPlaySinkVideoConvert * GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self); GstElement *el, *prev = NULL; - el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin, - COLORSPACE, "conv"); - if (el) - prev = el; + g_assert (cbin->conversion_elements == NULL); + + GST_DEBUG_OBJECT (self, + "Building video conversion with use-converters %d, use-balance %d", + self->use_converters, self->use_balance); + + if (self->use_converters) { + el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin, + COLORSPACE, "conv"); + if (el) + prev = el; + + el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin, + "videoscale", "scale"); + if (el) { + /* Add black borders if necessary to keep the DAR */ + g_object_set (el, "add-borders", TRUE, NULL); + if (prev) { + if (!gst_element_link_pads_full (prev, "src", el, "sink", + GST_PAD_LINK_CHECK_TEMPLATE_CAPS)) + goto link_failed; + } + prev = el; + } + } - el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin, - "videoscale", "scale"); - if (el) { - /* Add black borders if necessary to keep the DAR */ - g_object_set (el, "add-borders", TRUE, NULL); + if (self->use_balance && self->balance) { + el = self->balance; + gst_play_sink_convert_bin_add_conversion_element (cbin, el); if (prev) { if (!gst_element_link_pads_full (prev, "src", el, "sink", GST_PAD_LINK_CHECK_TEMPLATE_CAPS)) goto link_failed; } prev = el; + + el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin, + COLORSPACE, "conv"); + if (prev) { + if (!gst_element_link_pads_full (prev, "src", el, "sink", + GST_PAD_LINK_CHECK_TEMPLATE_CAPS)) + goto link_failed; + } + if (el) + prev = el; } return TRUE; @@ -66,15 +102,100 @@ link_failed: } static void +gst_play_sink_video_convert_finalize (GObject * object) +{ + GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (object); + + if (self->balance) + gst_object_unref (self->balance); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_play_sink_video_convert_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (object); + gboolean v, changed = FALSE; + + GST_PLAY_SINK_CONVERT_BIN_LOCK (self); + switch (prop_id) { + case PROP_USE_CONVERTERS: + v = g_value_get_boolean (value); + if (v != self->use_converters) { + self->use_converters = v; + changed = TRUE; + } + break; + case PROP_USE_BALANCE: + v = g_value_get_boolean (value); + if (v != self->use_balance) { + self->use_balance = v; + changed = TRUE; + } + break; + default: + break; + } + + if (changed) { + GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self); + GST_DEBUG_OBJECT (self, "Rebuilding converter bin"); + gst_play_sink_convert_bin_remove_elements (cbin); + gst_play_sink_video_convert_add_conversion_elements (self); + gst_play_sink_convert_bin_add_identity (cbin); + gst_play_sink_convert_bin_cache_converter_caps (cbin); + } + GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self); +} + +static void +gst_play_sink_video_convert_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (object); + + GST_PLAY_SINK_CONVERT_BIN_LOCK (self); + switch (prop_id) { + case PROP_USE_CONVERTERS: + g_value_set_boolean (value, self->use_converters); + break; + case PROP_USE_BALANCE: + g_value_set_boolean (value, self->use_balance); + break; + default: + break; + } + GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self); +} + +static void gst_play_sink_video_convert_class_init (GstPlaySinkVideoConvertClass * klass) { + GObjectClass *gobject_class; GstElementClass *gstelement_class; GST_DEBUG_CATEGORY_INIT (gst_play_sink_video_convert_debug, "playsinkvideoconvert", 0, "play bin"); + gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; + gobject_class->finalize = gst_play_sink_video_convert_finalize; + gobject_class->set_property = gst_play_sink_video_convert_set_property; + gobject_class->get_property = gst_play_sink_video_convert_get_property; + + g_object_class_install_property (gobject_class, PROP_USE_CONVERTERS, + g_param_spec_boolean ("use-converters", "Use converters", + "Whether to use conversion elements", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_USE_BALANCE, + g_param_spec_boolean ("use-balance", "Use balance", + "Whether to use a videobalance element", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_element_class_set_details_simple (gstelement_class, "Player Sink Video Converter", "Video/Bin/Converter", "Convenience bin for video conversion", @@ -87,6 +208,14 @@ gst_play_sink_video_convert_init (GstPlaySinkVideoConvert * self) GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self); cbin->audio = FALSE; + /* FIXME: Only create this on demand but for now we need + * it to always exist because of playsink's color balance + * proxying logic. + */ + self->balance = gst_element_factory_make ("videobalance", "videobalance"); + if (self->balance) + gst_object_ref_sink (self->balance); + gst_play_sink_video_convert_add_conversion_elements (self); gst_play_sink_convert_bin_cache_converter_caps (cbin); } diff --git a/gst/playback/gstplaysinkvideoconvert.h b/gst/playback/gstplaysinkvideoconvert.h index df56d97..5c50462 100644 --- a/gst/playback/gstplaysinkvideoconvert.h +++ b/gst/playback/gstplaysinkvideoconvert.h @@ -43,6 +43,10 @@ struct _GstPlaySinkVideoConvert { GstPlaySinkConvertBin parent; + /* < pseudo public > */ + GstElement *balance; + gboolean use_converters; + gboolean use_balance; }; struct _GstPlaySinkVideoConvertClass -- 2.7.4