GstVideoOrientationMethod direction;
GstVideoOrientationMethod prev_direction;
GstVideoOrientationMethod tag_direction;
+
+ GList *channels;
};
static GstElementClass *parent_class = NULL;
#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);
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)
{
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 */
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);
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;
+}
#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},
};
GMainLoop *loop;
GstObject *display;
GstElement *pipeline;
+ GstElement *vpp;
GstElement *caps;
GMutex mutex;
};
static gboolean
build_pipeline (struct _app *app)
{
- GstElement *vpp, *src;
+ GstElement *src;
GstBus *bus;
GError *err = NULL;
GString *cmd = g_string_new (NULL);
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");
}
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;
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);
ret = EXIT_SUCCESS;
gst_clear_object (&app.caps);
+ gst_clear_object (&app.vpp);
gst_clear_object (&app.pipeline);
gst_failed: