From: Tim-Philipp Müller Date: Sat, 30 Jun 2012 15:50:10 +0000 (+0100) Subject: tests: add test for switching video effects at run time X-Git-Tag: 1.19.3~511^2~6266 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1046936be533bf1ff566582c342e2c029cd8fff6;p=platform%2Fupstream%2Fgstreamer.git tests: add test for switching video effects at run time Bases on test app in bug #614296. Doesn't work reliably yet, leads to not-negotiated errors sooner or later, even when it's the same element being re-plugged. --- diff --git a/tests/icles/Makefile.am b/tests/icles/Makefile.am index ad619e01e6..7b76da9193 100644 --- a/tests/icles/Makefile.am +++ b/tests/icles/Makefile.am @@ -72,6 +72,10 @@ stress_playbin_SOURCES = stress-playbin.c stress_playbin_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) stress_playbin_LDADD = $(GST_LIBS) $(LIBM) +test_effect_switch_SOURCES = test-effect-switch.c +test_effect_switch_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) +test_effect_switch_LDADD = $(GST_LIBS) + test_scale_SOURCES = test-scale.c test_scale_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) test_scale_LDADD = $(GST_LIBS) $(LIBM) @@ -82,4 +86,4 @@ test_box_LDADD = $(GST_LIBS) $(LIBM) noinst_PROGRAMS = $(X_TESTS) $(PANGO_TESTS) \ audio-trickplay playbin-text position-formats stress-playbin \ - test-scale test-box + test-scale test-box test-effect-switch diff --git a/tests/icles/test-effect-switch.c b/tests/icles/test-effect-switch.c new file mode 100644 index 0000000000..a99c0ee0c9 --- /dev/null +++ b/tests/icles/test-effect-switch.c @@ -0,0 +1,231 @@ +/* GStreamer dynamic effect change test app + * Copyright (C) 2012 Tim-Philipp Müller + + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Based on python script by Thiago Sousa Santos + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +static gchar *opt_effects = NULL; + +#define DEFAULT_EFFECTS "identity,exclusion,navigationtest," \ + "agingtv,videoflip,vertigotv,gaussianblur,identity" + +static GstElement *conv_before; +static GstElement *conv_after; +static GstElement *cur_effect; +static GstElement *pipeline; + +static GQueue effects = G_QUEUE_INIT; + + +#if 0 +static GstPadProbeReturn +pad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) +{ + GstElement *next = user_data; + + GST_ERROR_OBJECT (pad, "pad is idle now"); + + gst_element_set_state (cur_effect, GST_STATE_NULL); + + /* remove unlinks automatically */ + GST_ERROR_OBJECT (pipeline, "removing %" GST_PTR_FORMAT, cur_effect); + gst_bin_remove (GST_BIN (pipeline), cur_effect); + GST_ERROR_OBJECT (pipeline, "adding %" GST_PTR_FORMAT, next); + gst_bin_add (GST_BIN (pipeline), next); + GST_ERROR_OBJECT (pipeline, "linking.."); + gst_element_link_many (conv_before, next, conv_after, NULL); + gst_element_set_state (next, GST_STATE_PLAYING); + cur_effect = next; + /* FIXME: this seems to not work */ + gst_pad_remove_probe (pad, info->id); + g_print ("Done\n"); + /* FIXME: returning PROBE_REMOVE from an idle probe seems to do nothing */ + return GST_PAD_PROBE_REMOVE; +} +#endif + +static gboolean +timeout_cb (gpointer user_data) +{ + GMainLoop *loop = user_data; + GstElement *next; + gulong block_id; + GstPad *pad; + + g_queue_push_tail (&effects, gst_object_ref (cur_effect)); + + next = g_queue_pop_head (&effects); + + if (next == NULL) { + g_main_loop_quit (loop); + return FALSE; + } + + g_print ("Switching from '%s' to '%s'..\n", GST_OBJECT_NAME (cur_effect), + GST_OBJECT_NAME (next)); + + pad = gst_element_get_static_pad (conv_before, "src"); + + block_id = + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BLOCK, NULL, NULL, NULL); + g_print ("Blocked\n"); + gst_pad_remove_probe (pad, block_id); + gst_element_set_state (cur_effect, GST_STATE_NULL); + + /* remove unlinks automatically */ + gst_bin_remove (GST_BIN (pipeline), cur_effect); + g_print ("Removed\n"); + gst_bin_add (GST_BIN (pipeline), next); + g_print ("Added\n"); + gst_element_link_many (conv_before, next, conv_after, NULL); + g_print ("Re-linked\n"); + gst_element_set_state (next, GST_STATE_PLAYING); + cur_effect = next; + gst_element_set_state (pipeline, GST_STATE_PLAYING); + /* FIXME: we have to remove the block before we link, otherwise the + * caps queries on linking will deadlock us - check if that's intentional */ +#if 0 + gst_pad_remove_probe (pad, block_id); +#endif + g_print ("Done\n\n\n"); + + /* FIXME: waiting for the pad to be idle, and then relinking from there + * doesn't seem to work very well either for some reason, and returning + * GST_PAD_PROBE_REMOVE does not seem to work. Doing the same from a + * BLOCKING callback has the same problem as above */ +#if 0 + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_IDLE, pad_probe_cb, next, NULL); +#endif + + return TRUE; +} + +static gboolean +bus_cb (GstBus * bus, GstMessage * msg, gpointer user_data) +{ + GMainLoop *loop = user_data; + + switch (GST_MESSAGE_TYPE (msg)) { + case GST_MESSAGE_ERROR:{ + GError *err = NULL; + gchar *dbg; + + gst_message_parse_error (msg, &err, &dbg); + gst_object_default_error (msg->src, err, dbg); + g_error_free (err); + g_free (dbg); + g_main_loop_quit (loop); + break; + } + default: + break; + } + return TRUE; +} + +int +main (int argc, char **argv) +{ + GOptionEntry options[] = { + {"effects", 'e', 0, G_OPTION_ARG_STRING, &opt_effects, + "Effects to use (comma-separated list of element names)", NULL}, + {NULL} + }; + GOptionContext *ctx; + GError *err = NULL; + GMainLoop *loop; + GstElement *src, *q1, *q2, *effect, *filter1, *filter2, *sink; + gchar **effect_names, **e; + + ctx = g_option_context_new (""); + g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE); + g_option_context_add_group (ctx, gst_init_get_option_group ()); + if (!g_option_context_parse (ctx, &argc, &argv, &err)) { + g_print ("Error initializing: %s\n", err->message); + return 1; + } + g_option_context_free (ctx); + + GST_FIXME ("Multiple things to check/fix, see source code"); + + if (opt_effects != NULL) + effect_names = g_strsplit (opt_effects, ",", -1); + else + effect_names = g_strsplit (DEFAULT_EFFECTS, ",", -1); + + for (e = effect_names; e != NULL && *e != NULL; ++e) { + g_print ("Adding effect '%s'\n", *e); + g_queue_push_tail (&effects, gst_element_factory_make (*e, NULL)); + } + + pipeline = gst_pipeline_new ("pipeline"); + + src = gst_element_factory_make ("videotestsrc", NULL); + g_object_set (src, "is-live", TRUE, NULL); + + filter1 = gst_element_factory_make ("capsfilter", NULL); + gst_util_set_object_arg (G_OBJECT (filter1), "caps", + "video/x-raw, format=I420, width=320, height=240, " + "format={ I420, YV12, YUY2, UYVY, AYUV, Y41B, Y42B, " + "YVYU, Y444, v210, v216, NV12, NV21, UYVP, A420, YUV9, YVU9, IYU1 }"); + + q1 = gst_element_factory_make ("queue", NULL); + + conv_before = gst_element_factory_make ("videoconvert", NULL); + + effect = g_queue_pop_head (&effects); + cur_effect = effect; + + conv_after = gst_element_factory_make ("videoconvert", NULL); + + q2 = gst_element_factory_make ("queue", NULL); + + filter2 = gst_element_factory_make ("capsfilter", NULL); + gst_util_set_object_arg (G_OBJECT (filter2), "caps", + "video/x-raw, width=320, height=240, " + "format={ RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR }"); + + sink = gst_element_factory_make ("ximagesink", NULL); + + gst_bin_add_many (GST_BIN (pipeline), src, filter1, q1, conv_before, effect, + conv_after, q2, sink, NULL); + + gst_element_link_many (src, filter1, q1, conv_before, effect, conv_after, + q2, sink, NULL); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + loop = g_main_loop_new (NULL, FALSE); + + gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), bus_cb, loop); + + g_timeout_add_seconds (1, timeout_cb, loop); + + g_main_loop_run (loop); + + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); + + return 0; +}