From: Jan Schmidt Date: Fri, 17 Aug 2018 17:37:09 +0000 (+1000) Subject: tests/examples/seek/instant-rate-change: Add example app X-Git-Tag: 1.19.3~511^2~689 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9f55f8c28efbbb55342a6960b7f3c458c4340d3f;p=platform%2Fupstream%2Fgstreamer.git tests/examples/seek/instant-rate-change: Add example app Add an example app to exercise instant rate changes in a few scenarios. Currently it deadlocks a lot sending rate changes to paused pipelines. --- diff --git a/tests/examples/seek/instant-rate-change.c b/tests/examples/seek/instant-rate-change.c new file mode 100644 index 0000000..6e4dec7 --- /dev/null +++ b/tests/examples/seek/instant-rate-change.c @@ -0,0 +1,316 @@ +/* Test example for instant rate changes. + * The example takes an input URI and runs a set of actions, + * seeking and pausing etc. + * + * Copyright (C) 2015-2018 Centricular Ltd + * @author: Edward Hervey + * @author: Jan Schmidt + * + * 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., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +/* There are several supported scenarios +0) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> Apply 'instant-rate-change' to 0.25x (repeat as fast as possible for 2 sec) -> let play for 2s +1) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> run for 10s, then pause -> wait 10s -> play +2) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> run for 10s, then pause -> wait 10s -> Apply 'instant-rate-change' to 1x -> play +3) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> run for 10s, then pause -> seeking (flush+key-unit) to 30s -> wait 10s -> play +4) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> Apply 'instant-rate-change' to 0.25x (toggle every 500ms) +*/ + +#define PLAY_PAUSE_DELAY 10 +#define IDLE_CYCLE_DELAY 2 + +#define TARGET_RATE_1 0.25 +#define TARGET_RATE_2 2.0 + +/* Set DISABLE_AUDIO to run with video only */ +// #define DISABLE_AUDIO + +/* Set to force the use of the system clock on the pipeline */ +// #define FORCE_SYSTEM_CLOCK + +typedef struct _MyDataStruct +{ + GMainLoop *mainloop; + GstElement *pipeline; + GstBus *bus; + + gdouble rate; + gboolean paused; + + guint scenario; + GstClockTime start; + GstClock *clock; + + guint timeout_id; + guint idle_id; +} MyDataStruct; + +static gboolean toggle_rate (MyDataStruct * data); + +static gboolean +do_enable_disable_idle (MyDataStruct * data) +{ + if (data->idle_id) { + g_print ("Disabling idle handler\n"); + g_source_remove (data->idle_id); + data->idle_id = 0; + } else { + g_print ("Enabling idle handler\n"); + data->idle_id = g_idle_add ((GSourceFunc) toggle_rate, data); + } + + return TRUE; +} + +static gboolean +do_play_pause (MyDataStruct * data) +{ + data->paused = !data->paused; + + switch (data->scenario) { + case 1: + g_print ("%s\n", data->paused ? "Pausing" : "Unpausing"); + gst_element_set_state (data->pipeline, + data->paused ? GST_STATE_PAUSED : GST_STATE_PLAYING); + data->timeout_id = g_timeout_add_seconds (PLAY_PAUSE_DELAY, + (GSourceFunc) do_play_pause, data); + break; + case 2: + if (!data->paused) { + gint64 pos = GST_CLOCK_TIME_NONE; + gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &pos); + + /* Change rate between 2x and 1x before unpausing */ + data->rate = (data->rate == 2.0) ? 1.0 : 2.0; + g_print ("Switching rate to %f (position %" GST_TIME_FORMAT ")\n", + data->rate, GST_TIME_ARGS (pos)); + gst_element_send_event (data->pipeline, gst_event_new_seek (data->rate, + GST_FORMAT_TIME, GST_SEEK_FLAG_INSTANT_RATE_CHANGE, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE, GST_SEEK_TYPE_NONE, + GST_CLOCK_TIME_NONE)); + } + + g_print ("%s\n", data->paused ? "Pausing" : "Unpausing"); + gst_element_set_state (data->pipeline, + data->paused ? GST_STATE_PAUSED : GST_STATE_PLAYING); + data->timeout_id = g_timeout_add_seconds (PLAY_PAUSE_DELAY, + (GSourceFunc) do_play_pause, data); + break; + case 3: + g_print ("%s\n", data->paused ? "Pausing" : "Unpausing"); + gst_element_set_state (data->pipeline, + data->paused ? GST_STATE_PAUSED : GST_STATE_PLAYING); + if (data->paused) { + /* On pause, seek to 30 seconds */ + g_print ("Seeking to 30s\n"); + gst_element_send_event (data->pipeline, + gst_event_new_seek (data->rate, GST_FORMAT_TIME, + GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, + GST_SEEK_TYPE_SET, 30 * GST_SECOND, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)); + } + data->timeout_id = g_timeout_add_seconds (PLAY_PAUSE_DELAY, + (GSourceFunc) do_play_pause, data); + break; + default: + break; + } + return FALSE; +} + +static gboolean +toggle_rate (MyDataStruct * data) +{ + gint64 pos = GST_CLOCK_TIME_NONE; + gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &pos); + + /* Toggle rate between the 2 target rates */ + if (data->rate != TARGET_RATE_2) + data->rate = TARGET_RATE_2; + else + data->rate = TARGET_RATE_1; + g_print ("Switching rate to %f (position %" GST_TIME_FORMAT ")\n", data->rate, + GST_TIME_ARGS (pos)); + gst_element_send_event (data->pipeline, gst_event_new_seek (data->rate, + GST_FORMAT_TIME, GST_SEEK_FLAG_INSTANT_RATE_CHANGE, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE, GST_SEEK_TYPE_NONE, + GST_CLOCK_TIME_NONE)); + return TRUE; +} + +static void +on_preroll (MyDataStruct * data) +{ + if (data->timeout_id != 0) + return; /* Already scheduled out scenario timer */ + + switch (data->scenario) { + case 0: + data->idle_id = g_idle_add ((GSourceFunc) toggle_rate, data); + data->timeout_id = g_timeout_add_seconds (IDLE_CYCLE_DELAY, + (GSourceFunc) do_enable_disable_idle, data); + break; + case 1: + case 2: + case 3:{ + gint64 pos = GST_CLOCK_TIME_NONE; + gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &pos); + + /* Change rate to 2x and play for 10 sec, pause for 10 sec */ + data->rate = 2.0; + g_print ("Switching rate to %f (position %" GST_TIME_FORMAT ")\n", + data->rate, GST_TIME_ARGS (pos)); + gst_element_send_event (data->pipeline, gst_event_new_seek (data->rate, + GST_FORMAT_TIME, GST_SEEK_FLAG_INSTANT_RATE_CHANGE, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE, GST_SEEK_TYPE_NONE, + GST_CLOCK_TIME_NONE)); + /* Instant rate change completed, schedule play/pause */ + data->timeout_id = g_timeout_add_seconds (PLAY_PAUSE_DELAY, + (GSourceFunc) do_play_pause, data); + break; + } + case 4: + g_timeout_add (250, (GSourceFunc) toggle_rate, data); + break; + default: + break; + } +} + +static gboolean +_on_bus_message (GstBus * bus, GstMessage * message, gpointer userdata) +{ + MyDataStruct *data = (MyDataStruct *) (userdata); + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR:{ + GError *err = NULL; + gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message)); + gst_message_parse_error (message, &err, NULL); + + g_printerr ("ERROR: from element %s: %s\n", name, err->message); + g_error_free (err); + g_free (name); + + g_printf ("Stopping\n"); + g_main_loop_quit (data->mainloop); + break; + } + case GST_MESSAGE_EOS: + g_printf ("EOS ! Stopping \n"); + g_main_loop_quit (data->mainloop); + break; + case GST_MESSAGE_ASYNC_DONE: + on_preroll (data); + break; + default: + break; + } + + return TRUE; +} + +static gchar * +cmdline_to_uri (const gchar * arg) +{ + if (gst_uri_is_valid (arg)) + return g_strdup (arg); + + return gst_filename_to_uri (arg, NULL); +} + +static void +print_usage (const char *arg0) +{ + g_print + ("Usage: %s <0-4> URI\nSelect test scenario 0 to 4, and supply a URI to test\n", + arg0); + g_print ("Scenarios:\n" + " 0) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> Apply 'instant-rate-change' to 0.25x (repeat as fast as possible for 2 sec) -> let play for 2s\n" + " 1) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> run for 10s, then pause -> wait 10s -> play\n" + " 2) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> run for 10s, then pause -> wait 10s -> Apply 'instant-rate-change' to 1x -> play\n" + " 3) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> run for 10s, then pause -> seeking (flush+key-unit) to 30s -> wait 10s -> play\n" + " 4) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> Apply 'instant-rate-change' to 0.25x (toggle every 500ms)\n"); +} + +int +main (int argc, gchar ** argv) +{ + GstBus *bus; + MyDataStruct *data; + gchar *uri; +#ifdef FORCE_SYSTEM_CLOCK + GstClock *clock; +#endif + + gst_init (&argc, &argv); + + data = g_new0 (MyDataStruct, 1); + + if (argc < 3) { + print_usage (argv[0]); + return 1; + } + + data->scenario = atoi (argv[1]); + uri = cmdline_to_uri (argv[2]); + if (data->scenario > 4 || uri == NULL) { + print_usage (argv[0]); + return 1; + } + + data->pipeline = gst_element_factory_make ("playbin", NULL); + if (data->pipeline == NULL) { + g_printerr ("Failed to create playbin element. Aborting"); + return 1; + } +#ifdef FORCE_SYSTEM_CLOCK + clock = gst_system_clock_obtain (); + gst_pipeline_use_clock (GST_PIPELINE (data->pipeline), clock); +#endif + +#ifdef DISABLE_AUDIO + g_object_set (data->pipeline, "flags", 0x00000615, NULL); +#endif + g_object_set (data->pipeline, "uri", uri, NULL); + g_free (uri); + + /* Put a bus handler */ + bus = gst_pipeline_get_bus (GST_PIPELINE (data->pipeline)); + gst_bus_add_watch (bus, _on_bus_message, data); + + /* Start pipeline */ + data->mainloop = g_main_loop_new (NULL, TRUE); + gst_element_set_state (data->pipeline, GST_STATE_PLAYING); + g_main_loop_run (data->mainloop); + + gst_element_set_state (data->pipeline, GST_STATE_NULL); + + gst_object_unref (data->pipeline); + gst_object_unref (bus); + + return 0; +} diff --git a/tests/examples/seek/meson.build b/tests/examples/seek/meson.build index fc6ce23..eb721b0 100644 --- a/tests/examples/seek/meson.build +++ b/tests/examples/seek/meson.build @@ -30,3 +30,10 @@ executable('stepping2', 'stepping2.c', include_directories: [configinc, libsinc], dependencies : [libm, glib_deps, gst_dep, video_dep], install: false) + +executable('instant-rate-change', 'instant-rate-change.c', + c_args : gst_plugins_base_args, + include_directories: [configinc, libsinc], + dependencies : [libm, glib_deps, gst_dep, video_dep], + install: false) +