1 /* Test example for instant rate changes.
2 * The example takes an input URI and runs a set of actions,
3 * seeking and pausing etc.
5 * Copyright (C) 2015-2018 Centricular Ltd
6 * @author: Edward Hervey <edward@centricular.com>
7 * @author: Jan Schmidt <jan@centricular.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
30 #include <glib-object.h>
31 #include <glib/gprintf.h>
35 /* There are several supported scenarios
36 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
37 1) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> run for 10s, then pause -> wait 10s -> play
38 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
39 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
40 4) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> Apply 'instant-rate-change' to 0.25x (toggle every 500ms)
43 #define PLAY_PAUSE_DELAY 10
44 #define IDLE_CYCLE_DELAY 2
46 #define TARGET_RATE_1 0.25
47 #define TARGET_RATE_2 2.0
49 /* Set DISABLE_AUDIO to run with video only */
50 // #define DISABLE_AUDIO
52 /* Set to force the use of the system clock on the pipeline */
53 // #define FORCE_SYSTEM_CLOCK
55 typedef struct _MyDataStruct
72 static gboolean toggle_rate (MyDataStruct * data);
75 do_enable_disable_idle (MyDataStruct * data)
78 g_print ("Disabling idle handler\n");
79 g_source_remove (data->idle_id);
82 g_print ("Enabling idle handler\n");
83 data->idle_id = g_idle_add ((GSourceFunc) toggle_rate, data);
90 do_play_pause (MyDataStruct * data)
92 data->paused = !data->paused;
94 switch (data->scenario) {
96 g_print ("%s\n", data->paused ? "Pausing" : "Unpausing");
97 gst_element_set_state (data->pipeline,
98 data->paused ? GST_STATE_PAUSED : GST_STATE_PLAYING);
99 data->timeout_id = g_timeout_add_seconds (PLAY_PAUSE_DELAY,
100 (GSourceFunc) do_play_pause, data);
104 gint64 pos = GST_CLOCK_TIME_NONE;
105 gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &pos);
107 /* Change rate between 2x and 1x before unpausing */
108 data->rate = (data->rate == 2.0) ? 1.0 : 2.0;
109 g_print ("Switching rate to %f (position %" GST_TIME_FORMAT ")\n",
110 data->rate, GST_TIME_ARGS (pos));
111 gst_element_send_event (data->pipeline, gst_event_new_seek (data->rate,
112 GST_FORMAT_TIME, GST_SEEK_FLAG_INSTANT_RATE_CHANGE,
113 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE, GST_SEEK_TYPE_NONE,
114 GST_CLOCK_TIME_NONE));
117 g_print ("%s\n", data->paused ? "Pausing" : "Unpausing");
118 gst_element_set_state (data->pipeline,
119 data->paused ? GST_STATE_PAUSED : GST_STATE_PLAYING);
120 data->timeout_id = g_timeout_add_seconds (PLAY_PAUSE_DELAY,
121 (GSourceFunc) do_play_pause, data);
124 g_print ("%s\n", data->paused ? "Pausing" : "Unpausing");
125 gst_element_set_state (data->pipeline,
126 data->paused ? GST_STATE_PAUSED : GST_STATE_PLAYING);
128 /* On pause, seek to 30 seconds */
129 g_print ("Seeking to 30s\n");
130 gst_element_send_event (data->pipeline,
131 gst_event_new_seek (data->rate, GST_FORMAT_TIME,
132 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
133 GST_SEEK_TYPE_SET, 30 * GST_SECOND,
134 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE));
136 data->timeout_id = g_timeout_add_seconds (PLAY_PAUSE_DELAY,
137 (GSourceFunc) do_play_pause, data);
146 toggle_rate (MyDataStruct * data)
148 gint64 pos = GST_CLOCK_TIME_NONE;
149 gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &pos);
151 /* Toggle rate between the 2 target rates */
152 if (data->rate != TARGET_RATE_2)
153 data->rate = TARGET_RATE_2;
155 data->rate = TARGET_RATE_1;
156 g_print ("Switching rate to %f (position %" GST_TIME_FORMAT ")\n", data->rate,
157 GST_TIME_ARGS (pos));
158 gst_element_send_event (data->pipeline, gst_event_new_seek (data->rate,
159 GST_FORMAT_TIME, GST_SEEK_FLAG_INSTANT_RATE_CHANGE,
160 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE, GST_SEEK_TYPE_NONE,
161 GST_CLOCK_TIME_NONE));
166 on_preroll (MyDataStruct * data)
168 if (data->timeout_id != 0)
169 return; /* Already scheduled out scenario timer */
171 switch (data->scenario) {
173 data->idle_id = g_idle_add ((GSourceFunc) toggle_rate, data);
174 data->timeout_id = g_timeout_add_seconds (IDLE_CYCLE_DELAY,
175 (GSourceFunc) do_enable_disable_idle, data);
180 gint64 pos = GST_CLOCK_TIME_NONE;
181 gst_element_query_position (data->pipeline, GST_FORMAT_TIME, &pos);
183 /* Change rate to 2x and play for 10 sec, pause for 10 sec */
185 g_print ("Switching rate to %f (position %" GST_TIME_FORMAT ")\n",
186 data->rate, GST_TIME_ARGS (pos));
187 gst_element_send_event (data->pipeline, gst_event_new_seek (data->rate,
188 GST_FORMAT_TIME, GST_SEEK_FLAG_INSTANT_RATE_CHANGE,
189 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE, GST_SEEK_TYPE_NONE,
190 GST_CLOCK_TIME_NONE));
191 /* Instant rate change completed, schedule play/pause */
192 data->timeout_id = g_timeout_add_seconds (PLAY_PAUSE_DELAY,
193 (GSourceFunc) do_play_pause, data);
197 g_timeout_add (250, (GSourceFunc) toggle_rate, data);
205 _on_bus_message (GstBus * bus, GstMessage * message, gpointer userdata)
207 MyDataStruct *data = (MyDataStruct *) (userdata);
209 switch (GST_MESSAGE_TYPE (message)) {
210 case GST_MESSAGE_ERROR:{
212 gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
213 gst_message_parse_error (message, &err, NULL);
215 g_printerr ("ERROR: from element %s: %s\n", name, err->message);
219 g_printf ("Stopping\n");
220 g_main_loop_quit (data->mainloop);
223 case GST_MESSAGE_EOS:
224 g_printf ("EOS ! Stopping \n");
225 g_main_loop_quit (data->mainloop);
227 case GST_MESSAGE_ASYNC_DONE:
238 cmdline_to_uri (const gchar * arg)
240 if (gst_uri_is_valid (arg))
241 return g_strdup (arg);
243 return gst_filename_to_uri (arg, NULL);
247 print_usage (const char *arg0)
250 ("Usage: %s <0-4> URI\nSelect test scenario 0 to 4, and supply a URI to test\n",
252 g_print ("Scenarios:\n"
253 " 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"
254 " 1) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> run for 10s, then pause -> wait 10s -> play\n"
255 " 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"
256 " 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"
257 " 4) Play rate to 1x -> Apply 'instant-rate-change' to 2x -> Apply 'instant-rate-change' to 0.25x (toggle every 500ms)\n");
261 main (int argc, gchar ** argv)
266 #ifdef FORCE_SYSTEM_CLOCK
270 gst_init (&argc, &argv);
272 data = g_new0 (MyDataStruct, 1);
275 print_usage (argv[0]);
279 data->scenario = atoi (argv[1]);
280 uri = cmdline_to_uri (argv[2]);
281 if (data->scenario > 4 || uri == NULL) {
282 print_usage (argv[0]);
286 data->pipeline = gst_element_factory_make ("playbin", NULL);
287 if (data->pipeline == NULL) {
288 g_printerr ("Failed to create playbin element. Aborting");
291 #ifdef FORCE_SYSTEM_CLOCK
292 clock = gst_system_clock_obtain ();
293 gst_pipeline_use_clock (GST_PIPELINE (data->pipeline), clock);
297 g_object_set (data->pipeline, "flags", 0x00000615, NULL);
299 g_object_set (data->pipeline, "uri", uri, NULL);
302 /* Put a bus handler */
303 bus = gst_pipeline_get_bus (GST_PIPELINE (data->pipeline));
304 gst_bus_add_watch (bus, _on_bus_message, data);
307 data->mainloop = g_main_loop_new (NULL, TRUE);
308 gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
309 g_main_loop_run (data->mainloop);
311 gst_element_set_state (data->pipeline, GST_STATE_NULL);
313 gst_object_unref (data->pipeline);
314 gst_object_unref (bus);