2 * Copyright (C) 2005 Thomas Vander Stichele <thomas at apestaart dot org>
4 * gstpipeline.c: Unit test for GstPipeline
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 #include <gst/check/gstcheck.h>
24 #define WAIT_TIME (300 * GST_MSECOND)
26 /* an empty pipeline can go to PLAYING in one go */
27 GST_START_TEST (test_async_state_change_empty)
29 GstPipeline *pipeline;
31 pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
32 fail_unless (pipeline != NULL, "Could not create pipeline");
34 fail_unless_equals_int (gst_element_set_state (GST_ELEMENT (pipeline),
35 GST_STATE_PLAYING), GST_STATE_CHANGE_SUCCESS);
37 gst_object_unref (pipeline);
42 GST_START_TEST (test_async_state_change_fake_ready)
44 GstPipeline *pipeline;
45 GstElement *src, *sink;
47 pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
48 fail_unless (pipeline != NULL, "Could not create pipeline");
50 src = gst_element_factory_make ("fakesrc", NULL);
51 sink = gst_element_factory_make ("fakesink", NULL);
53 gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
54 gst_element_link (src, sink);
56 fail_unless_equals_int (gst_element_set_state (GST_ELEMENT (pipeline),
57 GST_STATE_READY), GST_STATE_CHANGE_SUCCESS);
59 gst_object_unref (pipeline);
65 GST_START_TEST (test_async_state_change_fake)
67 GstPipeline *pipeline;
68 GstElement *src, *sink;
70 gboolean done = FALSE;
72 pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
73 fail_unless (pipeline != NULL, "Could not create pipeline");
75 src = gst_element_factory_make ("fakesrc", NULL);
76 sink = gst_element_factory_make ("fakesink", NULL);
78 gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
79 gst_element_link (src, sink);
81 bus = gst_pipeline_get_bus (pipeline);
83 fail_unless_equals_int (gst_element_set_state (GST_ELEMENT (pipeline),
84 GST_STATE_PLAYING), GST_STATE_CHANGE_ASYNC);
88 GstState old, new, pending;
90 message = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, -1);
92 gst_message_parse_state_changed (message, &old, &new, &pending);
93 GST_DEBUG_OBJECT (message->src, "state change from %d to %d", old, new);
94 if (message->src == GST_OBJECT (pipeline) && new == GST_STATE_PLAYING)
96 gst_message_unref (message);
100 fail_unless_equals_int (gst_element_set_state (GST_ELEMENT (pipeline),
101 GST_STATE_NULL), GST_STATE_CHANGE_SUCCESS);
103 gst_object_unref (bus);
104 gst_object_unref (pipeline);
109 GST_START_TEST (test_get_bus)
111 GstPipeline *pipeline;
114 pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
115 fail_unless (pipeline != NULL, "Could not create pipeline");
116 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
118 bus = gst_pipeline_get_bus (pipeline);
119 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline after get_bus", 1);
120 ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
122 gst_object_unref (pipeline);
124 ASSERT_OBJECT_REFCOUNT (bus, "bus after unref pipeline", 1);
125 gst_object_unref (bus);
130 GMainLoop *loop = NULL;
133 message_received (GstBus * bus, GstMessage * message, gpointer data)
135 GstElement *pipeline = GST_ELEMENT (data);
136 GstMessageType type = message->type;
138 GST_DEBUG ("message received");
140 case GST_MESSAGE_STATE_CHANGED:
142 GstState old, new, pending;
144 GST_DEBUG ("state change message received");
145 gst_message_parse_state_changed (message, &old, &new, &pending);
146 GST_DEBUG ("new state %d", new);
147 if (message->src == GST_OBJECT (pipeline) && new == GST_STATE_PLAYING) {
148 GST_DEBUG ("quitting main loop");
149 g_main_loop_quit (loop);
153 case GST_MESSAGE_ERROR:
165 GST_START_TEST (test_bus)
167 GstElement *pipeline;
168 GstElement *src, *sink;
172 GstStateChangeReturn ret;
174 pipeline = gst_pipeline_new (NULL);
175 fail_unless (pipeline != NULL, "Could not create pipeline");
176 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
178 src = gst_element_factory_make ("fakesrc", NULL);
179 fail_unless (src != NULL);
180 sink = gst_element_factory_make ("fakesink", NULL);
181 fail_unless (sink != NULL);
183 gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
184 fail_unless (gst_element_link (src, sink));
186 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
187 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline after get_bus", 1);
188 ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
190 id = gst_bus_add_watch (bus, message_received, pipeline);
191 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline after add_watch", 1);
192 ASSERT_OBJECT_REFCOUNT (bus, "bus after add_watch", 3);
194 ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
195 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
197 loop = g_main_loop_new (NULL, FALSE);
198 GST_DEBUG ("going into main loop");
199 g_main_loop_run (loop);
200 GST_DEBUG ("left main loop");
204 ASSERT_OBJECT_REFCOUNT_BETWEEN (pipeline, "pipeline after gone to playing", 1,
208 GST_DEBUG ("cleanup");
210 ret = gst_element_set_state (pipeline, GST_STATE_NULL);
211 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
212 ret = gst_element_get_state (pipeline, ¤t, NULL, GST_CLOCK_TIME_NONE);
213 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
214 fail_unless (current == GST_STATE_NULL, "state is not NULL but %d", current);
216 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline at start of cleanup", 1);
217 ASSERT_OBJECT_REFCOUNT (bus, "bus at start of cleanup", 3);
219 fail_unless (g_source_remove (id));
220 ASSERT_OBJECT_REFCOUNT (bus, "bus after removing source", 2);
222 GST_DEBUG ("unreffing pipeline");
223 gst_object_unref (pipeline);
225 ASSERT_OBJECT_REFCOUNT (bus, "bus after unref pipeline", 1);
226 gst_object_unref (bus);
231 static GMutex *probe_lock;
232 static GCond *probe_cond;
235 sink_pad_probe (GstPad * pad, GstBuffer * buffer,
236 GstClockTime * first_timestamp)
238 fail_if (GST_BUFFER_TIMESTAMP (buffer) == GST_CLOCK_TIME_NONE,
239 "testing if buffer timestamps are right, but got CLOCK_TIME_NONE");
241 if (*first_timestamp == GST_CLOCK_TIME_NONE) {
242 *first_timestamp = GST_BUFFER_TIMESTAMP (buffer);
245 g_mutex_lock (probe_lock);
246 g_cond_signal (probe_cond);
247 g_mutex_unlock (probe_lock);
252 GST_START_TEST (test_base_time)
254 GstElement *pipeline, *fakesrc, *fakesink;
256 GstClockTime observed, lower, upper, base, stream;
259 pipeline = gst_element_factory_make ("pipeline", "pipeline");
260 fakesrc = gst_element_factory_make ("fakesrc", "fakesrc");
261 fakesink = gst_element_factory_make ("fakesink", "fakesink");
263 fail_unless (pipeline && fakesrc && fakesink, "couldn't make elements");
265 g_object_set (fakesrc, "is-live", (gboolean) TRUE, NULL);
267 gst_bin_add_many (GST_BIN (pipeline), fakesrc, fakesink, NULL);
268 gst_element_link (fakesrc, fakesink);
270 sink = gst_element_get_pad (fakesink, "sink");
271 gst_pad_add_buffer_probe (sink, G_CALLBACK (sink_pad_probe), &observed);
273 fail_unless (gst_element_set_state (pipeline, GST_STATE_PAUSED)
274 == GST_STATE_CHANGE_NO_PREROLL, "expected no-preroll from live pipeline");
276 clock = gst_system_clock_obtain ();
277 fail_unless (clock && GST_IS_CLOCK (clock), "i want a clock dammit");
278 gst_pipeline_use_clock (GST_PIPELINE (pipeline), clock);
280 fail_unless (gst_pipeline_get_last_stream_time (GST_PIPELINE (pipeline)) == 0,
281 "stream time doesn't start off at 0");
283 probe_lock = g_mutex_new ();
284 probe_cond = g_cond_new ();
286 /* test the first: that base time is being distributed correctly, timestamps
287 are correct relative to the running clock and base time */
289 lower = gst_clock_get_time (clock);
291 observed = GST_CLOCK_TIME_NONE;
293 gst_element_set_state (pipeline, GST_STATE_PLAYING);
294 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
296 == GST_STATE_CHANGE_SUCCESS, "failed state change");
298 g_mutex_lock (probe_lock);
299 while (observed == GST_CLOCK_TIME_NONE)
300 g_cond_wait (probe_cond, probe_lock);
301 g_mutex_unlock (probe_lock);
303 /* now something a little more than lower was distributed as the base time,
304 * and the buffer was timestamped between 0 and upper-base
307 base = gst_element_get_base_time (pipeline);
308 fail_if (base == GST_CLOCK_TIME_NONE);
310 /* set stream time */
311 gst_element_set_state (pipeline, GST_STATE_PAUSED);
313 /* pulling upper here makes sure that the pipeline's new stream time has
314 already been computed */
315 upper = gst_clock_get_time (clock);
317 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
319 == GST_STATE_CHANGE_NO_PREROLL, "failed state change");
321 fail_if (observed == GST_CLOCK_TIME_NONE, "no timestamp recorded");
323 fail_unless (base >= lower, "early base time: %" GST_TIME_FORMAT " < %"
324 GST_TIME_FORMAT, GST_TIME_ARGS (base), GST_TIME_ARGS (lower));
325 fail_unless (upper >= base, "bogus base time: %" GST_TIME_FORMAT " > %"
326 GST_TIME_FORMAT, GST_TIME_ARGS (base), GST_TIME_ARGS (upper));
328 stream = gst_pipeline_get_last_stream_time (GST_PIPELINE (pipeline));
330 fail_unless (stream > 0, "bogus new stream time: %" GST_TIME_FORMAT " > %"
331 GST_TIME_FORMAT, GST_TIME_ARGS (stream), GST_TIME_ARGS (0));
332 fail_unless (stream <= upper,
333 "bogus new stream time: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
334 GST_TIME_ARGS (stream), GST_TIME_ARGS (upper));
336 fail_unless (observed <= stream, "timestamps outrun stream time: %"
337 GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
338 GST_TIME_ARGS (observed), GST_TIME_ARGS (stream));
339 fail_unless (observed >= 0, "early timestamp: %" GST_TIME_FORMAT " < %"
340 GST_TIME_FORMAT, GST_TIME_ARGS (observed),
341 GST_TIME_ARGS (lower - base));
342 fail_unless (observed <= upper - base,
343 "late timestamp: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
344 GST_TIME_ARGS (observed), GST_TIME_ARGS (upper - base));
347 /* test the second: that the base time is redistributed when we go to PLAYING
351 GstClockTime oldbase = base, oldstream = stream;
353 /* let some time pass */
354 clock_id = gst_clock_new_single_shot_id (clock, upper + WAIT_TIME);
355 fail_unless (gst_clock_id_wait (clock_id, NULL) == GST_CLOCK_OK,
356 "unexpected clock_id_wait return");
357 gst_clock_id_unref (clock_id);
359 lower = gst_clock_get_time (clock);
360 fail_if (lower == GST_CLOCK_TIME_NONE);
362 observed = GST_CLOCK_TIME_NONE;
364 fail_unless (lower >= upper + WAIT_TIME, "clock did not advance?");
366 gst_element_set_state (pipeline, GST_STATE_PLAYING);
367 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
369 == GST_STATE_CHANGE_SUCCESS, "failed state change");
371 g_mutex_lock (probe_lock);
372 while (observed == GST_CLOCK_TIME_NONE)
373 g_cond_wait (probe_cond, probe_lock);
374 g_mutex_unlock (probe_lock);
376 /* now the base time should have advanced by more than WAIT_TIME compared
377 * to what it was. The buffer will be timestamped between the last stream
378 * time and upper minus base.
381 base = gst_element_get_base_time (pipeline);
382 fail_if (base == GST_CLOCK_TIME_NONE);
384 /* set stream time */
385 gst_element_set_state (pipeline, GST_STATE_PAUSED);
387 /* new stream time already set */
388 upper = gst_clock_get_time (clock);
390 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
392 == GST_STATE_CHANGE_NO_PREROLL, "failed state change");
394 fail_if (observed == GST_CLOCK_TIME_NONE, "no timestamp recorded");
396 stream = gst_pipeline_get_last_stream_time (GST_PIPELINE (pipeline));
398 fail_unless (base >= oldbase + WAIT_TIME, "base time not reset");
399 fail_unless (upper >= base + stream, "bogus base time: %"
400 GST_TIME_FORMAT " > %" GST_TIME_FORMAT, GST_TIME_ARGS (base),
401 GST_TIME_ARGS (upper));
403 fail_unless (lower >= base);
404 fail_unless (observed >= lower - base, "early timestamp: %"
405 GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
406 GST_TIME_ARGS (observed), GST_TIME_ARGS (lower - base));
407 fail_unless (observed <= upper - base, "late timestamp: %"
408 GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
409 GST_TIME_ARGS (observed), GST_TIME_ARGS (upper - base));
410 fail_unless (stream - oldstream <= upper - lower,
411 "insufficient stream time: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
412 GST_TIME_ARGS (observed), GST_TIME_ARGS (upper));
415 /* test the third: that if I set CLOCK_TIME_NONE as the stream time, that the
416 base time is not changed */
419 GstClockTime oldbase = base, oldobserved = observed;
422 /* let some time pass */
423 clock_id = gst_clock_new_single_shot_id (clock, upper + WAIT_TIME);
424 ret = gst_clock_id_wait (clock_id, NULL);
425 fail_unless (ret == GST_CLOCK_OK,
426 "unexpected clock_id_wait return %d", ret);
427 gst_clock_id_unref (clock_id);
429 lower = gst_clock_get_time (clock);
431 observed = GST_CLOCK_TIME_NONE;
433 fail_unless (lower >= upper + WAIT_TIME, "clock did not advance?");
436 gst_pipeline_set_new_stream_time (GST_PIPELINE (pipeline),
437 GST_CLOCK_TIME_NONE);
439 gst_element_set_state (pipeline, GST_STATE_PLAYING);
440 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
442 == GST_STATE_CHANGE_SUCCESS, "failed state change");
444 g_mutex_lock (probe_lock);
445 while (observed == GST_CLOCK_TIME_NONE)
446 g_cond_wait (probe_cond, probe_lock);
447 g_mutex_unlock (probe_lock);
449 /* now the base time should be the same as it was, and the timestamp should
450 * be more than WAIT_TIME past what it was.
453 base = gst_element_get_base_time (pipeline);
455 /* set stream time */
456 gst_element_set_state (pipeline, GST_STATE_PAUSED);
458 /* new stream time already set */
459 upper = gst_clock_get_time (clock);
461 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
463 == GST_STATE_CHANGE_NO_PREROLL, "failed state change");
465 fail_if (observed == GST_CLOCK_TIME_NONE, "no timestamp recorded");
467 fail_unless (gst_pipeline_get_last_stream_time (GST_PIPELINE (pipeline))
468 == GST_CLOCK_TIME_NONE, "stream time was reset");
470 fail_unless (base == oldbase, "base time was reset");
472 fail_unless (observed >= lower - base, "early timestamp: %"
473 GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
474 GST_TIME_ARGS (observed), GST_TIME_ARGS (lower - base));
475 fail_unless (observed <= upper - base, "late timestamp: %"
476 GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
477 GST_TIME_ARGS (observed), GST_TIME_ARGS (upper - base));
478 fail_unless (observed - oldobserved >= WAIT_TIME,
479 "insufficient tstamp delta: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
480 GST_TIME_ARGS (observed), GST_TIME_ARGS (oldobserved));
483 gst_object_unref (sink);
484 gst_object_unref (clock);
485 gst_object_unref (pipeline);
491 gst_pipeline_suite (void)
493 Suite *s = suite_create ("GstPipeline");
494 TCase *tc_chain = tcase_create ("pipeline tests");
496 tcase_set_timeout (tc_chain, 0);
498 suite_add_tcase (s, tc_chain);
499 tcase_add_test (tc_chain, test_async_state_change_empty);
500 tcase_add_test (tc_chain, test_async_state_change_fake_ready);
501 tcase_add_test (tc_chain, test_async_state_change_fake);
502 tcase_add_test (tc_chain, test_get_bus);
503 tcase_add_test (tc_chain, test_bus);
504 tcase_add_test (tc_chain, test_base_time);
509 GST_CHECK_MAIN (gst_pipeline);