1 /* GStreamer unit tests for textoverlay
3 * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
23 #include <gst/check/gstcheck.h>
25 #define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
26 #define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
27 #define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2)
29 #define I420_Y_OFFSET(w,h) (0)
30 #define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
31 #define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
33 #define I420_SIZE(w,h) (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
38 /* For ease of programming we use globals to keep refs for our floating
39 * src and sink pads we create; otherwise we always have to do get_pad,
40 * get_peer, and then remove references in every test function */
41 static GstPad *myvideosrcpad, *mytextsrcpad, *mysinkpad;
43 #define VIDEO_CAPS_STRING \
45 "format = (string) I420, " \
46 "framerate = (fraction) 1/1, " \
47 "width = (int) 240, " \
50 #define VIDEO_CAPS_TEMPLATE_STRING \
52 "format = (string) I420"
54 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
57 GST_STATIC_CAPS (VIDEO_CAPS_TEMPLATE_STRING)
59 static GstStaticPadTemplate text_srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
62 GST_STATIC_CAPS ("text/x-raw, format=utf8")
65 static GstStaticPadTemplate video_srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
68 GST_STATIC_CAPS (VIDEO_CAPS_TEMPLATE_STRING)
71 /* much like gst_check_setup_src_pad(), but with possibility to give a hint
72 * which sink template of the element to use, if there are multiple ones */
74 notgst_check_setup_src_pad2 (GstElement * element,
75 GstStaticPadTemplate * template, GstCaps * caps,
76 const gchar * sink_template_name)
78 GstPad *srcpad, *sinkpad;
80 if (sink_template_name == NULL)
81 sink_template_name = "sink";
84 srcpad = gst_pad_new_from_static_template (template, "src");
85 GST_DEBUG_OBJECT (element, "setting up sending pad %p", srcpad);
86 fail_if (srcpad == NULL, "Could not create a srcpad");
87 ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1);
89 if (!(sinkpad = gst_element_get_static_pad (element, sink_template_name)))
90 sinkpad = gst_element_get_request_pad (element, sink_template_name);
91 fail_if (sinkpad == NULL, "Could not get sink pad from %s",
92 GST_ELEMENT_NAME (element));
93 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
95 fail_unless (gst_pad_set_caps (srcpad, caps));
96 fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK,
97 "Could not link source and %s sink pads", GST_ELEMENT_NAME (element));
98 gst_object_unref (sinkpad); /* because we got it higher up */
99 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
105 notgst_check_teardown_src_pad2 (GstElement * element,
106 const gchar * sink_template_name)
108 GstPad *srcpad, *sinkpad;
110 if (sink_template_name == NULL)
111 sink_template_name = "sink";
113 /* clean up floating src pad */
114 if (!(sinkpad = gst_element_get_static_pad (element, sink_template_name)))
115 sinkpad = gst_element_get_request_pad (element, sink_template_name);
116 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
117 srcpad = gst_pad_get_peer (sinkpad);
119 gst_pad_unlink (srcpad, sinkpad);
121 /* pad refs held by both creator and this function (through _get) */
122 ASSERT_OBJECT_REFCOUNT (sinkpad, "element sinkpad", 2);
123 gst_object_unref (sinkpad);
124 /* one more ref is held by element itself */
126 /* pad refs held by both creator and this function (through _get_peer) */
127 ASSERT_OBJECT_REFCOUNT (srcpad, "check srcpad", 2);
128 gst_object_unref (srcpad);
129 gst_object_unref (srcpad);
133 setup_textoverlay (gboolean video_only_no_text)
135 GstElement *textoverlay;
137 GST_DEBUG ("setup_textoverlay");
138 textoverlay = gst_check_setup_element ("textoverlay");
139 mysinkpad = gst_check_setup_sink_pad (textoverlay, &sinktemplate);
141 notgst_check_setup_src_pad2 (textoverlay, &video_srctemplate, NULL,
144 if (!video_only_no_text) {
146 notgst_check_setup_src_pad2 (textoverlay, &text_srctemplate, NULL,
148 gst_pad_set_active (mytextsrcpad, TRUE);
153 gst_pad_set_active (myvideosrcpad, TRUE);
154 gst_pad_set_active (mysinkpad, TRUE);
160 buffer_is_all_black (GstBuffer * buf, GstCaps * caps)
166 fail_unless (buf != NULL);
167 fail_unless (caps != NULL);
168 s = gst_caps_get_structure (caps, 0);
169 fail_unless (s != NULL);
170 fail_unless (gst_structure_get_int (s, "width", &w));
171 fail_unless (gst_structure_get_int (s, "height", &h));
173 gst_buffer_map (buf, &map, GST_MAP_READ);
174 for (y = 0; y < h; ++y) {
175 guint8 *ptr = map.data + (y * GST_ROUND_UP_4 (w));
177 for (x = 0; x < w; ++x) {
178 if (ptr[x] != 0x00) {
179 GST_LOG ("non-black pixel (%d) at (x,y) %d,%d", ptr[x], x, y);
180 gst_buffer_unmap (buf, &map);
185 gst_buffer_unmap (buf, &map);
191 create_video_caps (const gchar * caps_string)
195 caps = gst_caps_from_string (caps_string);
196 fail_unless (caps != NULL);
197 fail_unless (gst_caps_is_fixed (caps));
203 create_black_buffer (GstCaps * caps)
209 fail_unless (caps != NULL);
211 s = gst_caps_get_structure (caps, 0);
212 fail_unless (gst_structure_get_int (s, "width", &w));
213 fail_unless (gst_structure_get_int (s, "height", &h));
215 GST_LOG ("creating buffer (%dx%d)", w, h);
217 size = I420_SIZE (w, h);
218 buffer = gst_buffer_new_and_alloc (size);
219 /* we're only checking the Y plane later, so just zero it all out,
220 * even if it's not the blackest black there is */
221 gst_buffer_memset (buffer, 0, 0, size);
223 /* double check to make sure it's been created right */
224 fail_unless (buffer_is_all_black (buffer, caps));
230 create_text_buffer (const gchar * txt, GstClockTime ts, GstClockTime duration)
235 fail_unless (txt != NULL);
237 txt_len = strlen (txt);
239 buffer = gst_buffer_new_and_alloc (txt_len);
240 gst_buffer_fill (buffer, 0, txt, txt_len);
242 GST_BUFFER_TIMESTAMP (buffer) = ts;
243 GST_BUFFER_DURATION (buffer) = duration;
249 cleanup_textoverlay (GstElement * textoverlay)
251 GST_DEBUG ("cleanup_textoverlay");
253 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
254 g_list_free (buffers);
257 gst_element_set_state (textoverlay, GST_STATE_NULL);
258 gst_element_get_state (textoverlay, NULL, NULL, GST_CLOCK_TIME_NONE);
259 gst_pad_set_active (myvideosrcpad, FALSE);
260 gst_pad_set_active (mysinkpad, FALSE);
261 notgst_check_teardown_src_pad2 (textoverlay, "video_sink");
263 notgst_check_teardown_src_pad2 (textoverlay, "text_sink");
265 gst_check_teardown_sink_pad (textoverlay);
266 gst_check_teardown_element (textoverlay);
269 GST_START_TEST (test_video_passthrough)
271 GstElement *textoverlay;
272 GstBuffer *inbuffer, *outbuffer;
273 GstCaps *incaps, *outcaps;
276 textoverlay = setup_textoverlay (TRUE);
277 fail_unless (gst_element_set_state (textoverlay,
278 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
279 "could not set to playing");
281 incaps = create_video_caps (VIDEO_CAPS_STRING);
282 gst_pad_set_caps (myvideosrcpad, incaps);
283 inbuffer = create_black_buffer (incaps);
284 gst_caps_unref (incaps);
286 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
288 /* ========== (1) video buffer without timestamp => should be dropped ==== */
290 /* take additional ref to keep it alive */
291 gst_buffer_ref (inbuffer);
292 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
294 /* pushing gives away one of the two references we have ... */
295 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
297 /* should have been discarded as out-of-segment since it has no timestamp */
298 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
299 fail_unless_equals_int (g_list_length (buffers), 0);
301 /* ========== (2) buffer with 0 timestamp => simple passthrough ========== */
303 /* now try again, this time with timestamp (segment defaults to 0 start) */
304 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
305 GST_BUFFER_DURATION (inbuffer) = GST_CLOCK_TIME_NONE;
307 /* take additional ref to keep it alive */
308 gst_buffer_ref (inbuffer);
309 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
311 /* pushing gives away one of the two references we have ... */
312 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
314 /* text pad is not linked, timestamp is in segment, no static text to
315 * render, should have gone through right away without modification */
316 fail_unless_equals_int (g_list_length (buffers), 1);
317 outbuffer = GST_BUFFER_CAST (buffers->data);
318 fail_unless (outbuffer == inbuffer);
319 outcaps = gst_pad_get_current_caps (mysinkpad);
320 fail_unless (buffer_is_all_black (outbuffer, outcaps));
321 gst_caps_unref (outcaps);
322 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
325 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
326 g_list_free (buffers);
328 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
330 /* ========== (3) buffer with 0 timestamp and no duration, with the
331 * segment starting from 1sec => should be discarded */
333 gst_segment_init (&segment, GST_FORMAT_TIME);
334 segment.start = 1 * GST_SECOND;
337 gst_pad_push_event (myvideosrcpad, gst_event_new_segment (&segment));
339 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
340 GST_BUFFER_DURATION (inbuffer) = GST_CLOCK_TIME_NONE;
342 /* take additional ref to keep it alive */
343 gst_buffer_ref (inbuffer);
344 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
346 /* pushing gives away one of the two references we have ... */
347 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
349 /* should have been discarded as out-of-segment */
350 fail_unless_equals_int (g_list_length (buffers), 0);
351 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
353 /* ========== (4) buffer with 0 timestamp and small defined duration, with
354 * segment starting from 1sec => should be discarded */
356 gst_pad_push_event (myvideosrcpad, gst_event_new_segment (&segment));
358 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 10;
360 /* take additional ref to keep it alive */
361 gst_buffer_ref (inbuffer);
362 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
364 /* pushing gives away one of the two references we have ... */
365 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
367 /* should have been discarded as out-of-segment since it has no timestamp */
368 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
369 fail_unless_equals_int (g_list_length (buffers), 0);
371 /* ========== (5) buffer partially overlapping into the segment => should
372 * be pushed through, but with adjusted stamp values */
374 gst_pad_push_event (myvideosrcpad, gst_event_new_segment (&segment));
376 GST_BUFFER_TIMESTAMP (inbuffer) = GST_SECOND / 4;
377 GST_BUFFER_DURATION (inbuffer) = GST_SECOND;
379 /* take additional ref to keep it alive */
380 gst_buffer_ref (inbuffer);
381 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
383 /* pushing gives away one of the two references we have ... */
384 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
386 /* should be a new buffer for the stamp fix-up */
387 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
388 fail_unless_equals_int (g_list_length (buffers), 1);
389 outbuffer = GST_BUFFER_CAST (buffers->data);
390 outcaps = gst_pad_get_current_caps (mysinkpad);
391 fail_unless (outbuffer != inbuffer);
392 fail_unless (GST_BUFFER_TIMESTAMP (outbuffer) == GST_SECOND);
393 fail_unless (GST_BUFFER_DURATION (outbuffer) == (GST_SECOND / 4));
394 fail_unless (buffer_is_all_black (outbuffer, outcaps));
395 gst_caps_unref (outcaps);
397 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
398 g_list_free (buffers);
400 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
403 cleanup_textoverlay (textoverlay);
404 gst_buffer_unref (inbuffer);
409 GST_START_TEST (test_video_render_static_text)
411 GstElement *textoverlay;
412 GstBuffer *inbuffer, *outbuffer;
413 GstCaps *incaps, *outcaps;
415 textoverlay = setup_textoverlay (TRUE);
417 /* set static text to render */
418 g_object_set (textoverlay, "text", "XLX", NULL);
420 fail_unless (gst_element_set_state (textoverlay,
421 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
422 "could not set to playing");
424 incaps = create_video_caps (VIDEO_CAPS_STRING);
425 gst_pad_set_caps (myvideosrcpad, incaps);
426 inbuffer = create_black_buffer (incaps);
427 gst_caps_unref (incaps);
428 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
430 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
431 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 10;
433 /* take additional ref to keep it alive */
434 gst_buffer_ref (inbuffer);
435 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
437 /* pushing gives away one of the two references we have ... */
438 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
440 /* should have been dropped in favour of a new writable buffer */
441 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
442 fail_unless_equals_int (g_list_length (buffers), 1);
443 outbuffer = GST_BUFFER_CAST (buffers->data);
444 outcaps = gst_pad_get_current_caps (mysinkpad);
445 fail_unless (outbuffer != inbuffer);
447 /* there should be text rendered */
448 fail_unless (buffer_is_all_black (outbuffer, outcaps) == FALSE);
449 gst_caps_unref (outcaps);
451 fail_unless (GST_BUFFER_TIMESTAMP (outbuffer) == 0);
452 fail_unless (GST_BUFFER_DURATION (outbuffer) == (GST_SECOND / 10));
455 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
456 g_list_free (buffers);
458 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
461 cleanup_textoverlay (textoverlay);
462 gst_buffer_unref (inbuffer);
468 test_video_waits_for_text_send_text_newsegment_thread (gpointer data)
472 g_usleep (1 * G_USEC_PER_SEC);
474 /* send an update newsegment; the video buffer should now be pushed through
475 * even though there is no text buffer queued at the moment */
476 GST_INFO ("Sending newsegment update on text pad");
477 gst_segment_init (&segment, GST_FORMAT_TIME);
478 segment.base = 35 * GST_SECOND;
479 segment.start = 35 * GST_SECOND;
480 segment.time = 35 * GST_SECOND;
481 gst_pad_push_event (mytextsrcpad, gst_event_new_segment (&segment));
487 test_video_waits_for_text_shutdown_element (gpointer data)
489 g_usleep (1 * G_USEC_PER_SEC);
491 GST_INFO ("Trying to shut down textoverlay element ...");
492 /* set to NULL state to make sure we can shut it down while it's
493 * blocking in the video chain function waiting for a text buffer */
494 gst_element_set_state (GST_ELEMENT (data), GST_STATE_NULL);
500 GST_START_TEST (test_video_waits_for_text)
502 GstElement *textoverlay;
503 GstBuffer *inbuffer, *outbuffer, *tbuf;
504 GstCaps *caps, *incaps, *outcaps;
507 textoverlay = setup_textoverlay (FALSE);
509 fail_unless (gst_element_set_state (textoverlay,
510 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
511 "could not set to playing");
513 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, "utf8",
515 gst_pad_set_caps (mytextsrcpad, caps);
516 gst_caps_unref (caps);
518 tbuf = create_text_buffer ("XLX", 1 * GST_SECOND, 5 * GST_SECOND);
519 gst_buffer_ref (tbuf);
520 ASSERT_BUFFER_REFCOUNT (tbuf, "tbuf", 2);
522 GST_LOG ("pushing text buffer");
523 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
525 /* it should be stuck in textoverlay until it gets a text buffer or a
526 * newsegment event that indicates it's not needed any longer */
527 fail_unless_equals_int (g_list_length (buffers), 0);
529 incaps = create_video_caps (VIDEO_CAPS_STRING);
530 gst_pad_set_caps (myvideosrcpad, incaps);
531 inbuffer = create_black_buffer (incaps);
532 gst_caps_unref (incaps);
533 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
535 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
536 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 2;
538 /* pushing gives away one of the two references we have ... */
539 GST_LOG ("pushing video buffer 1");
540 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
542 /* video buffer should have gone through untainted, since the text is later */
543 fail_unless_equals_int (g_list_length (buffers), 1);
545 /* text should still be stuck in textoverlay */
546 ASSERT_BUFFER_REFCOUNT (tbuf, "tbuf", 2);
548 /* there should be no text rendered */
549 outbuffer = GST_BUFFER_CAST (buffers->data);
550 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
551 outcaps = gst_pad_get_current_caps (mysinkpad);
552 fail_unless (buffer_is_all_black (outbuffer, outcaps));
553 gst_caps_unref (outcaps);
555 /* now, another video buffer */
556 inbuffer = create_black_buffer (incaps);
557 GST_BUFFER_TIMESTAMP (inbuffer) = GST_SECOND;
558 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 2;
559 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
561 /* pushing gives away one of the two references we have ... */
562 GST_LOG ("pushing video buffer 2");
563 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
565 /* video buffer should have gone right away, with text rendered on it */
566 fail_unless_equals_int (g_list_length (buffers), 2);
568 /* text should still be stuck in textoverlay */
569 ASSERT_BUFFER_REFCOUNT (tbuf, "tbuf", 2);
571 /* there should be text rendered */
572 outbuffer = GST_BUFFER_CAST (buffers->next->data);
573 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
574 outcaps = gst_pad_get_current_caps (mysinkpad);
575 fail_unless (buffer_is_all_black (outbuffer, outcaps) == FALSE);
576 gst_caps_unref (outcaps);
578 /* a third video buffer */
579 inbuffer = create_black_buffer (incaps);
580 GST_BUFFER_TIMESTAMP (inbuffer) = 30 * GST_SECOND;
581 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 2;
583 /* video buffer #3: should not go through, it should discard the current
584 * text buffer as too old and then wait for the next text buffer (or a
585 * newsegment event to arrive); we spawn a background thread to send such
586 * a newsegment event after a second or so so we get back control */
588 g_thread_try_new ("gst-check",
589 test_video_waits_for_text_send_text_newsegment_thread, NULL, NULL);
590 fail_unless (thread != NULL);
591 g_thread_unref (thread);
593 GST_LOG ("pushing video buffer 3");
594 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
596 /* but the text should no longer be stuck in textoverlay */
597 ASSERT_BUFFER_REFCOUNT (tbuf, "tbuf", 1);
599 /* video buffer should have gone through after newsegment event */
600 fail_unless_equals_int (g_list_length (buffers), 3);
602 /* ... and there should not be any text rendered on it */
603 outbuffer = GST_BUFFER_CAST (buffers->next->next->data);
604 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
605 outcaps = gst_pad_get_current_caps (mysinkpad);
606 fail_unless (buffer_is_all_black (outbuffer, outcaps));
607 gst_caps_unref (outcaps);
609 /* a fourth video buffer */
610 inbuffer = create_black_buffer (incaps);
611 GST_BUFFER_TIMESTAMP (inbuffer) = 35 * GST_SECOND;
612 GST_BUFFER_DURATION (inbuffer) = GST_SECOND;
614 /* video buffer #4: should not go through, it should wait for the next
615 * text buffer (or a newsegment event) to arrive; we spawn a background
616 * thread to shut down the element while it's waiting to make sure that
618 thread = g_thread_try_new ("gst-check",
619 test_video_waits_for_text_shutdown_element, textoverlay, NULL);
620 fail_unless (thread != NULL);
621 g_thread_unref (thread);
623 GST_LOG ("pushing video buffer 4");
624 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_FLUSHING);
627 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
628 g_list_free (buffers);
632 cleanup_textoverlay (textoverlay);
634 /* give up our ref, textoverlay should've cleared its queued buffer by now */
635 ASSERT_BUFFER_REFCOUNT (tbuf, "tbuf", 1);
636 gst_buffer_unref (tbuf);
642 test_render_continuity_push_video_buffers_thread (gpointer data)
644 /* push video buffers at 1fps */
645 guint frame_count = 0;
648 vcaps = create_video_caps (VIDEO_CAPS_STRING);
649 gst_pad_set_caps (myvideosrcpad, vcaps);
654 vbuf = create_black_buffer (vcaps);
655 ASSERT_BUFFER_REFCOUNT (vbuf, "vbuf", 1);
657 GST_BUFFER_TIMESTAMP (vbuf) = frame_count * GST_SECOND;
658 GST_BUFFER_DURATION (vbuf) = GST_SECOND;
660 /* pushing gives away one of the two references we have ... */
661 GST_LOG ("pushing video buffer %u @ %" GST_TIME_FORMAT, frame_count,
662 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (vbuf)));
663 fail_unless (gst_pad_push (myvideosrcpad, vbuf) == GST_FLOW_OK);
666 } while (frame_count < 15);
668 gst_caps_unref (vcaps);
673 GST_START_TEST (test_render_continuity)
676 GstElement *textoverlay;
678 GstCaps *caps, *outcaps;
680 textoverlay = setup_textoverlay (FALSE);
682 fail_unless (gst_element_set_state (textoverlay,
683 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
684 "could not set to playing");
686 thread = g_thread_try_new ("gst-check",
687 test_render_continuity_push_video_buffers_thread, NULL, NULL);
688 fail_unless (thread != NULL);
689 g_thread_unref (thread);
691 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, "utf8",
693 gst_pad_set_caps (mytextsrcpad, caps);
694 gst_caps_unref (caps);
696 tbuf = create_text_buffer ("XLX", 2 * GST_SECOND, GST_SECOND);
697 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
698 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
699 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
701 tbuf = create_text_buffer ("XLX", 3 * GST_SECOND, 2 * GST_SECOND);
702 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
703 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
704 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
706 tbuf = create_text_buffer ("XLX", 7 * GST_SECOND, GST_SECOND);
707 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
708 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
709 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
711 tbuf = create_text_buffer ("XLX", 8 * GST_SECOND, GST_SECOND);
712 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
713 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
714 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
716 tbuf = create_text_buffer ("XLX", 9 * GST_SECOND, GST_SECOND);
717 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
718 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
719 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
721 tbuf = create_text_buffer ("XLX", 10 * GST_SECOND, 30 * GST_SECOND);
722 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
723 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
724 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
726 GST_LOG ("give the other thread some time to push through the remaining"
728 g_usleep (G_USEC_PER_SEC);
731 /* we should have 15 buffers each with one second length now */
732 fail_unless_equals_int (g_list_length (buffers), 15);
734 outcaps = gst_pad_get_current_caps (mysinkpad);
736 /* buffers 0 + 1 should be black */
737 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers, 0)),
739 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers, 1)),
742 /* buffers 2 - 4 should have text */
743 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
744 2)), outcaps) == FALSE);
745 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
746 3)), outcaps) == FALSE);
747 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
748 4)), outcaps) == FALSE);
750 /* buffers 5 + 6 should be black */
751 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers, 5)),
753 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers, 6)),
756 /* buffers 7 - last should have text */
757 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
758 7)), outcaps) == FALSE);
759 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
760 8)), outcaps) == FALSE);
761 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
762 9)), outcaps) == FALSE);
763 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
764 10)), outcaps) == FALSE);
765 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
766 11)), outcaps) == FALSE);
767 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
768 12)), outcaps) == FALSE);
769 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
770 13)), outcaps) == FALSE);
771 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
772 14)), outcaps) == FALSE);
773 gst_caps_unref (outcaps);
776 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
777 g_list_free (buffers);
781 cleanup_textoverlay (textoverlay);
787 textoverlay_suite (void)
789 Suite *s = suite_create ("textoverlay");
790 TCase *tc_chain = tcase_create ("general");
792 suite_add_tcase (s, tc_chain);
794 tcase_add_test (tc_chain, test_video_passthrough);
795 tcase_add_test (tc_chain, test_video_render_static_text);
796 tcase_add_test (tc_chain, test_render_continuity);
797 tcase_add_test (tc_chain, test_video_waits_for_text);
802 GST_CHECK_MAIN (textoverlay);