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.
25 #include <gst/check/gstcheck.h>
28 #define WAIT_TIME (300 * GST_MSECOND)
30 /* an empty pipeline can go to PLAYING in one go */
31 GST_START_TEST (test_async_state_change_empty)
33 GstPipeline *pipeline;
35 pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
36 fail_unless (pipeline != NULL, "Could not create pipeline");
38 fail_unless_equals_int (gst_element_set_state (GST_ELEMENT (pipeline),
39 GST_STATE_PLAYING), GST_STATE_CHANGE_SUCCESS);
41 gst_object_unref (pipeline);
46 GST_START_TEST (test_async_state_change_fake_ready)
48 GstPipeline *pipeline;
49 GstElement *src, *sink;
51 pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
52 fail_unless (pipeline != NULL, "Could not create pipeline");
54 src = gst_element_factory_make ("fakesrc", NULL);
55 sink = gst_element_factory_make ("fakesink", NULL);
57 gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
58 gst_element_link (src, sink);
60 fail_unless_equals_int (gst_element_set_state (GST_ELEMENT (pipeline),
61 GST_STATE_READY), GST_STATE_CHANGE_SUCCESS);
63 gst_object_unref (pipeline);
68 GST_START_TEST (test_async_state_change_fake)
70 GstPipeline *pipeline;
71 GstElement *src, *sink;
73 gboolean done = FALSE;
75 pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
76 fail_unless (pipeline != NULL, "Could not create pipeline");
78 src = gst_element_factory_make ("fakesrc", NULL);
79 sink = gst_element_factory_make ("fakesink", NULL);
81 gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
82 gst_element_link (src, sink);
84 bus = gst_pipeline_get_bus (pipeline);
86 fail_unless_equals_int (gst_element_set_state (GST_ELEMENT (pipeline),
87 GST_STATE_PLAYING), GST_STATE_CHANGE_ASYNC);
91 GstState old, new, pending;
93 message = gst_bus_poll (bus, GST_MESSAGE_STATE_CHANGED, -1);
95 gst_message_parse_state_changed (message, &old, &new, &pending);
96 GST_DEBUG_OBJECT (message->src, "state change from %d to %d", old, new);
97 if (message->src == GST_OBJECT (pipeline) && new == GST_STATE_PLAYING)
99 gst_message_unref (message);
103 fail_unless_equals_int (gst_element_set_state (GST_ELEMENT (pipeline),
104 GST_STATE_NULL), GST_STATE_CHANGE_SUCCESS);
106 /* here we don't get the state change messages, because of auto-flush in
109 gst_object_unref (bus);
110 gst_object_unref (pipeline);
115 GST_START_TEST (test_get_bus)
117 GstPipeline *pipeline;
120 pipeline = GST_PIPELINE (gst_pipeline_new (NULL));
121 fail_unless (pipeline != NULL, "Could not create pipeline");
122 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
124 bus = gst_pipeline_get_bus (pipeline);
125 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline after get_bus", 1);
126 ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
128 gst_object_unref (pipeline);
130 ASSERT_OBJECT_REFCOUNT (bus, "bus after unref pipeline", 1);
131 gst_object_unref (bus);
136 static GMainLoop *loop = NULL;
139 message_received (GstBus * bus, GstMessage * message, gpointer data)
141 GstElement *pipeline = GST_ELEMENT (data);
142 GstMessageType type = message->type;
144 GST_DEBUG ("message received");
146 case GST_MESSAGE_STATE_CHANGED:
148 GstState old, new, pending;
150 GST_DEBUG ("state change message received");
151 gst_message_parse_state_changed (message, &old, &new, &pending);
152 GST_DEBUG ("new state %d", new);
153 if (message->src == GST_OBJECT (pipeline) && new == GST_STATE_PLAYING) {
154 GST_DEBUG ("quitting main loop");
155 g_main_loop_quit (loop);
159 case GST_MESSAGE_ERROR:
171 GST_START_TEST (test_bus)
173 GstElement *pipeline;
174 GstElement *src, *sink;
178 GstStateChangeReturn ret;
180 pipeline = gst_pipeline_new (NULL);
181 fail_unless (pipeline != NULL, "Could not create pipeline");
182 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline", 1);
184 src = gst_element_factory_make ("fakesrc", NULL);
185 fail_unless (src != NULL);
186 sink = gst_element_factory_make ("fakesink", NULL);
187 fail_unless (sink != NULL);
189 gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
190 fail_unless (gst_element_link (src, sink));
192 bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
193 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline after get_bus", 1);
194 ASSERT_OBJECT_REFCOUNT (bus, "bus", 2);
196 id = gst_bus_add_watch (bus, message_received, pipeline);
197 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline after add_watch", 1);
198 ASSERT_OBJECT_REFCOUNT (bus, "bus after add_watch", 3);
200 ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
201 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
203 loop = g_main_loop_new (NULL, FALSE);
204 GST_DEBUG ("going into main loop");
205 g_main_loop_run (loop);
206 GST_DEBUG ("left main loop");
210 ASSERT_OBJECT_REFCOUNT_BETWEEN (pipeline, "pipeline after gone to playing", 1,
214 GST_DEBUG ("cleanup");
216 ret = gst_element_set_state (pipeline, GST_STATE_NULL);
217 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
218 ret = gst_element_get_state (pipeline, ¤t, NULL, GST_CLOCK_TIME_NONE);
219 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
220 fail_unless (current == GST_STATE_NULL, "state is not NULL but %d", current);
222 ASSERT_OBJECT_REFCOUNT (pipeline, "pipeline at start of cleanup", 1);
223 ASSERT_OBJECT_REFCOUNT (bus, "bus at start of cleanup", 3);
225 fail_unless (g_source_remove (id));
226 ASSERT_OBJECT_REFCOUNT (bus, "bus after removing source", 2);
228 GST_DEBUG ("unreffing pipeline");
229 gst_object_unref (pipeline);
231 ASSERT_OBJECT_REFCOUNT (bus, "bus after unref pipeline", 1);
232 gst_object_unref (bus);
237 static GMutex *probe_lock;
238 static GCond *probe_cond;
241 sink_pad_probe (GstPad * pad, GstPadProbeType type, GstBuffer * buffer,
242 GstClockTime * first_timestamp)
244 fail_if (GST_BUFFER_TIMESTAMP (buffer) == GST_CLOCK_TIME_NONE,
245 "testing if buffer timestamps are right, but got CLOCK_TIME_NONE");
247 if (*first_timestamp == GST_CLOCK_TIME_NONE) {
248 *first_timestamp = GST_BUFFER_TIMESTAMP (buffer);
251 g_mutex_lock (probe_lock);
252 g_cond_signal (probe_cond);
253 g_mutex_unlock (probe_lock);
258 GST_START_TEST (test_base_time)
260 GstElement *pipeline, *fakesrc, *fakesink;
262 GstClockTime observed, lower, upper, base, stream;
265 pipeline = gst_element_factory_make ("pipeline", "pipeline");
266 fakesrc = gst_element_factory_make ("fakesrc", "fakesrc");
267 fakesink = gst_element_factory_make ("fakesink", "fakesink");
269 fail_unless (pipeline && fakesrc && fakesink, "couldn't make elements");
271 g_object_set (fakesrc, "is-live", (gboolean) TRUE, NULL);
273 gst_bin_add_many (GST_BIN (pipeline), fakesrc, fakesink, NULL);
274 gst_element_link (fakesrc, fakesink);
276 sink = gst_element_get_static_pad (fakesink, "sink");
277 gst_pad_add_probe (sink, GST_PAD_PROBE_TYPE_BUFFER,
278 (GstPadProbeCallback) sink_pad_probe, &observed, NULL);
280 fail_unless (gst_element_set_state (pipeline, GST_STATE_PAUSED)
281 == GST_STATE_CHANGE_NO_PREROLL, "expected no-preroll from live pipeline");
283 clock = gst_system_clock_obtain ();
284 fail_unless (clock && GST_IS_CLOCK (clock), "i want a clock dammit");
285 gst_pipeline_use_clock (GST_PIPELINE (pipeline), clock);
287 fail_unless (gst_element_get_start_time (pipeline) == 0,
288 "stream time doesn't start off at 0");
290 probe_lock = g_mutex_new ();
291 probe_cond = g_cond_new ();
293 /* test the first: that base time is being distributed correctly, timestamps
294 are correct relative to the running clock and base time */
296 lower = gst_clock_get_time (clock);
298 observed = GST_CLOCK_TIME_NONE;
300 gst_element_set_state (pipeline, GST_STATE_PLAYING);
301 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
303 == GST_STATE_CHANGE_SUCCESS, "failed state change");
305 g_mutex_lock (probe_lock);
306 while (observed == GST_CLOCK_TIME_NONE)
307 g_cond_wait (probe_cond, probe_lock);
308 g_mutex_unlock (probe_lock);
310 /* now something a little more than lower was distributed as the base time,
311 * and the buffer was timestamped between 0 and upper-base
314 base = gst_element_get_base_time (pipeline);
315 fail_if (base == GST_CLOCK_TIME_NONE);
317 /* set stream time */
318 gst_element_set_state (pipeline, GST_STATE_PAUSED);
320 /* pulling upper here makes sure that the pipeline's new stream time has
321 already been computed */
322 upper = gst_clock_get_time (clock);
324 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
326 == GST_STATE_CHANGE_NO_PREROLL, "failed state change");
328 fail_if (observed == GST_CLOCK_TIME_NONE, "no timestamp recorded");
330 fail_unless (base >= lower, "early base time: %" GST_TIME_FORMAT " < %"
331 GST_TIME_FORMAT, GST_TIME_ARGS (base), GST_TIME_ARGS (lower));
332 fail_unless (upper >= base, "bogus base time: %" GST_TIME_FORMAT " > %"
333 GST_TIME_FORMAT, GST_TIME_ARGS (base), GST_TIME_ARGS (upper));
335 stream = gst_element_get_start_time (pipeline);
337 fail_unless (stream > 0, "bogus new stream time: %" GST_TIME_FORMAT " > %"
338 GST_TIME_FORMAT, GST_TIME_ARGS (stream), GST_TIME_ARGS (0));
339 fail_unless (stream <= upper,
340 "bogus new stream time: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
341 GST_TIME_ARGS (stream), GST_TIME_ARGS (upper));
343 fail_unless (observed <= stream, "timestamps outrun stream time: %"
344 GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
345 GST_TIME_ARGS (observed), GST_TIME_ARGS (stream));
346 fail_unless (observed != GST_CLOCK_TIME_NONE, "early timestamp: %"
347 GST_TIME_FORMAT " < %" GST_TIME_FORMAT, GST_TIME_ARGS (observed),
348 GST_TIME_ARGS (lower - base));
349 fail_unless (observed <= upper - base,
350 "late timestamp: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
351 GST_TIME_ARGS (observed), GST_TIME_ARGS (upper - base));
354 /* test the second: that the base time is redistributed when we go to PLAYING
358 GstClockTime oldbase = base, oldstream = stream;
360 /* let some time pass */
361 clock_id = gst_clock_new_single_shot_id (clock, upper + WAIT_TIME);
362 fail_unless (gst_clock_id_wait (clock_id, NULL) == GST_CLOCK_OK,
363 "unexpected clock_id_wait return");
364 gst_clock_id_unref (clock_id);
366 lower = gst_clock_get_time (clock);
367 fail_if (lower == GST_CLOCK_TIME_NONE);
369 observed = GST_CLOCK_TIME_NONE;
371 fail_unless (lower >= upper + WAIT_TIME, "clock did not advance?");
373 gst_element_set_state (pipeline, GST_STATE_PLAYING);
374 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
376 == GST_STATE_CHANGE_SUCCESS, "failed state change");
378 g_mutex_lock (probe_lock);
379 while (observed == GST_CLOCK_TIME_NONE)
380 g_cond_wait (probe_cond, probe_lock);
381 g_mutex_unlock (probe_lock);
383 /* now the base time should have advanced by more than WAIT_TIME compared
384 * to what it was. The buffer will be timestamped between the last stream
385 * time and upper minus base.
388 base = gst_element_get_base_time (pipeline);
389 fail_if (base == GST_CLOCK_TIME_NONE);
391 /* set stream time */
392 gst_element_set_state (pipeline, GST_STATE_PAUSED);
394 /* new stream time already set */
395 upper = gst_clock_get_time (clock);
397 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
399 == GST_STATE_CHANGE_NO_PREROLL, "failed state change");
401 fail_if (observed == GST_CLOCK_TIME_NONE, "no timestamp recorded");
403 stream = gst_element_get_start_time (pipeline);
405 fail_unless (base >= oldbase + WAIT_TIME, "base time not reset");
406 fail_unless (upper >= base + stream, "bogus base time: %"
407 GST_TIME_FORMAT " > %" GST_TIME_FORMAT, GST_TIME_ARGS (base),
408 GST_TIME_ARGS (upper));
410 fail_unless (lower >= base);
411 fail_unless (observed >= lower - base, "early timestamp: %"
412 GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
413 GST_TIME_ARGS (observed), GST_TIME_ARGS (lower - base));
414 fail_unless (observed <= upper - base, "late timestamp: %"
415 GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
416 GST_TIME_ARGS (observed), GST_TIME_ARGS (upper - base));
417 fail_unless (stream - oldstream <= upper - lower,
418 "insufficient stream time: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
419 GST_TIME_ARGS (observed), GST_TIME_ARGS (upper));
422 /* test the third: that if I set CLOCK_TIME_NONE as the stream time, that the
423 base time is not changed */
426 GstClockTime oldbase = base, oldobserved = observed;
429 /* let some time pass */
430 clock_id = gst_clock_new_single_shot_id (clock, upper + WAIT_TIME);
431 ret = gst_clock_id_wait (clock_id, NULL);
432 fail_unless (ret == GST_CLOCK_OK,
433 "unexpected clock_id_wait return %d", ret);
434 gst_clock_id_unref (clock_id);
436 lower = gst_clock_get_time (clock);
438 observed = GST_CLOCK_TIME_NONE;
440 fail_unless (lower >= upper + WAIT_TIME, "clock did not advance?");
443 gst_element_set_start_time (pipeline, GST_CLOCK_TIME_NONE);
445 gst_element_set_state (pipeline, GST_STATE_PLAYING);
446 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
448 == GST_STATE_CHANGE_SUCCESS, "failed state change");
450 g_mutex_lock (probe_lock);
451 while (observed == GST_CLOCK_TIME_NONE)
452 g_cond_wait (probe_cond, probe_lock);
453 g_mutex_unlock (probe_lock);
455 /* now the base time should be the same as it was, and the timestamp should
456 * be more than WAIT_TIME past what it was.
459 base = gst_element_get_base_time (pipeline);
461 /* set stream time */
462 gst_element_set_state (pipeline, GST_STATE_PAUSED);
464 /* new stream time already set */
465 upper = gst_clock_get_time (clock);
467 fail_unless (gst_element_get_state (pipeline, NULL, NULL,
469 == GST_STATE_CHANGE_NO_PREROLL, "failed state change");
471 fail_if (observed == GST_CLOCK_TIME_NONE, "no timestamp recorded");
473 fail_unless (gst_element_get_start_time (pipeline)
474 == GST_CLOCK_TIME_NONE, "stream time was reset");
476 fail_unless (base == oldbase, "base time was reset");
478 fail_unless (observed >= lower - base, "early timestamp: %"
479 GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
480 GST_TIME_ARGS (observed), GST_TIME_ARGS (lower - base));
481 fail_unless (observed <= upper - base, "late timestamp: %"
482 GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
483 GST_TIME_ARGS (observed), GST_TIME_ARGS (upper - base));
484 fail_unless (observed - oldobserved >= WAIT_TIME,
485 "insufficient tstamp delta: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
486 GST_TIME_ARGS (observed), GST_TIME_ARGS (oldobserved));
489 gst_object_unref (sink);
490 gst_object_unref (clock);
491 gst_object_unref (pipeline);
497 pipeline_thread (gpointer data)
499 GstElement *pipeline, *src, *sink;
501 src = gst_element_factory_make ("fakesrc", NULL);
502 g_object_set (src, "num-buffers", 20, NULL);
503 sink = gst_element_factory_make ("fakesink", NULL);
504 g_object_set (sink, "sync", TRUE, NULL);
505 pipeline = gst_pipeline_new (NULL);
506 gst_bin_add (GST_BIN (pipeline), src);
507 gst_bin_add (GST_BIN (pipeline), sink);
508 gst_element_link (src, sink);
509 gst_element_set_state (pipeline, GST_STATE_PLAYING);
510 g_usleep (G_USEC_PER_SEC / 10);
511 gst_element_set_state (pipeline, GST_STATE_NULL);
512 gst_object_unref (pipeline);
516 GST_START_TEST (test_concurrent_create)
518 GThread *threads[30];
521 for (i = 0; i < G_N_ELEMENTS (threads); ++i) {
522 threads[i] = g_thread_create (pipeline_thread, NULL, TRUE, NULL);
524 for (i = 0; i < G_N_ELEMENTS (threads); ++i) {
526 g_thread_join (threads[i]);
532 GST_START_TEST (test_pipeline_in_pipeline)
534 GstElement *pipeline, *bin, *fakesrc, *fakesink;
537 pipeline = gst_element_factory_make ("pipeline", "pipeline");
538 bin = gst_element_factory_make ("pipeline", "pipeline-as-bin");
539 fakesrc = gst_element_factory_make ("fakesrc", "fakesrc");
540 fakesink = gst_element_factory_make ("fakesink", "fakesink");
542 fail_unless (pipeline && bin && fakesrc && fakesink);
544 g_object_set (fakesrc, "num-buffers", 100, NULL);
546 gst_bin_add (GST_BIN (pipeline), bin);
547 gst_bin_add_many (GST_BIN (bin), fakesrc, fakesink, NULL);
548 gst_element_link (fakesrc, fakesink);
550 fail_unless_equals_int (gst_element_set_state (pipeline, GST_STATE_PLAYING),
551 GST_STATE_CHANGE_ASYNC);
553 msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipeline), -1,
555 gst_message_unref (msg);
557 gst_element_set_state (pipeline, GST_STATE_NULL);
559 gst_object_unref (pipeline);
565 gst_pipeline_suite (void)
567 Suite *s = suite_create ("GstPipeline");
568 TCase *tc_chain = tcase_create ("pipeline tests");
570 tcase_set_timeout (tc_chain, 0);
572 suite_add_tcase (s, tc_chain);
573 tcase_add_test (tc_chain, test_async_state_change_empty);
574 tcase_add_test (tc_chain, test_async_state_change_fake_ready);
575 tcase_add_test (tc_chain, test_async_state_change_fake);
576 tcase_add_test (tc_chain, test_get_bus);
577 tcase_add_test (tc_chain, test_bus);
578 tcase_add_test (tc_chain, test_base_time);
579 tcase_add_test (tc_chain, test_concurrent_create);
580 tcase_add_test (tc_chain, test_pipeline_in_pipeline);
585 GST_CHECK_MAIN (gst_pipeline);