1 /* GStreamer
2 *
3 * unit test for fakesink
4 *
5 * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
6 * <2007> Wim Taymans <wim@fluendo.com>
7 * <2009> Tim-Philipp Müller <tim centricular net>
8 *
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.
13 *
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.
18 *
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.
23 */
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <gst/base/gstpushsrc.h>
29 #include <gst/check/gstcheck.h>
30
31 typedef struct
32 {
33 GstPad *pad;
34 GstBuffer *buffer;
35 GThread *thread;
36 GstFlowReturn ret;
37 } ChainData;
38
39 static gpointer
chain_async_buffer(gpointer data)40 chain_async_buffer (gpointer data)
41 {
42 ChainData *chain_data = (ChainData *) data;
43
44 chain_data->ret = gst_pad_chain (chain_data->pad, chain_data->buffer);
45
46 return chain_data;
47 }
48
49 static ChainData *
chain_async(GstPad * pad,GstBuffer * buffer)50 chain_async (GstPad * pad, GstBuffer * buffer)
51 {
52 GThread *thread;
53 ChainData *chain_data;
54 GError *error = NULL;
55
56 chain_data = g_new (ChainData, 1);
57 chain_data->pad = pad;
58 chain_data->buffer = buffer;
59 chain_data->ret = GST_FLOW_ERROR;
60
61 thread =
62 g_thread_try_new ("gst-check", chain_async_buffer, chain_data, &error);
63 if (error != NULL) {
64 g_warning ("could not create thread reason: %s", error->message);
65 g_free (chain_data);
66 return NULL;
67 }
68 chain_data->thread = thread;
69
70 return chain_data;
71 }
72
73 static GstFlowReturn
chain_async_return(ChainData * data)74 chain_async_return (ChainData * data)
75 {
76 GstFlowReturn ret;
77
78 g_thread_join (data->thread);
79 ret = data->ret;
80 g_free (data);
81
82 return ret;
83 }
84
GST_START_TEST(test_clipping)85 GST_START_TEST (test_clipping)
86 {
87 GstElement *sink;
88 GstPad *sinkpad;
89 GstStateChangeReturn ret;
90
91 /* create sink */
92 sink = gst_element_factory_make ("fakesink", "sink");
93 fail_if (sink == NULL);
94
95 sinkpad = gst_element_get_static_pad (sink, "sink");
96 fail_if (sinkpad == NULL);
97
98 /* make element ready to accept data */
99 ret = gst_element_set_state (sink, GST_STATE_PAUSED);
100 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
101
102 gst_pad_send_event (sinkpad, gst_event_new_stream_start ("test"));
103
104 /* send segment */
105 {
106 GstEvent *event;
107 GstSegment segment;
108 gboolean eret;
109
110 GST_DEBUG ("sending segment");
111 gst_segment_init (&segment, GST_FORMAT_TIME);
112 segment.start = 1 * GST_SECOND;
113 segment.stop = 5 * GST_SECOND;
114 segment.time = 1 * GST_SECOND;
115
116 event = gst_event_new_segment (&segment);
117
118 eret = gst_pad_send_event (sinkpad, event);
119 fail_if (eret == FALSE);
120 }
121
122 /* new segment should not have finished preroll */
123 ret = gst_element_get_state (sink, NULL, NULL, 0);
124 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
125
126 /* send buffer that should be dropped */
127 {
128 GstBuffer *buffer;
129 GstFlowReturn fret;
130
131 buffer = gst_buffer_new ();
132 GST_BUFFER_TIMESTAMP (buffer) = 0;
133 GST_BUFFER_DURATION (buffer) = 1 * GST_MSECOND;
134
135 GST_DEBUG ("sending buffer to be dropped");
136 fret = gst_pad_chain (sinkpad, buffer);
137 fail_if (fret != GST_FLOW_OK);
138 }
139 /* dropped buffer should not have finished preroll */
140 ret = gst_element_get_state (sink, NULL, NULL, 0);
141 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
142
143 /* send buffer that should be dropped */
144 {
145 GstBuffer *buffer;
146 GstFlowReturn fret;
147
148 buffer = gst_buffer_new ();
149 GST_BUFFER_TIMESTAMP (buffer) = 5 * GST_SECOND;
150 GST_BUFFER_DURATION (buffer) = 1 * GST_MSECOND;
151
152 GST_DEBUG ("sending buffer to be dropped");
153 fret = gst_pad_chain (sinkpad, buffer);
154 fail_if (fret != GST_FLOW_OK);
155 }
156 /* dropped buffer should not have finished preroll */
157 ret = gst_element_get_state (sink, NULL, NULL, 0);
158 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
159
160 /* send buffer that should block and finish preroll */
161 {
162 GstBuffer *buffer;
163 GstFlowReturn fret;
164 ChainData *data;
165 GstState current, pending;
166
167 buffer = gst_buffer_new ();
168 GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
169 GST_BUFFER_DURATION (buffer) = 1 * GST_MSECOND;
170
171 GST_DEBUG ("sending buffer to finish preroll");
172 data = chain_async (sinkpad, buffer);
173 fail_if (data == NULL);
174
175 /* state should now eventually change to PAUSED */
176 ret = gst_element_get_state (sink, ¤t, &pending, GST_CLOCK_TIME_NONE);
177 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
178 fail_unless (current == GST_STATE_PAUSED);
179 fail_unless (pending == GST_STATE_VOID_PENDING);
180
181 /* playing should render the buffer */
182 ret = gst_element_set_state (sink, GST_STATE_PLAYING);
183 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
184
185 /* and we should get a success return value */
186 fret = chain_async_return (data);
187 fail_if (fret != GST_FLOW_OK);
188 }
189
190 /* send some buffer that will be dropped or clipped, this can
191 * only be observed in the debug log. */
192 {
193 GstBuffer *buffer;
194 GstFlowReturn fret;
195
196 buffer = gst_buffer_new ();
197 GST_BUFFER_TIMESTAMP (buffer) = 6 * GST_SECOND;
198 GST_BUFFER_DURATION (buffer) = 1 * GST_MSECOND;
199
200 /* should be dropped */
201 GST_DEBUG ("sending buffer to drop");
202 fret = gst_pad_chain (sinkpad, buffer);
203 fail_if (fret != GST_FLOW_OK);
204
205 buffer = gst_buffer_new ();
206 GST_BUFFER_TIMESTAMP (buffer) = 0 * GST_SECOND;
207 GST_BUFFER_DURATION (buffer) = 2 * GST_SECOND;
208
209 /* should be clipped */
210 GST_DEBUG ("sending buffer to clip");
211 fret = gst_pad_chain (sinkpad, buffer);
212 fail_if (fret != GST_FLOW_OK);
213
214 buffer = gst_buffer_new ();
215 GST_BUFFER_TIMESTAMP (buffer) = 4 * GST_SECOND;
216 GST_BUFFER_DURATION (buffer) = 2 * GST_SECOND;
217
218 /* should be clipped */
219 GST_DEBUG ("sending buffer to clip");
220 fret = gst_pad_chain (sinkpad, buffer);
221 fail_if (fret != GST_FLOW_OK);
222 }
223
224 gst_element_set_state (sink, GST_STATE_NULL);
225 gst_element_get_state (sink, NULL, NULL, GST_CLOCK_TIME_NONE);
226 gst_object_unref (sinkpad);
227 gst_object_unref (sink);
228 }
229
230 GST_END_TEST;
231
232 static gint num_preroll = 0;
233
234 static void
preroll_count(GstElement * sink)235 preroll_count (GstElement * sink)
236 {
237 num_preroll++;
238 GST_DEBUG ("got preroll handoff %d", num_preroll);
239 }
240
GST_START_TEST(test_preroll_sync)241 GST_START_TEST (test_preroll_sync)
242 {
243 GstElement *pipeline, *sink;
244 GstPad *sinkpad;
245 GstStateChangeReturn ret;
246
247 /* create sink */
248 pipeline = gst_pipeline_new ("pipeline");
249 fail_if (pipeline == NULL);
250
251 sink = gst_element_factory_make ("fakesink", "sink");
252 fail_if (sink == NULL);
253 g_object_set (G_OBJECT (sink), "sync", TRUE, NULL);
254 g_object_set (G_OBJECT (sink), "signal-handoffs", TRUE, NULL);
255 g_signal_connect (sink, "preroll-handoff", G_CALLBACK (preroll_count), NULL);
256
257 fail_unless (num_preroll == 0);
258
259 gst_bin_add (GST_BIN (pipeline), sink);
260
261 sinkpad = gst_element_get_static_pad (sink, "sink");
262 fail_if (sinkpad == NULL);
263
264 /* make pipeline and element ready to accept data */
265 ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
266 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
267
268 gst_pad_send_event (sinkpad, gst_event_new_stream_start ("test"));
269
270 /* send segment */
271 {
272 GstEvent *event;
273 GstSegment segment;
274 gboolean eret;
275
276 GST_DEBUG ("sending segment");
277 gst_segment_init (&segment, GST_FORMAT_TIME);
278 segment.start = 0 * GST_SECOND;
279 segment.stop = 102 * GST_SECOND;
280 segment.time = 0 * GST_SECOND;
281
282 event = gst_event_new_segment (&segment);
283 eret = gst_pad_send_event (sinkpad, event);
284 fail_if (eret == FALSE);
285 }
286
287 /* send buffer that should block and finish preroll */
288 {
289 GstBuffer *buffer;
290 GstFlowReturn fret;
291 ChainData *data;
292 GstState current, pending;
293
294 buffer = gst_buffer_new ();
295 GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
296 GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
297
298 GST_DEBUG ("sending buffer to finish preroll");
299 data = chain_async (sinkpad, buffer);
300 fail_if (data == NULL);
301
302 /* state should now eventually change to PAUSED */
303 ret =
304 gst_element_get_state (pipeline, ¤t, &pending,
305 GST_CLOCK_TIME_NONE);
306 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
307 fail_unless (current == GST_STATE_PAUSED);
308 fail_unless (pending == GST_STATE_VOID_PENDING);
309
310 fail_unless (num_preroll == 1);
311
312 /* playing should render the buffer */
313 ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
314 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
315
316 /* and we should get a success return value */
317 fret = chain_async_return (data);
318 fail_if (fret != GST_FLOW_OK);
319
320 /* now we are playing no new preroll was done */
321 fail_unless (num_preroll == 1);
322
323 buffer = gst_buffer_new ();
324 /* far in the future to make sure we block */
325 GST_BUFFER_TIMESTAMP (buffer) = 100 * GST_SECOND;
326 GST_BUFFER_DURATION (buffer) = 100 * GST_SECOND;
327 data = chain_async (sinkpad, buffer);
328 fail_if (data == NULL);
329
330 g_usleep (1000000);
331
332 /* pause again. Since the buffer has a humongous timestamp we likely
333 * interrupt the clock_wait and we should preroll on this buffer again */
334 ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
335 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
336
337 ret =
338 gst_element_get_state (pipeline, ¤t, &pending,
339 GST_CLOCK_TIME_NONE);
340 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
341 fail_unless (current == GST_STATE_PAUSED);
342 fail_unless (pending == GST_STATE_VOID_PENDING);
343
344 fail_unless (num_preroll == 2);
345
346 /* shutdown */
347 ret = gst_element_set_state (pipeline, GST_STATE_READY);
348 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
349
350 /* should be wrong state now */
351 fret = chain_async_return (data);
352 fail_if (fret != GST_FLOW_FLUSHING);
353 }
354 gst_element_set_state (pipeline, GST_STATE_NULL);
355 gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
356 gst_object_unref (sinkpad);
357 gst_object_unref (pipeline);
358 }
359
360 GST_END_TEST;
361
362 /* after EOS, we refuse everything */
GST_START_TEST(test_eos)363 GST_START_TEST (test_eos)
364 {
365 GstElement *pipeline, *sink;
366 GstPad *sinkpad;
367 GstStateChangeReturn ret;
368 GstMessage *message;
369 GstBus *bus;
370
371 /* create sink */
372 pipeline = gst_pipeline_new ("pipeline");
373 fail_if (pipeline == NULL);
374
375 bus = gst_pipeline_get_bus (GST_PIPELINE_CAST (pipeline));
376 fail_if (bus == NULL);
377
378 sink = gst_element_factory_make ("fakesink", "sink");
379 fail_if (sink == NULL);
380 g_object_set (G_OBJECT (sink), "sync", TRUE, NULL);
381
382 gst_bin_add (GST_BIN (pipeline), sink);
383
384 sinkpad = gst_element_get_static_pad (sink, "sink");
385 fail_if (sinkpad == NULL);
386
387 /* make pipeline and element ready to accept data */
388 ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
389 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
390
391 /* send EOS, this should work fine */
392 {
393 GstEvent *eos;
394 gboolean eret;
395
396 GST_DEBUG ("sending EOS");
397 eos = gst_event_new_eos ();
398
399 eret = gst_pad_send_event (sinkpad, eos);
400 fail_if (eret == FALSE);
401 }
402
403 /* wait for preroll */
404 gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
405
406 /* EOS should be on the bus at some point */
407 while (TRUE) {
408 GstMessageType type;
409
410 /* blocking wait for messages */
411 message = gst_bus_timed_pop (bus, GST_CLOCK_TIME_NONE);
412 type = GST_MESSAGE_TYPE (message);
413 gst_message_unref (message);
414
415 GST_DEBUG ("got message %s", gst_message_type_get_name (type));
416
417 if (type == GST_MESSAGE_EOS)
418 break;
419 }
420 gst_object_unref (bus);
421
422 /* send another EOS, this should fail */
423 {
424 GstEvent *eos;
425 gboolean eret;
426
427 GST_DEBUG ("sending second EOS");
428 eos = gst_event_new_eos ();
429
430 eret = gst_pad_send_event (sinkpad, eos);
431 fail_if (eret == TRUE);
432 }
433
434 /* send segment, this should fail */
435 {
436 GstEvent *event;
437 GstSegment segment;
438 gboolean eret;
439
440 GST_DEBUG ("sending segment");
441 gst_segment_init (&segment, GST_FORMAT_TIME);
442 segment.start = 0 * GST_SECOND;
443 segment.stop = 2 * GST_SECOND;
444 segment.time = 0 * GST_SECOND;
445 event = gst_event_new_segment (&segment);
446
447 eret = gst_pad_send_event (sinkpad, event);
448 fail_if (eret == TRUE);
449 }
450
451 /* send buffer that should fail after EOS */
452 {
453 GstBuffer *buffer;
454 GstFlowReturn fret;
455
456 buffer = gst_buffer_new ();
457 GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
458 GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
459
460 GST_DEBUG ("sending buffer");
461
462 /* buffer after EOS is not EOS */
463 fret = gst_pad_chain (sinkpad, buffer);
464 fail_unless (fret == GST_FLOW_EOS);
465 }
466
467 /* flush, EOS state is flushed again. */
468 {
469 GstEvent *event;
470 gboolean eret;
471
472 GST_DEBUG ("sending FLUSH_START");
473 event = gst_event_new_flush_start ();
474 eret = gst_pad_send_event (sinkpad, event);
475 fail_unless (eret == TRUE);
476
477 GST_DEBUG ("sending FLUSH_STOP");
478 event = gst_event_new_flush_stop (TRUE);
479 eret = gst_pad_send_event (sinkpad, event);
480 fail_unless (eret == TRUE);
481 }
482
483 gst_pad_send_event (sinkpad, gst_event_new_stream_start ("test"));
484
485 /* send segment, this should now work again */
486 {
487 GstEvent *event;
488 GstSegment segment;
489 gboolean eret;
490
491 GST_DEBUG ("sending segment");
492 gst_segment_init (&segment, GST_FORMAT_TIME);
493 segment.start = 0 * GST_SECOND;
494 segment.stop = 2 * GST_SECOND;
495 segment.time = 0 * GST_SECOND;
496 event = gst_event_new_segment (&segment);
497
498 eret = gst_pad_send_event (sinkpad, event);
499 fail_unless (eret == TRUE);
500 }
501
502 /* send buffer that should work and block */
503 {
504 GstBuffer *buffer;
505 GstFlowReturn fret;
506
507 buffer = gst_buffer_new ();
508 GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
509 GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
510
511 GST_DEBUG ("sending buffer");
512
513 fret = gst_pad_chain (sinkpad, buffer);
514 fail_unless (fret == GST_FLOW_OK);
515 }
516
517 gst_element_set_state (pipeline, GST_STATE_NULL);
518 gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
519 gst_object_unref (sinkpad);
520 gst_object_unref (pipeline);
521 }
522
523 GST_END_TEST;
524
525 /* test EOS triggered by the element */
GST_START_TEST(test_eos2)526 GST_START_TEST (test_eos2)
527 {
528 GstElement *pipeline, *sink;
529 GstPad *sinkpad;
530 GstStateChangeReturn ret;
531
532 /* create sink */
533 pipeline = gst_pipeline_new ("pipeline");
534 fail_if (pipeline == NULL);
535
536 sink = gst_element_factory_make ("fakesink", "sink");
537 fail_if (sink == NULL);
538 g_object_set (G_OBJECT (sink), "sync", TRUE, NULL);
539 g_object_set (G_OBJECT (sink), "num-buffers", 1, NULL);
540
541 gst_bin_add (GST_BIN (pipeline), sink);
542
543 sinkpad = gst_element_get_static_pad (sink, "sink");
544 fail_if (sinkpad == NULL);
545
546 /* make pipeline and element ready to accept data */
547 ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
548 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
549
550 gst_pad_send_event (sinkpad, gst_event_new_stream_start ("test"));
551
552 /* send segment, this should work */
553 {
554 GstEvent *event;
555 GstSegment segment;
556 gboolean eret;
557
558 GST_DEBUG ("sending segment");
559 gst_segment_init (&segment, GST_FORMAT_TIME);
560 segment.start = 0 * GST_SECOND;
561 segment.stop = 2 * GST_SECOND;
562 segment.time = 0 * GST_SECOND;
563 event = gst_event_new_segment (&segment);
564
565 eret = gst_pad_send_event (sinkpad, event);
566 fail_if (eret == FALSE);
567 }
568
569 /* send buffer that should return EOS */
570 {
571 GstBuffer *buffer;
572 GstFlowReturn fret;
573
574 buffer = gst_buffer_new ();
575 GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
576 GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
577
578 GST_DEBUG ("sending buffer");
579
580 /* this buffer will generate EOS */
581 fret = gst_pad_chain (sinkpad, buffer);
582 fail_unless (fret == GST_FLOW_EOS);
583 }
584
585 /* send buffer that should return EOS */
586 {
587 GstBuffer *buffer;
588 GstFlowReturn fret;
589
590 buffer = gst_buffer_new ();
591 GST_BUFFER_TIMESTAMP (buffer) = 1 * GST_SECOND;
592 GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
593
594 GST_DEBUG ("sending buffer");
595
596 fret = gst_pad_chain (sinkpad, buffer);
597 fail_unless (fret == GST_FLOW_EOS);
598 }
599
600 gst_element_set_state (pipeline, GST_STATE_NULL);
601 gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
602 gst_object_unref (sinkpad);
603 gst_object_unref (pipeline);
604 }
605
606 GST_END_TEST;
607
608 /* test position reporting before, during and after flush
609 * in PAUSED and PLAYING */
GST_START_TEST(test_position)610 GST_START_TEST (test_position)
611 {
612 GstElement *pipeline, *sink;
613 GstPad *sinkpad;
614 GstStateChangeReturn ret;
615 gboolean qret;
616 gint64 qcur;
617 GstBuffer *buffer;
618 GstFlowReturn fret;
619 ChainData *data;
620 GstEvent *event;
621 gboolean eret;
622 gint i;
623
624 /* create sink */
625 pipeline = gst_pipeline_new ("pipeline");
626 fail_if (pipeline == NULL);
627
628 sink = gst_element_factory_make ("fakesink", "sink");
629 fail_if (sink == NULL);
630 g_object_set (G_OBJECT (sink), "sync", TRUE, NULL);
631 g_object_set (G_OBJECT (sink), "num-buffers", 2, NULL);
632
633 gst_bin_add (GST_BIN (pipeline), sink);
634
635 sinkpad = gst_element_get_static_pad (sink, "sink");
636 fail_if (sinkpad == NULL);
637
638 /* do position query, this should fail, we have nothing received yet */
639 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
640 fail_unless (qret == FALSE);
641
642 ret = gst_element_set_state (pipeline, GST_STATE_READY);
643 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
644
645 /* do position query, this should fail, we have nothing received yet */
646 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
647 fail_unless (qret == FALSE);
648
649 /* make pipeline and element ready to accept data */
650 ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
651 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
652
653 /* do position query, this should fail, we have nothing received yet */
654 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
655 fail_unless (qret == FALSE);
656
657 gst_pad_send_event (sinkpad, gst_event_new_stream_start ("test"));
658
659 /* send segment, this should work */
660 {
661 GstSegment segment;
662
663 GST_DEBUG ("sending segment");
664 gst_segment_init (&segment, GST_FORMAT_TIME);
665 segment.start = 1 * GST_SECOND;
666 segment.stop = 3 * GST_SECOND;
667 segment.time = 1 * GST_SECOND;
668 event = gst_event_new_segment (&segment);
669
670 eret = gst_pad_send_event (sinkpad, event);
671 fail_if (eret == FALSE);
672 }
673
674 /* FIXME, do position query, this should succeed with the time value from the
675 * segment. */
676 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
677 fail_unless (qret == TRUE);
678 fail_unless (qcur == 1 * GST_SECOND);
679
680 /* send buffer that we will flush out */
681 buffer = gst_buffer_new ();
682 GST_BUFFER_TIMESTAMP (buffer) = 2 * GST_SECOND;
683 GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
684
685 GST_DEBUG ("sending buffer");
686
687 /* this buffer causes the sink to preroll */
688 data = chain_async (sinkpad, buffer);
689 fail_if (data == NULL);
690
691 /* wait for preroll */
692 ret = gst_element_get_state (pipeline, NULL, NULL, -1);
693
694 /* do position query, this should succeed with the time value from the
695 * segment. */
696 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
697 fail_unless (qret == TRUE);
698 fail_unless (qcur == 1 * GST_SECOND);
699
700 /* start flushing, no timing is affected yet */
701 {
702 GST_DEBUG ("sending flush_start");
703 event = gst_event_new_flush_start ();
704
705 eret = gst_pad_send_event (sinkpad, event);
706 fail_if (eret == FALSE);
707 }
708
709 /* preroll buffer is flushed out */
710 fret = chain_async_return (data);
711 fail_unless (fret == GST_FLOW_FLUSHING);
712
713 /* do position query, this should succeed with the time value from the
714 * segment before the flush. */
715 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
716 fail_unless (qret == TRUE);
717 fail_unless (qcur == 1 * GST_SECOND);
718
719 /* stop flushing, timing is affected now */
720 {
721 GST_DEBUG ("sending flush_stop");
722 event = gst_event_new_flush_stop (TRUE);
723
724 eret = gst_pad_send_event (sinkpad, event);
725 fail_if (eret == FALSE);
726 }
727
728 /* do position query, this should fail, the segment is flushed */
729 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
730 fail_unless (qret == FALSE);
731
732 /* send segment, this should work */
733 {
734 GstSegment segment;
735
736 GST_DEBUG ("sending segment");
737 gst_segment_init (&segment, GST_FORMAT_TIME);
738 segment.start = 2 * GST_SECOND;
739 segment.stop = 4 * GST_SECOND;
740 segment.time = 1 * GST_SECOND;
741 event = gst_event_new_segment (&segment);
742
743 eret = gst_pad_send_event (sinkpad, event);
744 fail_if (eret == FALSE);
745 }
746
747 /* send buffer that should return OK */
748 buffer = gst_buffer_new ();
749 GST_BUFFER_TIMESTAMP (buffer) = 3 * GST_SECOND;
750 GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
751
752 GST_DEBUG ("sending buffer");
753
754 /* this buffer causes the sink to preroll */
755 data = chain_async (sinkpad, buffer);
756 fail_if (data == NULL);
757
758 /* wait for preroll */
759 ret = gst_element_get_state (pipeline, NULL, NULL, -1);
760
761 /* do position query, this should succeed with the time value from the
762 * segment. */
763 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
764 fail_unless (qret == TRUE);
765 fail_unless (qcur == 1 * GST_SECOND);
766
767 ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
768 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
769
770 /* position now is increasing but never exceeds the boundaries of the segment */
771 for (i = 0; i < 5; i++) {
772 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
773 GST_DEBUG ("position %" GST_TIME_FORMAT, GST_TIME_ARGS (qcur));
774 fail_unless (qret == TRUE);
775 fail_unless (qcur >= 1 * GST_SECOND && qcur <= 3 * GST_SECOND);
776 g_usleep (1000 * 250);
777 }
778
779 /* preroll buffer is rendered, we expect one more buffer after this one */
780 fret = chain_async_return (data);
781 fail_unless (fret == GST_FLOW_OK);
782
783 /* after rendering the position must be bigger then the stream_time of the
784 * buffer */
785 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
786 fail_unless (qret == TRUE);
787 fail_unless (qcur >= 2 * GST_SECOND && qcur <= 3 * GST_SECOND);
788
789 /* start flushing in PLAYING */
790 {
791 GST_DEBUG ("sending flush_start");
792 event = gst_event_new_flush_start ();
793
794 eret = gst_pad_send_event (sinkpad, event);
795 fail_if (eret == FALSE);
796 }
797
798 /* this should now just report the last stream time */
799 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
800 fail_unless (qret == TRUE);
801 fail_unless (qcur >= 2 * GST_SECOND && qcur <= 3 * GST_SECOND);
802
803 {
804 GST_DEBUG ("sending flush_stop");
805 event = gst_event_new_flush_stop (TRUE);
806
807 eret = gst_pad_send_event (sinkpad, event);
808 fail_if (eret == FALSE);
809 }
810
811 /* do position query, this should fail, the segment is flushed */
812 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
813 fail_unless (qret == FALSE);
814
815 /* send segment, this should work */
816 {
817 GstSegment segment;
818
819 GST_DEBUG ("sending segment");
820 gst_segment_init (&segment, GST_FORMAT_TIME);
821 segment.start = 2 * GST_SECOND;
822 segment.stop = 4 * GST_SECOND;
823 segment.time = 1 * GST_SECOND;
824 event = gst_event_new_segment (&segment);
825
826 eret = gst_pad_send_event (sinkpad, event);
827 fail_if (eret == FALSE);
828 }
829
830 /* send buffer that should return EOS */
831 buffer = gst_buffer_new ();
832 GST_BUFFER_TIMESTAMP (buffer) = 3 * GST_SECOND;
833 GST_BUFFER_DURATION (buffer) = 1 * GST_SECOND;
834
835 GST_DEBUG ("sending buffer");
836
837 /* this buffer causes the sink to preroll */
838 data = chain_async (sinkpad, buffer);
839 fail_if (data == NULL);
840
841 /* wait for preroll */
842 ret = gst_element_get_state (pipeline, NULL, NULL, -1);
843
844 /* preroll buffer is rendered, we expect no more buffer after this one */
845 fret = chain_async_return (data);
846 fail_unless (fret == GST_FLOW_EOS);
847
848 /* do position query, this should succeed with the stream time of the buffer
849 * against the clock. Since the buffer is synced against the clock, the time
850 * should be at least the stream time of the buffer. */
851 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
852 fail_unless (qret == TRUE);
853 fail_unless (qcur >= 2 * GST_SECOND && qcur <= 3 * GST_SECOND);
854
855 /* wait 2 more seconds, enough to test if the position was clipped correctly
856 * against the segment */
857 g_usleep (2 * G_USEC_PER_SEC);
858
859 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
860 fail_unless (qret == TRUE);
861 fail_unless (qcur == 3 * GST_SECOND);
862
863 GST_DEBUG ("going to PAUSED");
864
865 ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
866 fail_unless (ret == GST_STATE_CHANGE_ASYNC);
867
868 /* we report the time of the last start of the buffer. This is slightly
869 * incorrect, we should report the exact time when we paused but there is no
870 * record of that anywhere */
871 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
872 fail_unless (qret == TRUE);
873 fail_unless (qcur == 3 * GST_SECOND);
874
875 ret = gst_element_set_state (pipeline, GST_STATE_READY);
876 fail_unless (ret == GST_STATE_CHANGE_SUCCESS);
877
878 /* fails again because we are in the wrong state */
879 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
880 fail_unless (qret == FALSE);
881
882 gst_element_set_state (pipeline, GST_STATE_NULL);
883
884 qret = gst_element_query_position (sink, GST_FORMAT_TIME, &qcur);
885 fail_unless (qret == FALSE);
886
887 gst_object_unref (sinkpad);
888 gst_object_unref (pipeline);
889 }
890
891 GST_END_TEST;
892
893 /* like fakesrc, but also pushes an OOB event after each buffer */
894 typedef GstPushSrc OOBSource;
895 typedef GstPushSrcClass OOBSourceClass;
896
897 GType oob_source_get_type (void);
898 G_DEFINE_TYPE (OOBSource, oob_source, GST_TYPE_PUSH_SRC);
899
900 static GstFlowReturn
oob_source_create(GstPushSrc * src,GstBuffer ** p_buf)901 oob_source_create (GstPushSrc * src, GstBuffer ** p_buf)
902 {
903 *p_buf = gst_buffer_new ();
904
905 gst_pad_push_event (GST_BASE_SRC_PAD (src),
906 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM_OOB, NULL));
907
908 return GST_FLOW_OK;
909 }
910
911 static void
oob_source_class_init(OOBSourceClass * klass)912 oob_source_class_init (OOBSourceClass * klass)
913 {
914 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("src",
915 GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
916 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
917 GstPushSrcClass *pushsrc_class = GST_PUSH_SRC_CLASS (klass);
918
919 gst_element_class_add_static_pad_template (element_class, &sinktemplate);
920
921 pushsrc_class->create = GST_DEBUG_FUNCPTR (oob_source_create);
922 }
923
924 static void
oob_source_init(OOBSource * src)925 oob_source_init (OOBSource * src)
926 {
927 /* nothing to do */
928 }
929
930 #define NOTIFY_RACE_NUM_PIPELINES 10
931
932 typedef struct
933 {
934 GstElement *src;
935 GstElement *queue;
936 GstElement *sink;
937 GstElement *pipe;
938 } NotifyRacePipeline;
939
940 static void
test_notify_race_setup_pipeline(NotifyRacePipeline * p)941 test_notify_race_setup_pipeline (NotifyRacePipeline * p)
942 {
943 GST_DEBUG ("Creating pipeline");
944 p->pipe = gst_pipeline_new ("pipeline");
945 p->src = g_object_new (oob_source_get_type (), NULL);
946
947 p->queue = gst_element_factory_make ("queue", NULL);
948 g_object_set (p->queue, "max-size-buffers", 2, NULL);
949
950 p->sink = gst_element_factory_make ("fakesink", NULL);
951 gst_bin_add (GST_BIN (p->pipe), p->src);
952 gst_bin_add (GST_BIN (p->pipe), p->queue);
953 gst_bin_add (GST_BIN (p->pipe), p->sink);
954 gst_element_link_many (p->src, p->queue, p->sink, NULL);
955
956 GST_DEBUG ("Setting pipeline to PAUSED..");
957 fail_unless_equals_int (gst_element_set_state (p->pipe, GST_STATE_PAUSED),
958 GST_STATE_CHANGE_ASYNC);
959 GST_DEBUG ("Waiting for pipeline to preroll..");
960 fail_unless_equals_int (gst_element_get_state (p->pipe, NULL, NULL, -1),
961 GST_STATE_CHANGE_SUCCESS);
962 GST_DEBUG ("Ready to party!");
963 }
964
965 static void
test_notify_race_cleanup_pipeline(NotifyRacePipeline * p)966 test_notify_race_cleanup_pipeline (NotifyRacePipeline * p)
967 {
968 gst_element_set_state (p->pipe, GST_STATE_NULL);
969 gst_object_unref (p->pipe);
970 memset (p, 0, sizeof (NotifyRacePipeline));
971 }
972
973 /* we create N pipelines to make sure the notify race isn't per-class, but
974 * only per instance */
GST_START_TEST(test_notify_race)975 GST_START_TEST (test_notify_race)
976 {
977 NotifyRacePipeline pipelines[NOTIFY_RACE_NUM_PIPELINES];
978 int i;
979
980 for (i = 0; i < G_N_ELEMENTS (pipelines); ++i) {
981 GST_DEBUG ("Setting up pipeline %d", i);
982 test_notify_race_setup_pipeline (&pipelines[i]);
983 }
984
985 for (i = 0; i < G_N_ELEMENTS (pipelines); ++i) {
986 GST_DEBUG ("Starting pipeline %d", i);
987 gst_element_set_state (pipelines[i].pipe, GST_STATE_PLAYING);
988 }
989
990 g_usleep (2 * G_USEC_PER_SEC);
991
992 for (i = 0; i < G_N_ELEMENTS (pipelines); ++i) {
993 GST_DEBUG ("Cleaning up pipeline %d", i);
994 test_notify_race_cleanup_pipeline (&pipelines[i]);
995 }
996 }
997
998 GST_END_TEST;
999
1000 static void
last_message_cb(GObject * obj,GParamSpec * pspec,gpointer user_data)1001 last_message_cb (GObject * obj, GParamSpec * pspec, gpointer user_data)
1002 {
1003 gint *p_counter = user_data;
1004 gchar *s, *end, *last_msg = NULL;
1005 guint64 offset, count;
1006
1007 g_object_get (obj, "last-message", &last_msg, NULL);
1008 fail_unless (last_msg != NULL);
1009
1010 if (!strstr (last_msg, "chain"))
1011 goto skip;
1012
1013 GST_LOG_OBJECT (obj, "%s", last_msg);
1014
1015 s = strstr (last_msg, "offset: ");
1016 fail_unless (s != NULL);
1017
1018 s += strlen ("offset: ");
1019
1020 offset = g_ascii_strtoull (s, &end, 10);
1021 fail_unless (offset < G_MAXUINT64);
1022 fail_if (end == s);
1023
1024 count = *p_counter;
1025
1026 fail_unless_equals_int (count, offset);
1027
1028 *p_counter = count + 1;
1029
1030 skip:
1031
1032 g_free (last_msg);
1033 }
1034
1035 #define NUM_BUFFERS 500
1036
GST_START_TEST(test_last_message_notify)1037 GST_START_TEST (test_last_message_notify)
1038 {
1039 GstElement *pipe, *src, *tee, *q1, *q2, *sink1, *sink2;
1040 gint counter1 = 0;
1041 gint counter2 = 0;
1042 GstMessage *m;
1043
1044 pipe = gst_pipeline_new ("pipeline");
1045 src = gst_element_factory_make ("fakesrc", NULL);
1046 gst_util_set_object_arg (G_OBJECT (src), "sizetype", "fixed");
1047 g_object_set (src, "num-buffers", NUM_BUFFERS, "sizemax", 1, NULL);
1048
1049 tee = gst_element_factory_make ("tee", NULL);
1050
1051 q1 = gst_element_factory_make ("queue", NULL);
1052 sink1 = gst_element_factory_make ("fakesink", NULL);
1053 g_object_set (sink1, "silent", FALSE, NULL);
1054
1055 q2 = gst_element_factory_make ("queue", NULL);
1056 sink2 = gst_element_factory_make ("fakesink", NULL);
1057 g_object_set (sink2, "silent", FALSE, NULL);
1058
1059 gst_bin_add_many (GST_BIN (pipe), src, tee, q1, q2, sink1, sink2, NULL);
1060 fail_unless (gst_element_link_many (src, tee, NULL));
1061 fail_unless (gst_element_link_many (tee, q1, sink1, NULL));
1062 fail_unless (gst_element_link_many (tee, q2, sink2, NULL));
1063
1064 g_signal_connect (sink1, "notify::last-message",
1065 G_CALLBACK (last_message_cb), &counter1);
1066 g_signal_connect (sink2, "notify::last-message",
1067 G_CALLBACK (last_message_cb), &counter2);
1068
1069 GST_DEBUG ("Setting pipeline to PLAYING");
1070 fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_PLAYING),
1071 GST_STATE_CHANGE_ASYNC);
1072
1073 m = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe), -1, GST_MESSAGE_EOS);
1074 gst_message_unref (m);
1075
1076 fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_NULL),
1077 GST_STATE_CHANGE_SUCCESS);
1078
1079 fail_unless_equals_int (counter1, NUM_BUFFERS);
1080 fail_unless_equals_int (counter2, NUM_BUFFERS);
1081
1082 gst_object_unref (pipe);
1083 }
1084
1085 GST_END_TEST;
1086
1087 static void
deep_notify_last_message_cb(GstObject * obj,GstObject * prop_obj,GParamSpec * pspec,gpointer user_data)1088 deep_notify_last_message_cb (GstObject * obj, GstObject * prop_obj,
1089 GParamSpec * pspec, gpointer user_data)
1090 {
1091 gint *counter_array = user_data;
1092 gint *p_counter;
1093 gchar *s, *end, *last_msg = NULL;
1094 guint64 offset, count;
1095
1096 if (strcmp (GST_OBJECT_NAME (prop_obj), "fakesink0") == 0)
1097 p_counter = counter_array;
1098 else if (strcmp (GST_OBJECT_NAME (prop_obj), "fakesink1") == 0)
1099 p_counter = counter_array + 1;
1100 else
1101 g_assert_not_reached ();
1102
1103 g_object_get (prop_obj, "last-message", &last_msg, NULL);
1104 fail_unless (last_msg != NULL);
1105
1106 if (!strstr (last_msg, "chain"))
1107 goto skip;
1108
1109 GST_LOG_OBJECT (prop_obj, "%s", last_msg);
1110
1111 s = strstr (last_msg, "offset: ");
1112 fail_unless (s != NULL);
1113
1114 s += strlen ("offset: ");
1115
1116 offset = g_ascii_strtoull (s, &end, 10);
1117 fail_unless (offset < G_MAXUINT64);
1118 fail_if (end == s);
1119
1120 count = *p_counter;
1121
1122 // fail_unless_equals_int (count, offset);
1123
1124 *p_counter = count + 1;
1125
1126 skip:
1127
1128 g_free (last_msg);
1129 }
1130
GST_START_TEST(test_last_message_deep_notify)1131 GST_START_TEST (test_last_message_deep_notify)
1132 {
1133 GstElement *pipe, *src, *tee, *q1, *q2, *sink1, *sink2;
1134 gint counter[2] = { 0, 0 };
1135 GstMessage *m;
1136
1137 pipe = gst_pipeline_new ("pipeline");
1138 src = gst_element_factory_make ("fakesrc", NULL);
1139 gst_util_set_object_arg (G_OBJECT (src), "sizetype", "fixed");
1140 g_object_set (src, "num-buffers", NUM_BUFFERS, "sizemax", 1, NULL);
1141
1142 tee = gst_element_factory_make ("tee", NULL);
1143
1144 q1 = gst_element_factory_make ("queue", NULL);
1145 sink1 = gst_element_factory_make ("fakesink", NULL);
1146 g_object_set (sink1, "silent", FALSE, NULL);
1147
1148 q2 = gst_element_factory_make ("queue", NULL);
1149 sink2 = gst_element_factory_make ("fakesink", NULL);
1150 g_object_set (sink2, "silent", FALSE, NULL);
1151
1152 gst_bin_add_many (GST_BIN (pipe), src, tee, q1, q2, sink1, sink2, NULL);
1153 fail_unless (gst_element_link_many (src, tee, NULL));
1154 fail_unless (gst_element_link_many (tee, q1, sink1, NULL));
1155 fail_unless (gst_element_link_many (tee, q2, sink2, NULL));
1156
1157 g_signal_connect (pipe, "deep-notify::last-message",
1158 G_CALLBACK (deep_notify_last_message_cb), counter);
1159
1160 GST_DEBUG ("Setting pipeline to PLAYING");
1161 fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_PLAYING),
1162 GST_STATE_CHANGE_ASYNC);
1163
1164 m = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe), -1, GST_MESSAGE_EOS);
1165 gst_message_unref (m);
1166
1167 fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_NULL),
1168 GST_STATE_CHANGE_SUCCESS);
1169
1170 GST_ERROR ("sink1: %d, sink2: %d, total: %d", counter[0], counter[1],
1171 counter[0] + counter[1]);
1172
1173 fail_unless_equals_int (counter[0], NUM_BUFFERS);
1174 fail_unless_equals_int (counter[1], NUM_BUFFERS);
1175 }
1176
1177 GST_END_TEST;
1178
1179 static Suite *
fakesink_suite(void)1180 fakesink_suite (void)
1181 {
1182 Suite *s = suite_create ("fakesink");
1183 TCase *tc_chain = tcase_create ("general");
1184
1185 tcase_set_timeout (tc_chain, 20);
1186
1187 suite_add_tcase (s, tc_chain);
1188 tcase_add_test (tc_chain, test_clipping);
1189 tcase_add_test (tc_chain, test_preroll_sync);
1190 tcase_add_test (tc_chain, test_eos);
1191 tcase_add_test (tc_chain, test_eos2);
1192 tcase_add_test (tc_chain, test_position);
1193 tcase_add_test (tc_chain, test_notify_race);
1194 tcase_add_test (tc_chain, test_last_message_notify);
1195 tcase_skip_broken_test (tc_chain, test_last_message_deep_notify);
1196
1197 return s;
1198 }
1199
1200 GST_CHECK_MAIN (fakesink);
1201