From 87fe2e321e595f83faf8b40e9a4ab5d8140c140e Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Wed, 24 Feb 2021 13:06:51 +0100 Subject: [PATCH] va: vpp: implement GstColorBalance interface And modify multiple-vpp example to use it with -r parameter. Part-of: --- sys/va/gstvafilter.c | 25 ++++++- sys/va/gstvafilter.h | 4 + sys/va/gstvavpp.c | 156 ++++++++++++++++++++++++++++++++++++++- tests/examples/va/meson.build | 2 +- tests/examples/va/multiple-vpp.c | 40 +++++++++- 5 files changed, 219 insertions(+), 8 deletions(-) diff --git a/sys/va/gstvafilter.c b/sys/va/gstvafilter.c index 99e20ab..83c1477 100644 --- a/sys/va/gstvafilter.c +++ b/sys/va/gstvafilter.c @@ -26,7 +26,6 @@ #include -#include #include #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) diff --git a/sys/va/gstvafilter.h b/sys/va/gstvafilter.h index d680671..274ea5d 100644 --- a/sys/va/gstvafilter.h +++ b/sys/va/gstvafilter.h @@ -24,6 +24,8 @@ #include +#include + 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, diff --git a/sys/va/gstvavpp.c b/sys/va/gstvavpp.c index c41fe25..c27f5dc 100644 --- a/sys/va/gstvavpp.c +++ b/sys/va/gstvavpp.c @@ -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; +} diff --git a/tests/examples/va/meson.build b/tests/examples/va/meson.build index c716eb4..5cd5b2d 100644 --- a/tests/examples/va/meson.build +++ b/tests/examples/va/meson.build @@ -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'], ) diff --git a/tests/examples/va/multiple-vpp.c b/tests/examples/va/multiple-vpp.c index c761f0b..cd8c784 100644 --- a/tests/examples/va/multiple-vpp.c +++ b/tests/examples/va/multiple-vpp.c @@ -1,15 +1,19 @@ #include #include +#include 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: -- 2.7.4