va: vpp: implement GstColorBalance interface
authorVíctor Manuel Jáquez Leal <vjaquez@igalia.com>
Wed, 24 Feb 2021 12:06:51 +0000 (13:06 +0100)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Thu, 25 Feb 2021 11:22:53 +0000 (11:22 +0000)
And modify multiple-vpp example to use it with -r parameter.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2033>

sys/va/gstvafilter.c
sys/va/gstvafilter.h
sys/va/gstvavpp.c
tests/examples/va/meson.build
tests/examples/va/multiple-vpp.c

index 99e20ab..83c1477 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <gst/video/video.h>
 
-#include <va/va_vpp.h>
 #include <va/va_drmcommon.h>
 
 #include "gstvacaps.h"
@@ -665,6 +664,30 @@ gst_va_filter_install_properties (GstVaFilter * self, GObjectClass * klass)
   return TRUE;
 }
 
+gboolean
+gst_va_filter_has_filter (GstVaFilter * self, VAProcFilterType type)
+{
+  guint i;
+
+  g_return_val_if_fail (GST_IS_VA_FILTER (self), FALSE);
+
+  if (!gst_va_filter_is_open (self))
+    return FALSE;
+
+  if (!gst_va_filter_ensure_filters (self))
+    return FALSE;
+
+  for (i = 0; i < self->available_filters->len; i++) {
+    const struct VaFilter *filter =
+        &g_array_index (self->available_filters, struct VaFilter, i);
+
+    if (filter->type == type)
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
 const gpointer
 gst_va_filter_get_filter_caps (GstVaFilter * self, VAProcFilterType type,
     guint * num_caps)
index d680671..274ea5d 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <gst/video/video.h>
 
+#include <va/va_vpp.h>
+
 G_BEGIN_DECLS
 
 #define GST_TYPE_VA_FILTER (gst_va_filter_get_type())
@@ -48,6 +50,8 @@ GstVaFilter *         gst_va_filter_new                   (GstVaDisplay * displa
 gboolean              gst_va_filter_open                  (GstVaFilter * self);
 gboolean              gst_va_filter_close                 (GstVaFilter * self);
 gboolean              gst_va_filter_is_open               (GstVaFilter * self);
+gboolean              gst_va_filter_has_filter            (GstVaFilter * self,
+                                                           VAProcFilterType type);
 gboolean              gst_va_filter_install_properties    (GstVaFilter * self,
                                                            GObjectClass * klass);
 gboolean              gst_va_filter_set_orientation       (GstVaFilter * self,
index c41fe25..c27f5dc 100644 (file)
@@ -124,6 +124,8 @@ struct _GstVaVpp
   GstVideoOrientationMethod direction;
   GstVideoOrientationMethod prev_direction;
   GstVideoOrientationMethod tag_direction;
+
+  GList *channels;
 };
 
 static GstElementClass *parent_class = NULL;
@@ -162,11 +164,16 @@ static GQuark meta_tag_orientation_quark;
 #define META_TAG_VIDEO meta_tag_video_quark
 static GQuark meta_tag_video_quark;
 
+static void gst_va_vpp_colorbalance_init (gpointer iface, gpointer data);
+
 static void
 gst_va_vpp_dispose (GObject * object)
 {
   GstVaVpp *self = GST_VA_VPP (object);
 
+  if (self->channels)
+    g_list_free_full (g_steal_pointer (&self->channels), g_object_unref);
+
   if (self->sinkpad_pool) {
     gst_buffer_pool_set_active (self->sinkpad_pool, FALSE);
     gst_clear_object (&self->sinkpad_pool);
@@ -2327,6 +2334,19 @@ gst_va_vpp_class_init (gpointer g_class, gpointer class_data)
   gst_object_unref (display);
 }
 
+static inline void
+_create_colorbalance_channel (GstVaVpp * self, const gchar * label)
+{
+  GstColorBalanceChannel *channel;
+
+  channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
+  channel->label = g_strdup_printf ("VA-%s", label);
+  channel->min_value = -1000;
+  channel->max_value = 1000;
+
+  self->channels = g_list_append (self->channels, channel);
+}
+
 static void
 gst_va_vpp_init (GTypeInstance * instance, gpointer g_class)
 {
@@ -2359,17 +2379,23 @@ gst_va_vpp_init (GTypeInstance * instance, gpointer g_class)
   if (pspec) {
     self->brightness =
         g_value_get_float (g_param_spec_get_default_value (pspec));
+    _create_colorbalance_channel (self, "BRIGHTNESS");
   }
   pspec = g_object_class_find_property (g_class, "contrast");
-  if (pspec)
+  if (pspec) {
     self->contrast = g_value_get_float (g_param_spec_get_default_value (pspec));
+    _create_colorbalance_channel (self, "CONTRAST");
+  }
   pspec = g_object_class_find_property (g_class, "hue");
-  if (pspec)
+  if (pspec) {
     self->hue = g_value_get_float (g_param_spec_get_default_value (pspec));
+    _create_colorbalance_channel (self, "HUE");
+  }
   pspec = g_object_class_find_property (g_class, "saturation");
   if (pspec) {
     self->saturation =
         g_value_get_float (g_param_spec_get_default_value (pspec));
+    _create_colorbalance_channel (self, "SATURATION");
   }
 
   /* enable QoS */
@@ -2442,6 +2468,16 @@ gst_va_vpp_register (GstPlugin * plugin, GstVaDevice * device, guint rank)
   type = g_type_register_static (GST_TYPE_BASE_TRANSFORM, type_name, &type_info,
       0);
 
+  {
+    GstVaFilter *filter = gst_va_filter_new (device->display);
+    if (gst_va_filter_open (filter)
+        && gst_va_filter_has_filter (filter, VAProcFilterColorBalance)) {
+      const GInterfaceInfo info = { gst_va_vpp_colorbalance_init, NULL, NULL };
+      g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE, &info);
+    }
+    gst_object_unref (filter);
+  }
+
   ret = gst_element_register (plugin, feature_name, rank, type);
 
   g_free (type_name);
@@ -2449,3 +2485,119 @@ gst_va_vpp_register (GstPlugin * plugin, GstVaDevice * device, guint rank)
 
   return ret;
 }
+
+/* Color Balance interface */
+static const GList *
+gst_va_vpp_colorbalance_list_channels (GstColorBalance * balance)
+{
+  GstVaVpp *self = GST_VA_VPP (balance);
+
+  return self->channels;
+}
+
+static gboolean
+_set_cb_val (GstVaVpp * self, const gchar * name,
+    GstColorBalanceChannel * channel, gint value, gfloat * cb)
+{
+  GObjectClass *klass = G_OBJECT_CLASS (GST_VA_VPP_GET_CLASS (self));
+  GParamSpec *pspec;
+  GParamSpecFloat *fpspec;
+  gfloat new_value;
+  gboolean changed;
+
+  pspec = g_object_class_find_property (klass, name);
+  if (!pspec)
+    return FALSE;
+
+  fpspec = G_PARAM_SPEC_FLOAT (pspec);
+  new_value = (value - channel->min_value) * (fpspec->maximum - fpspec->minimum)
+      / (channel->max_value - channel->min_value) + fpspec->minimum;
+
+  GST_OBJECT_LOCK (self);
+  changed = new_value != *cb;
+  *cb = new_value;
+  value = (*cb + fpspec->minimum) * (channel->max_value - channel->min_value)
+      / (fpspec->maximum - fpspec->minimum) + channel->min_value;
+  GST_OBJECT_UNLOCK (self);
+
+  if (changed) {
+    GST_INFO_OBJECT (self, "%s: %d / %f", channel->label, value, new_value);
+    gst_color_balance_value_changed (GST_COLOR_BALANCE (self), channel, value);
+  }
+
+  return TRUE;
+}
+
+static void
+gst_va_vpp_colorbalance_set_value (GstColorBalance * balance,
+    GstColorBalanceChannel * channel, gint value)
+{
+  GstVaVpp *self = GST_VA_VPP (balance);
+
+  if (g_str_has_suffix (channel->label, "HUE"))
+    _set_cb_val (self, "hue", channel, value, &self->hue);
+  else if (g_str_has_suffix (channel->label, "BRIGHTNESS"))
+    _set_cb_val (self, "brightness", channel, value, &self->brightness);
+  else if (g_str_has_suffix (channel->label, "CONTRAST"))
+    _set_cb_val (self, "contrast", channel, value, &self->contrast);
+  else if (g_str_has_suffix (channel->label, "SATURATION"))
+    _set_cb_val (self, "saturation", channel, value, &self->saturation);
+}
+
+static gboolean
+_get_cb_val (GstVaVpp * self, const gchar * name,
+    GstColorBalanceChannel * channel, gfloat * cb, gint * val)
+{
+  GObjectClass *klass = G_OBJECT_CLASS (GST_VA_VPP_GET_CLASS (self));
+  GParamSpec *pspec;
+  GParamSpecFloat *fpspec;
+
+  pspec = g_object_class_find_property (klass, name);
+  if (!pspec)
+    return FALSE;
+
+  fpspec = G_PARAM_SPEC_FLOAT (pspec);
+
+  GST_OBJECT_LOCK (self);
+  *val = (*cb + fpspec->minimum) * (channel->max_value - channel->min_value)
+      / (fpspec->maximum - fpspec->minimum) + channel->min_value;
+  GST_OBJECT_UNLOCK (self);
+
+  return TRUE;
+}
+
+static gint
+gst_va_vpp_colorbalance_get_value (GstColorBalance * balance,
+    GstColorBalanceChannel * channel)
+{
+  GstVaVpp *self = GST_VA_VPP (balance);
+  gint value = 0;
+
+  if (g_str_has_suffix (channel->label, "HUE"))
+    _get_cb_val (self, "hue", channel, &self->hue, &value);
+  else if (g_str_has_suffix (channel->label, "BRIGHTNESS"))
+    _get_cb_val (self, "brightness", channel, &self->brightness, &value);
+  else if (g_str_has_suffix (channel->label, "CONTRAST"))
+    _get_cb_val (self, "contrast", channel, &self->contrast, &value);
+  else if (g_str_has_suffix (channel->label, "SATURATION"))
+    _get_cb_val (self, "saturation", channel, &self->saturation, &value);
+
+  return value;
+}
+
+static GstColorBalanceType
+gst_va_vpp_colorbalance_get_balance_type (GstColorBalance * balance)
+{
+  return GST_COLOR_BALANCE_HARDWARE;
+}
+
+static void
+gst_va_vpp_colorbalance_init (gpointer iface, gpointer data)
+{
+  GstColorBalanceInterface *cbiface = iface;
+
+  cbiface->list_channels = gst_va_vpp_colorbalance_list_channels;
+  cbiface->set_value = gst_va_vpp_colorbalance_set_value;
+  cbiface->get_value = gst_va_vpp_colorbalance_get_value;
+  cbiface->get_balance_type = gst_va_vpp_colorbalance_get_balance_type;
+}
index c716eb4..5cd5b2d 100644 (file)
@@ -21,6 +21,6 @@ executable('multiple-vpp',
   'multiple-vpp.c',
   install: false,
   include_directories : [configinc],
-  dependencies : [gst_dep],
+  dependencies : [gst_dep, gstvideo_dep],
   c_args : gst_plugins_bad_args + ['-DGST_USE_UNSTABLE_API'],
 )
index c761f0b..cd8c784 100644 (file)
@@ -1,15 +1,19 @@
 #include <stdlib.h>
 
 #include <gst/gst.h>
+#include <gst/video/video.h>
 
 static gint num_buffers = 50;
 static gboolean camera = FALSE;
+static gboolean randomcb = FALSE;
 
 static GOptionEntry entries[] = {
   {"num-buffers", 'n', 0, G_OPTION_ARG_INT, &num_buffers,
       "Number of buffers (<= 0 : forever)", "N"},
   {"camera", 'c', 0, G_OPTION_ARG_NONE, &camera, "Use v4l2src as video source",
       NULL},
+  {"random-cb", 'r', 0, G_OPTION_ARG_NONE, &randomcb,
+      "Change colorbalance randomly every second", NULL},
   {NULL},
 };
 
@@ -18,6 +22,7 @@ struct _app
   GMainLoop *loop;
   GstObject *display;
   GstElement *pipeline;
+  GstElement *vpp;
   GstElement *caps;
   GMutex mutex;
 };
@@ -156,7 +161,7 @@ config_vpp (GstElement * vpp)
 static gboolean
 build_pipeline (struct _app *app)
 {
-  GstElement *vpp, *src;
+  GstElement *src;
   GstBus *bus;
   GError *err = NULL;
   GString *cmd = g_string_new (NULL);
@@ -180,9 +185,9 @@ build_pipeline (struct _app *app)
     gst_object_unref (src);
   }
 
-  vpp = gst_bin_get_by_name (GST_BIN (app->pipeline), "vpp");
-  config_vpp (vpp);
-  gst_object_unref (vpp);
+  app->vpp = gst_bin_get_by_name (GST_BIN (app->pipeline), "vpp");
+  if (!randomcb)
+    config_vpp (app->vpp);
 
   app->caps = gst_bin_get_by_name (GST_BIN (app->pipeline), "caps");
 
@@ -195,6 +200,29 @@ build_pipeline (struct _app *app)
 }
 
 static gboolean
+change_cb_randomly (gpointer data)
+{
+  struct _app *app = data;
+  GstColorBalance *cb;
+  GList *channels;
+
+  if (!GST_COLOR_BALANCE_GET_INTERFACE (app->vpp))
+    return G_SOURCE_REMOVE;
+
+  cb = GST_COLOR_BALANCE (app->vpp);
+  channels = (GList *) gst_color_balance_list_channels (cb);
+  for (; channels && channels->data; channels = channels->next) {
+    GstColorBalanceChannel *channel = channels->data;
+    gint value =
+        g_random_int_range (channel->min_value, channel->max_value + 1);
+
+    gst_color_balance_set_value (cb, channel, value);
+  }
+
+  return G_SOURCE_CONTINUE;
+}
+
+static gboolean
 parse_arguments (int *argc, char ***argv)
 {
   GOptionContext *ctxt;
@@ -231,6 +259,9 @@ main (int argc, char **argv)
   if (!build_pipeline (&app))
     goto gst_failed;
 
+  if (randomcb)
+    g_timeout_add_seconds (1, change_cb_randomly, &app);
+
   gst_element_set_state (app.pipeline, GST_STATE_PLAYING);
 
   g_main_loop_run (app.loop);
@@ -246,6 +277,7 @@ main (int argc, char **argv)
   ret = EXIT_SUCCESS;
 
   gst_clear_object (&app.caps);
+  gst_clear_object (&app.vpp);
   gst_clear_object (&app.pipeline);
 
 gst_failed: