va: vpp: implement GstColorBalance interface

And modify multiple-vpp example to use it with -r parameter.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2033>
This commit is contained in:
Víctor Manuel Jáquez Leal 2021-02-24 13:06:51 +01:00 committed by GStreamer Merge Bot
parent 5b117045e0
commit 87fe2e321e
5 changed files with 219 additions and 8 deletions

View File

@ -26,7 +26,6 @@
#include <gst/video/video.h> #include <gst/video/video.h>
#include <va/va_vpp.h>
#include <va/va_drmcommon.h> #include <va/va_drmcommon.h>
#include "gstvacaps.h" #include "gstvacaps.h"
@ -665,6 +664,30 @@ gst_va_filter_install_properties (GstVaFilter * self, GObjectClass * klass)
return TRUE; 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 const gpointer
gst_va_filter_get_filter_caps (GstVaFilter * self, VAProcFilterType type, gst_va_filter_get_filter_caps (GstVaFilter * self, VAProcFilterType type,
guint * num_caps) guint * num_caps)

View File

@ -24,6 +24,8 @@
#include <gst/video/video.h> #include <gst/video/video.h>
#include <va/va_vpp.h>
G_BEGIN_DECLS G_BEGIN_DECLS
#define GST_TYPE_VA_FILTER (gst_va_filter_get_type()) #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_open (GstVaFilter * self);
gboolean gst_va_filter_close (GstVaFilter * self); gboolean gst_va_filter_close (GstVaFilter * self);
gboolean gst_va_filter_is_open (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, gboolean gst_va_filter_install_properties (GstVaFilter * self,
GObjectClass * klass); GObjectClass * klass);
gboolean gst_va_filter_set_orientation (GstVaFilter * self, gboolean gst_va_filter_set_orientation (GstVaFilter * self,

View File

@ -124,6 +124,8 @@ struct _GstVaVpp
GstVideoOrientationMethod direction; GstVideoOrientationMethod direction;
GstVideoOrientationMethod prev_direction; GstVideoOrientationMethod prev_direction;
GstVideoOrientationMethod tag_direction; GstVideoOrientationMethod tag_direction;
GList *channels;
}; };
static GstElementClass *parent_class = NULL; static GstElementClass *parent_class = NULL;
@ -162,11 +164,16 @@ static GQuark meta_tag_orientation_quark;
#define META_TAG_VIDEO meta_tag_video_quark #define META_TAG_VIDEO meta_tag_video_quark
static GQuark meta_tag_video_quark; static GQuark meta_tag_video_quark;
static void gst_va_vpp_colorbalance_init (gpointer iface, gpointer data);
static void static void
gst_va_vpp_dispose (GObject * object) gst_va_vpp_dispose (GObject * object)
{ {
GstVaVpp *self = GST_VA_VPP (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) { if (self->sinkpad_pool) {
gst_buffer_pool_set_active (self->sinkpad_pool, FALSE); gst_buffer_pool_set_active (self->sinkpad_pool, FALSE);
gst_clear_object (&self->sinkpad_pool); 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); 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 static void
gst_va_vpp_init (GTypeInstance * instance, gpointer g_class) gst_va_vpp_init (GTypeInstance * instance, gpointer g_class)
{ {
@ -2359,17 +2379,23 @@ gst_va_vpp_init (GTypeInstance * instance, gpointer g_class)
if (pspec) { if (pspec) {
self->brightness = self->brightness =
g_value_get_float (g_param_spec_get_default_value (pspec)); 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"); 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)); 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"); 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)); 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"); pspec = g_object_class_find_property (g_class, "saturation");
if (pspec) { if (pspec) {
self->saturation = self->saturation =
g_value_get_float (g_param_spec_get_default_value (pspec)); g_value_get_float (g_param_spec_get_default_value (pspec));
_create_colorbalance_channel (self, "SATURATION");
} }
/* enable QoS */ /* 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, type = g_type_register_static (GST_TYPE_BASE_TRANSFORM, type_name, &type_info,
0); 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); ret = gst_element_register (plugin, feature_name, rank, type);
g_free (type_name); g_free (type_name);
@ -2449,3 +2485,119 @@ gst_va_vpp_register (GstPlugin * plugin, GstVaDevice * device, guint rank)
return ret; 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;
}

View File

@ -21,6 +21,6 @@ executable('multiple-vpp',
'multiple-vpp.c', 'multiple-vpp.c',
install: false, install: false,
include_directories : [configinc], include_directories : [configinc],
dependencies : [gst_dep], dependencies : [gst_dep, gstvideo_dep],
c_args : gst_plugins_bad_args + ['-DGST_USE_UNSTABLE_API'], c_args : gst_plugins_bad_args + ['-DGST_USE_UNSTABLE_API'],
) )

View File

@ -1,15 +1,19 @@
#include <stdlib.h> #include <stdlib.h>
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/video/video.h>
static gint num_buffers = 50; static gint num_buffers = 50;
static gboolean camera = FALSE; static gboolean camera = FALSE;
static gboolean randomcb = FALSE;
static GOptionEntry entries[] = { static GOptionEntry entries[] = {
{"num-buffers", 'n', 0, G_OPTION_ARG_INT, &num_buffers, {"num-buffers", 'n', 0, G_OPTION_ARG_INT, &num_buffers,
"Number of buffers (<= 0 : forever)", "N"}, "Number of buffers (<= 0 : forever)", "N"},
{"camera", 'c', 0, G_OPTION_ARG_NONE, &camera, "Use v4l2src as video source", {"camera", 'c', 0, G_OPTION_ARG_NONE, &camera, "Use v4l2src as video source",
NULL}, NULL},
{"random-cb", 'r', 0, G_OPTION_ARG_NONE, &randomcb,
"Change colorbalance randomly every second", NULL},
{NULL}, {NULL},
}; };
@ -18,6 +22,7 @@ struct _app
GMainLoop *loop; GMainLoop *loop;
GstObject *display; GstObject *display;
GstElement *pipeline; GstElement *pipeline;
GstElement *vpp;
GstElement *caps; GstElement *caps;
GMutex mutex; GMutex mutex;
}; };
@ -156,7 +161,7 @@ config_vpp (GstElement * vpp)
static gboolean static gboolean
build_pipeline (struct _app *app) build_pipeline (struct _app *app)
{ {
GstElement *vpp, *src; GstElement *src;
GstBus *bus; GstBus *bus;
GError *err = NULL; GError *err = NULL;
GString *cmd = g_string_new (NULL); GString *cmd = g_string_new (NULL);
@ -180,9 +185,9 @@ build_pipeline (struct _app *app)
gst_object_unref (src); gst_object_unref (src);
} }
vpp = gst_bin_get_by_name (GST_BIN (app->pipeline), "vpp"); app->vpp = gst_bin_get_by_name (GST_BIN (app->pipeline), "vpp");
config_vpp (vpp); if (!randomcb)
gst_object_unref (vpp); config_vpp (app->vpp);
app->caps = gst_bin_get_by_name (GST_BIN (app->pipeline), "caps"); app->caps = gst_bin_get_by_name (GST_BIN (app->pipeline), "caps");
@ -194,6 +199,29 @@ build_pipeline (struct _app *app)
return TRUE; return TRUE;
} }
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 static gboolean
parse_arguments (int *argc, char ***argv) parse_arguments (int *argc, char ***argv)
{ {
@ -231,6 +259,9 @@ main (int argc, char **argv)
if (!build_pipeline (&app)) if (!build_pipeline (&app))
goto gst_failed; goto gst_failed;
if (randomcb)
g_timeout_add_seconds (1, change_cb_randomly, &app);
gst_element_set_state (app.pipeline, GST_STATE_PLAYING); gst_element_set_state (app.pipeline, GST_STATE_PLAYING);
g_main_loop_run (app.loop); g_main_loop_run (app.loop);
@ -246,6 +277,7 @@ main (int argc, char **argv)
ret = EXIT_SUCCESS; ret = EXIT_SUCCESS;
gst_clear_object (&app.caps); gst_clear_object (&app.caps);
gst_clear_object (&app.vpp);
gst_clear_object (&app.pipeline); gst_clear_object (&app.pipeline);
gst_failed: gst_failed: