playsink: Add a software color-balance element before the sink if the sink doesn...
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Wed, 22 Feb 2012 10:56:59 +0000 (11:56 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Wed, 22 Feb 2012 11:08:10 +0000 (12:08 +0100)
gst/playback/gstplay-enum.c
gst/playback/gstplay-enum.h
gst/playback/gstplaybin2.c
gst/playback/gstplaysink.c
gst/playback/gstplaysinkaudioconvert.c
gst/playback/gstplaysinkvideoconvert.c
gst/playback/gstplaysinkvideoconvert.h

index e337fdf..4fe137d 100644 (file)
@@ -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;
index 77a34cf..457d90c 100644 (file)
@@ -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())
index ce429f1..dde0cb8 100644 (file)
@@ -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
index 5017620..d8f2c3b 100644 (file)
@@ -33,6 +33,7 @@
 #include <gst/pbutils/pbutils.h>
 #include <gst/video/video.h>
 #include <gst/interfaces/streamvolume.h>
+#include <gst/interfaces/colorbalance.h>
 
 #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)
 {
index a0756bc..77504da 100644 (file)
@@ -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))
index 72a9aff..85a5d2b 100644 (file)
@@ -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);
 }
index df56d97..5c50462 100644 (file)
@@ -43,6 +43,10 @@ struct _GstPlaySinkVideoConvert
 {
   GstPlaySinkConvertBin parent;
 
+  /* < pseudo public > */
+  GstElement *balance;
+  gboolean use_converters;
+  gboolean use_balance;
 };
 
 struct _GstPlaySinkVideoConvertClass