4 #include <gst/video/video.h>
5 #include <gst/controller/gstinterpolationcontrolsource.h>
6 #include <gst/controller/gstdirectcontrolbinding.h>
8 #define CHANGE_DIR_WITH_EVENT 0
10 static gint num_buffers = 50;
11 static gboolean camera = FALSE;
12 static gboolean randomcb = FALSE;
13 static gboolean randomdir = FALSE;
14 static gboolean randomsharpen = FALSE;
16 static GOptionEntry entries[] = {
17 {"num-buffers", 'n', 0, G_OPTION_ARG_INT, &num_buffers,
18 "Number of buffers (<= 0 : forever)", "N"},
19 {"camera", 'c', 0, G_OPTION_ARG_NONE, &camera, "Use v4l2src as video source",
21 {"random-cb", 'r', 0, G_OPTION_ARG_NONE, &randomcb,
22 "Change colorbalance randomly every second (if supported)", NULL},
23 {"random-dir", 'd', 0, G_OPTION_ARG_NONE, &randomdir,
24 "Change video direction randomly every second (if supported)", NULL},
25 {"random-sharpen", 's', 0, G_OPTION_ARG_NONE, &randomsharpen,
26 "Change sharpen filter randombly every second (if supported)", NULL},
39 GstControlSource *sharpen;
42 static GstBusSyncReply
43 context_handler (GstBus * bus, GstMessage * msg, gpointer data)
45 struct _app *app = data;
46 const gchar *context_type;
48 switch (GST_MESSAGE_TYPE (msg)) {
49 case GST_MESSAGE_HAVE_CONTEXT:{
50 GstContext *context = NULL;
52 gst_message_parse_have_context (msg, &context);
54 context_type = gst_context_get_context_type (context);
56 if (g_strcmp0 (context_type, "gst.va.display.handle") == 0) {
57 const GstStructure *s = gst_context_get_structure (context);
58 GstObject *display = NULL;
60 gst_printerr ("got have context %s from %s: ", context_type,
61 GST_MESSAGE_SRC_NAME (msg));
63 gst_structure_get (s, "gst-display", GST_TYPE_OBJECT, &display, NULL);
64 gst_printerrln ("%s", display ?
65 GST_OBJECT_NAME (display) : "no gst display");
66 gst_context_unref (context);
69 g_mutex_lock (&app->mutex);
70 gst_object_replace (&app->display, display);
71 gst_object_unref (display);
72 g_mutex_unlock (&app->mutex);
77 gst_message_unref (msg);
81 case GST_MESSAGE_NEED_CONTEXT:
82 gst_message_parse_context_type (msg, &context_type);
84 if (g_strcmp0 (context_type, "gst.va.display.handle") == 0) {
88 gst_printerr ("got need context %s from %s: ", context_type,
89 GST_MESSAGE_SRC_NAME (msg));
91 g_mutex_lock (&app->mutex);
93 g_mutex_unlock (&app->mutex);
94 gst_printerrln ("no gst display yet");
95 gst_message_unref (msg);
99 context = gst_context_new ("gst.va.display.handle", TRUE);
100 s = gst_context_writable_structure (context);
101 gst_structure_set (s, "gst-display", GST_TYPE_OBJECT, app->display,
103 gst_printerrln ("%s", GST_OBJECT_NAME (app->display));
104 gst_element_set_context (GST_ELEMENT (GST_MESSAGE_SRC (msg)), context);
105 gst_context_unref (context);
106 g_mutex_unlock (&app->mutex);
110 gst_message_unref (msg);
122 message_handler (GstBus * bus, GstMessage * msg, gpointer data)
124 struct _app *app = data;
126 switch (GST_MESSAGE_TYPE (msg)) {
127 case GST_MESSAGE_EOS:
128 g_main_loop_quit (app->loop);
130 case GST_MESSAGE_ERROR:{
134 gst_message_parse_error (msg, &err, &debug);
135 gst_printerrln ("GStreamer error: %s\n%s", err->message,
142 g_main_loop_quit (app->loop);
153 config_vpp (GstElement * vpp)
156 GObjectClass *g_class = G_OBJECT_GET_CLASS (vpp);
157 const static gchar *props[] = { "brightness", "hue", "saturation",
163 for (i = 0; i < G_N_ELEMENTS (props); i++) {
164 pspec = g_object_class_find_property (g_class, props[i]);
168 max = ((GParamSpecFloat *) pspec)->maximum;
169 g_object_set (vpp, props[i], max, NULL);
174 build_pipeline (struct _app *app)
179 GString *cmd = g_string_new (NULL);
180 const gchar *source = camera ? "v4l2src" : "videotestsrc";
182 g_string_printf (cmd, "%s name=src ! tee name=t "
183 "t. ! queue ! vapostproc name=vpp ! capsfilter name=caps ! "
184 "fpsdisplaysink video-sink=autovideosink "
185 "t. ! queue ! vapostproc ! timeoverlay ! autovideosink", source);
187 app->pipeline = gst_parse_launch (cmd->str, &err);
188 g_string_free (cmd, TRUE);
190 gst_printerrln ("Couldn't create pipeline: %s", err->message);
195 if (num_buffers > 0) {
196 src = gst_bin_get_by_name (GST_BIN (app->pipeline), "src");
197 g_object_set (src, "num-buffers", num_buffers, NULL);
198 gst_object_unref (src);
201 app->vpp = gst_bin_get_by_name (GST_BIN (app->pipeline), "vpp");
202 if (!randomcb && !randomdir && !randomsharpen)
203 config_vpp (app->vpp);
205 app->caps = gst_bin_get_by_name (GST_BIN (app->pipeline), "caps");
207 bus = gst_pipeline_get_bus (GST_PIPELINE (app->pipeline));
208 gst_bus_set_sync_handler (bus, context_handler, app, NULL);
209 gst_bus_add_watch (bus, message_handler, app);
210 gst_object_unref (bus);
216 change_cb_randomly (gpointer data)
218 struct _app *app = data;
222 if (!GST_COLOR_BALANCE_GET_INTERFACE (app->vpp))
223 return G_SOURCE_REMOVE;
225 cb = GST_COLOR_BALANCE (app->vpp);
226 channels = (GList *) gst_color_balance_list_channels (cb);
227 for (; channels && channels->data; channels = channels->next) {
228 GstColorBalanceChannel *channel = channels->data;
230 g_random_int_range (channel->min_value, channel->max_value + 1);
232 gst_color_balance_set_value (cb, channel, value);
235 return G_SOURCE_CONTINUE;
239 change_dir_randomly (gpointer data)
241 struct _app *app = data;
242 GObjectClass *g_class = G_OBJECT_GET_CLASS (app->vpp);
245 pspec = g_object_class_find_property (g_class, "video-direction");
247 return G_SOURCE_REMOVE;
249 /* choose either sent direction by property or by event */
250 #if !CHANGE_DIR_WITH_EVENT
252 GEnumClass *enumclass;
255 enumclass = G_PARAM_SPEC_ENUM (pspec)->enum_class;
256 idx = g_random_int_range (0, enumclass->n_values);
257 value = enumclass->values[idx].value;
259 g_object_set (app->vpp, "video-direction", value, NULL);
265 static const gchar *orientation[] = {
266 "rotate-0", "rotate-90", "rotate-180", "rotate-270",
267 "flip-rotate-0", "flip-rotate-90", "flip-rotate-180", "flip-rotate-270",
271 idx = g_random_int_range (0, G_N_ELEMENTS (orientation));
273 event = gst_event_new_tag (gst_tag_list_new (GST_TAG_IMAGE_ORIENTATION,
274 orientation[idx], NULL));
275 gst_element_send_event (app->pipeline, event);
279 return G_SOURCE_CONTINUE;
282 static inline GParamSpec *
283 vpp_has_sharpen (GstElement * vpp)
285 GObjectClass *g_class = G_OBJECT_GET_CLASS (vpp);
286 return g_object_class_find_property (g_class, "sharpen");
290 change_sharpen_randomly (gpointer data)
292 struct _app *app = data;
296 pspec = vpp_has_sharpen (app->vpp);
298 return G_SOURCE_REMOVE;
299 value = g_random_double_range (G_PARAM_SPEC_FLOAT (pspec)->minimum,
300 G_PARAM_SPEC_FLOAT (pspec)->maximum);
302 gst_timed_value_control_source_set (GST_TIMED_VALUE_CONTROL_SOURCE
303 (app->sharpen), GST_SECOND, value);
305 return G_SOURCE_CONTINUE;
309 parse_arguments (int *argc, char ***argv)
311 GOptionContext *ctxt;
314 ctxt = g_option_context_new ("— Multiple VA postprocessors");
315 g_option_context_add_main_entries (ctxt, entries, NULL);
316 g_option_context_add_group (ctxt, gst_init_get_option_group ());
318 if (!g_option_context_parse (ctxt, argc, argv, &err)) {
319 gst_printerrln ("option parsing failed: %s", err->message);
324 g_option_context_free (ctxt);
329 main (int argc, char **argv)
332 struct _app app = { NULL, };
333 int ret = EXIT_FAILURE;
335 if (!parse_arguments (&argc, &argv))
338 g_mutex_init (&app.mutex);
340 app.loop = g_main_loop_new (NULL, TRUE);
342 if (!build_pipeline (&app))
346 g_timeout_add_seconds (1, change_cb_randomly, &app);
349 #if CHANGE_DIR_WITH_EVENT
350 gst_util_set_object_arg (G_OBJECT (app.vpp), "video-direction", "auto");
352 g_timeout_add_seconds (1, change_dir_randomly, &app);
355 if (randomsharpen && vpp_has_sharpen (app.vpp)) {
356 GstControlBinding *bind;
358 app.sharpen = gst_interpolation_control_source_new ();
359 bind = gst_direct_control_binding_new_absolute (GST_OBJECT (app.vpp),
360 "sharpen", app.sharpen);
361 gst_object_add_control_binding (GST_OBJECT (app.vpp), bind);
362 g_object_set (app.sharpen, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);
364 change_sharpen_randomly (&app);
365 g_timeout_add_seconds (1, change_sharpen_randomly, &app);
368 gst_element_set_state (app.pipeline, GST_STATE_PLAYING);
370 g_main_loop_run (app.loop);
372 gst_element_set_state (app.pipeline, GST_STATE_NULL);
374 bus = gst_pipeline_get_bus (GST_PIPELINE (app.pipeline));
375 gst_bus_remove_watch (bus);
376 gst_object_unref (bus);
378 gst_clear_object (&app.display);
382 gst_clear_object (&app.caps);
383 gst_clear_object (&app.vpp);
384 gst_clear_object (&app.pipeline);
385 gst_clear_object (&app.sharpen);
388 g_mutex_clear (&app.mutex);
389 g_main_loop_unref (app.loop);