1 /* GStreamer unit tests for textoverlay
2 *
3 * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
4 *
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.
9 *
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.
14 *
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., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <gst/check/gstcheck.h>
26 #include <gst/video/video-overlay-composition.h>
27
28 #define I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
29 #define I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
30 #define I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(I420_Y_ROWSTRIDE(width)))/2)
31
32 #define I420_Y_OFFSET(w,h) (0)
33 #define I420_U_OFFSET(w,h) (I420_Y_OFFSET(w,h)+(I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
34 #define I420_V_OFFSET(w,h) (I420_U_OFFSET(w,h)+(I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
35
36 #define I420_SIZE(w,h) (I420_V_OFFSET(w,h)+(I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
37
38 #define WIDTH 240
39 #define HEIGHT 120
40
41 /* For ease of programming we use globals to keep refs for our floating
42 * src and sink pads we create; otherwise we always have to do get_pad,
43 * get_peer, and then remove references in every test function */
44 static GstPad *myvideosrcpad, *mytextsrcpad, *mysinkpad;
45
46 #define VIDEO_CAPS_STRING \
47 "video/x-raw, " \
48 "format = (string) I420, " \
49 "framerate = (fraction) 1/1, " \
50 "width = (int) 240, " \
51 "height = (int) 120"
52
53 #define VIDEO_CAPS_TEMPLATE_STRING \
54 "video/x-raw, " \
55 "format = (string) I420"
56
57 #define VIDEO_CAPS_TEMPLATE_WITH_FEATURE_STRING \
58 "video/x-raw(" GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY ", " \
59 GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION "), " \
60 "format = (string) I420;" \
61 "video/x-raw, " \
62 "format = (string) I420;"
63
64 #define UNSUPPORTED_VIDEO_CAPS_STRING \
65 "video/x-raw(" GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META "), " \
66 "format = (string) I420, " \
67 "framerate = (fraction) 1/1, " \
68 "width = (int) 240, " \
69 "height = (int) 120"
70
71 #define UNSUPPORTED_VIDEO_CAPS_TEMPLATE_STRING \
72 "video/x-raw(" GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META "), " \
73 "format = (string) I420"
74
75 #define UNSUPPORTED_VIDEO_CAPS_TEMPLATE_WITH_FEATURE_STRING \
76 "video/x-raw(" GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META "," \
77 GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION "), " \
78 "format = (string) I420;" \
79 "video/x-raw(" GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META "), " \
80 "format = (string) I420"
81
82 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
83 GST_PAD_SINK,
84 GST_PAD_ALWAYS,
85 GST_STATIC_CAPS (VIDEO_CAPS_TEMPLATE_STRING)
86 );
87
88 static GstStaticPadTemplate sinktemplate_with_features =
89 GST_STATIC_PAD_TEMPLATE ("sink",
90 GST_PAD_SINK,
91 GST_PAD_ALWAYS,
92 GST_STATIC_CAPS (VIDEO_CAPS_TEMPLATE_WITH_FEATURE_STRING)
93 );
94
95 static GstStaticPadTemplate text_srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
96 GST_PAD_SRC,
97 GST_PAD_ALWAYS,
98 GST_STATIC_CAPS ("text/x-raw, format=utf8")
99 );
100
101 static GstStaticPadTemplate video_srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
102 GST_PAD_SRC,
103 GST_PAD_ALWAYS,
104 GST_STATIC_CAPS (VIDEO_CAPS_TEMPLATE_STRING)
105 );
106
107 static GstStaticPadTemplate unsupported_sinktemplate_with_features =
108 GST_STATIC_PAD_TEMPLATE ("sink",
109 GST_PAD_SINK,
110 GST_PAD_ALWAYS,
111 GST_STATIC_CAPS (UNSUPPORTED_VIDEO_CAPS_TEMPLATE_WITH_FEATURE_STRING)
112 );
113
114 static GstStaticPadTemplate sinktemplate_any = GST_STATIC_PAD_TEMPLATE ("sink",
115 GST_PAD_SINK,
116 GST_PAD_ALWAYS,
117 GST_STATIC_CAPS_ANY);
118
119 static GstStaticPadTemplate unsupported_video_srctemplate =
120 GST_STATIC_PAD_TEMPLATE ("src",
121 GST_PAD_SRC,
122 GST_PAD_ALWAYS,
123 GST_STATIC_CAPS (UNSUPPORTED_VIDEO_CAPS_TEMPLATE_STRING)
124 );
125
126 static void
gst_check_setup_events_textoverlay(GstPad * srcpad,GstElement * element,GstCaps * caps,GstFormat format,const gchar * stream_id)127 gst_check_setup_events_textoverlay (GstPad * srcpad, GstElement * element,
128 GstCaps * caps, GstFormat format, const gchar * stream_id)
129 {
130 GstSegment segment;
131
132 gst_segment_init (&segment, format);
133
134 fail_unless (gst_pad_push_event (srcpad,
135 gst_event_new_stream_start (stream_id)));
136 if (caps)
137 fail_unless (gst_pad_push_event (srcpad, gst_event_new_caps (caps)));
138 fail_unless (gst_pad_push_event (srcpad, gst_event_new_segment (&segment)));
139 }
140
141
142 static gboolean
sink_query_handler(GstPad * pad,GstObject * parent,GstQuery * query)143 sink_query_handler (GstPad * pad, GstObject * parent, GstQuery * query)
144 {
145 gboolean ret = FALSE;
146 GstQueryType type = GST_QUERY_TYPE (query);
147
148 switch (type) {
149 case GST_QUERY_ALLOCATION:{
150 gst_query_add_allocation_meta (query,
151 GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
152
153 ret = TRUE;
154
155 break;
156 }
157 default:{
158 ret = gst_pad_query_default (pad, parent, query);
159 break;
160 }
161 }
162 return ret;
163 }
164
165 /* much like gst_check_setup_src_pad(), but with possibility to give a hint
166 * which sink template of the element to use, if there are multiple ones */
167 static GstPad *
notgst_check_setup_src_pad2(GstElement * element,GstStaticPadTemplate * template,GstCaps * caps,const gchar * sink_template_name)168 notgst_check_setup_src_pad2 (GstElement * element,
169 GstStaticPadTemplate * template, GstCaps * caps,
170 const gchar * sink_template_name)
171 {
172 GstPad *srcpad, *sinkpad;
173
174 if (sink_template_name == NULL)
175 sink_template_name = "sink";
176
177 /* sending pad */
178 srcpad = gst_pad_new_from_static_template (template, "src");
179 GST_DEBUG_OBJECT (element, "setting up sending pad %p", srcpad);
180 fail_if (srcpad == NULL, "Could not create a srcpad");
181 ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1);
182
183 if (!(sinkpad = gst_element_get_static_pad (element, sink_template_name)))
184 sinkpad = gst_element_request_pad_simple (element, sink_template_name);
185 fail_if (sinkpad == NULL, "Could not get sink pad from %s",
186 GST_ELEMENT_NAME (element));
187 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
188 if (caps)
189 fail_unless (gst_pad_set_caps (srcpad, caps));
190 fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK,
191 "Could not link source and %s sink pads", GST_ELEMENT_NAME (element));
192 gst_object_unref (sinkpad); /* because we got it higher up */
193 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
194
195 return srcpad;
196 }
197
198 static void
notgst_check_teardown_src_pad2(GstElement * element,const gchar * sink_template_name)199 notgst_check_teardown_src_pad2 (GstElement * element,
200 const gchar * sink_template_name)
201 {
202 GstPad *srcpad, *sinkpad;
203
204 if (sink_template_name == NULL)
205 sink_template_name = "sink";
206
207 /* clean up floating src pad */
208 if (!(sinkpad = gst_element_get_static_pad (element, sink_template_name)))
209 sinkpad = gst_element_request_pad_simple (element, sink_template_name);
210 ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
211 srcpad = gst_pad_get_peer (sinkpad);
212
213 gst_pad_unlink (srcpad, sinkpad);
214
215 /* pad refs held by both creator and this function (through _get) */
216 ASSERT_OBJECT_REFCOUNT (sinkpad, "element sinkpad", 2);
217 gst_object_unref (sinkpad);
218 /* one more ref is held by element itself */
219
220 /* pad refs held by both creator and this function (through _get_peer) */
221 ASSERT_OBJECT_REFCOUNT (srcpad, "check srcpad", 2);
222 gst_object_unref (srcpad);
223 gst_object_unref (srcpad);
224 }
225
226 static GstElement *
setup_textoverlay_with_templates(GstStaticPadTemplate * srcpad_template,GstStaticPadTemplate * textpad_template,GstStaticPadTemplate * sinkpad_template,gboolean enable_allocation_query)227 setup_textoverlay_with_templates (GstStaticPadTemplate * srcpad_template,
228 GstStaticPadTemplate * textpad_template,
229 GstStaticPadTemplate * sinkpad_template, gboolean enable_allocation_query)
230 {
231 GstElement *textoverlay;
232
233 GST_DEBUG ("setup_textoverlay");
234 textoverlay = gst_check_setup_element ("textoverlay");
235 mysinkpad = gst_check_setup_sink_pad (textoverlay, sinkpad_template);
236
237 if (enable_allocation_query) {
238 GST_PAD_SET_PROXY_ALLOCATION (mysinkpad);
239 gst_pad_set_query_function (mysinkpad, sink_query_handler);
240 }
241
242 myvideosrcpad =
243 notgst_check_setup_src_pad2 (textoverlay, srcpad_template, NULL,
244 "video_sink");
245
246 if (textpad_template) {
247 mytextsrcpad =
248 notgst_check_setup_src_pad2 (textoverlay, textpad_template, NULL,
249 "text_sink");
250 gst_pad_set_active (mytextsrcpad, TRUE);
251 } else {
252 mytextsrcpad = NULL;
253 }
254
255 gst_pad_set_active (myvideosrcpad, TRUE);
256 gst_pad_set_active (mysinkpad, TRUE);
257
258 return textoverlay;
259 }
260
261 static GstElement *
setup_textoverlay(gboolean video_only_no_text)262 setup_textoverlay (gboolean video_only_no_text)
263 {
264 GstStaticPadTemplate *srcpad_template = NULL;
265 GstStaticPadTemplate *textpad_template = NULL;
266 GstStaticPadTemplate *sinkpad_template = NULL;
267
268 srcpad_template = &video_srctemplate;
269 if (!video_only_no_text)
270 textpad_template = &text_srctemplate;
271 sinkpad_template = &sinktemplate;
272
273 return setup_textoverlay_with_templates (srcpad_template,
274 textpad_template, sinkpad_template, FALSE);
275 }
276
277 static gboolean
buffer_is_all_black(GstBuffer * buf,GstCaps * caps)278 buffer_is_all_black (GstBuffer * buf, GstCaps * caps)
279 {
280 GstStructure *s;
281 gint x, y, w, h;
282 GstMapInfo map;
283
284 fail_unless (buf != NULL);
285 fail_unless (caps != NULL);
286 s = gst_caps_get_structure (caps, 0);
287 fail_unless (s != NULL);
288 fail_unless (gst_structure_get_int (s, "width", &w));
289 fail_unless (gst_structure_get_int (s, "height", &h));
290
291 gst_buffer_map (buf, &map, GST_MAP_READ);
292 for (y = 0; y < h; ++y) {
293 guint8 *ptr = map.data + (y * GST_ROUND_UP_4 (w));
294
295 for (x = 0; x < w; ++x) {
296 if (ptr[x] != 0x00) {
297 GST_LOG ("non-black pixel (%d) at (x,y) %d,%d", ptr[x], x, y);
298 gst_buffer_unmap (buf, &map);
299 return FALSE;
300 }
301 }
302 }
303 gst_buffer_unmap (buf, &map);
304
305 return TRUE;
306 }
307
308 static GstCaps *
create_video_caps(const gchar * caps_string)309 create_video_caps (const gchar * caps_string)
310 {
311 GstCaps *caps;
312
313 caps = gst_caps_from_string (caps_string);
314 fail_unless (caps != NULL);
315 fail_unless (gst_caps_is_fixed (caps));
316
317 return caps;
318 }
319
320 static GstBuffer *
create_black_buffer(GstCaps * caps)321 create_black_buffer (GstCaps * caps)
322 {
323 GstStructure *s;
324 GstBuffer *buffer;
325 gint w, h, size;
326
327 fail_unless (caps != NULL);
328
329 s = gst_caps_get_structure (caps, 0);
330 fail_unless (gst_structure_get_int (s, "width", &w));
331 fail_unless (gst_structure_get_int (s, "height", &h));
332
333 GST_LOG ("creating buffer (%dx%d)", w, h);
334
335 size = I420_SIZE (w, h);
336 buffer = gst_buffer_new_and_alloc (size);
337 /* we're only checking the Y plane later, so just zero it all out,
338 * even if it's not the blackest black there is */
339 gst_buffer_memset (buffer, 0, 0, size);
340
341 /* double check to make sure it's been created right */
342 fail_unless (buffer_is_all_black (buffer, caps));
343
344 return buffer;
345 }
346
347 static GstBuffer *
create_text_buffer(const gchar * txt,GstClockTime ts,GstClockTime duration)348 create_text_buffer (const gchar * txt, GstClockTime ts, GstClockTime duration)
349 {
350 GstBuffer *buffer;
351 guint txt_len;
352
353 fail_unless (txt != NULL);
354
355 txt_len = strlen (txt);
356
357 buffer = gst_buffer_new_and_alloc (txt_len);
358 gst_buffer_fill (buffer, 0, txt, txt_len);
359
360 GST_BUFFER_TIMESTAMP (buffer) = ts;
361 GST_BUFFER_DURATION (buffer) = duration;
362
363 return buffer;
364 }
365
366 static gboolean
_test_textoverlay_check_caps_has_feature(GstElement * textoverlay,const gchar * padname,const gchar * feature)367 _test_textoverlay_check_caps_has_feature (GstElement * textoverlay,
368 const gchar * padname, const gchar * feature)
369 {
370 GstPad *pad;
371 GstCaps *caps;
372 GstCapsFeatures *f;
373 gboolean ret;
374
375 pad = gst_element_get_static_pad (textoverlay, padname);
376 fail_unless (pad != NULL);
377
378 caps = gst_pad_get_current_caps (pad);
379 fail_unless (caps != NULL);
380
381 gst_object_unref (pad);
382
383 f = gst_caps_get_features (caps, 0);
384 if (f != NULL) {
385 ret = gst_caps_features_contains (f, feature);
386 } else {
387 ret = FALSE;
388 }
389
390 gst_caps_unref (caps);
391 return ret;
392 }
393
394 static void
cleanup_textoverlay(GstElement * textoverlay)395 cleanup_textoverlay (GstElement * textoverlay)
396 {
397 GST_DEBUG ("cleanup_textoverlay");
398
399 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
400 g_list_free (buffers);
401 buffers = NULL;
402
403 gst_element_set_state (textoverlay, GST_STATE_NULL);
404 gst_element_get_state (textoverlay, NULL, NULL, GST_CLOCK_TIME_NONE);
405 gst_pad_set_active (myvideosrcpad, FALSE);
406 gst_pad_set_active (mysinkpad, FALSE);
407 notgst_check_teardown_src_pad2 (textoverlay, "video_sink");
408 if (mytextsrcpad) {
409 notgst_check_teardown_src_pad2 (textoverlay, "text_sink");
410 }
411 gst_check_teardown_sink_pad (textoverlay);
412 gst_check_teardown_element (textoverlay);
413 }
414
GST_START_TEST(test_video_passthrough)415 GST_START_TEST (test_video_passthrough)
416 {
417 GstElement *textoverlay;
418 GstBuffer *inbuffer, *outbuffer;
419 GstCaps *incaps, *outcaps;
420 GstSegment segment;
421
422 textoverlay = setup_textoverlay (TRUE);
423 fail_unless (gst_element_set_state (textoverlay,
424 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
425 "could not set to playing");
426
427 incaps = create_video_caps (VIDEO_CAPS_STRING);
428 gst_check_setup_events_textoverlay (myvideosrcpad, textoverlay, incaps,
429 GST_FORMAT_TIME, "video");
430 inbuffer = create_black_buffer (incaps);
431 gst_caps_unref (incaps);
432
433 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
434
435 /* ========== (1) video buffer without timestamp => should be dropped ==== */
436
437 /* take additional ref to keep it alive */
438 gst_buffer_ref (inbuffer);
439 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
440
441 /* pushing gives away one of the two references we have ... */
442 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
443
444 /* should have been discarded as out-of-segment since it has no timestamp */
445 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
446 fail_unless_equals_int (g_list_length (buffers), 0);
447
448 /* ========== (2) buffer with 0 timestamp => simple passthrough ========== */
449
450 /* now try again, this time with timestamp (segment defaults to 0 start) */
451 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
452 GST_BUFFER_DURATION (inbuffer) = GST_CLOCK_TIME_NONE;
453
454 /* take additional ref to keep it alive */
455 gst_buffer_ref (inbuffer);
456 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
457
458 /* pushing gives away one of the two references we have ... */
459 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
460
461 /* text pad is not linked, timestamp is in segment, no static text to
462 * render, should have gone through right away without modification */
463 fail_unless_equals_int (g_list_length (buffers), 1);
464 outbuffer = GST_BUFFER_CAST (buffers->data);
465 fail_unless (outbuffer == inbuffer);
466 outcaps = gst_pad_get_current_caps (mysinkpad);
467 fail_unless (buffer_is_all_black (outbuffer, outcaps));
468 gst_caps_unref (outcaps);
469 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
470
471 /* and clean up */
472 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
473 g_list_free (buffers);
474 buffers = NULL;
475 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
476
477 /* ========== (3) buffer with 0 timestamp and no duration, with the
478 * segment starting from 1sec => should be discarded */
479
480 gst_segment_init (&segment, GST_FORMAT_TIME);
481 segment.start = 1 * GST_SECOND;
482 segment.stop = -1;
483 segment.time = 0;
484 gst_pad_push_event (myvideosrcpad, gst_event_new_segment (&segment));
485
486 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
487 GST_BUFFER_DURATION (inbuffer) = GST_CLOCK_TIME_NONE;
488
489 /* take additional ref to keep it alive */
490 gst_buffer_ref (inbuffer);
491 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
492
493 /* pushing gives away one of the two references we have ... */
494 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
495
496 /* should have been discarded as out-of-segment */
497 fail_unless_equals_int (g_list_length (buffers), 0);
498 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
499
500 /* ========== (4) buffer with 0 timestamp and small defined duration, with
501 * segment starting from 1sec => should be discarded */
502
503 gst_pad_push_event (myvideosrcpad, gst_event_new_segment (&segment));
504
505 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 10;
506
507 /* take additional ref to keep it alive */
508 gst_buffer_ref (inbuffer);
509 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
510
511 /* pushing gives away one of the two references we have ... */
512 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
513
514 /* should have been discarded as out-of-segment since it has no timestamp */
515 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
516 fail_unless_equals_int (g_list_length (buffers), 0);
517
518 /* ========== (5) buffer partially overlapping into the segment => should
519 * be pushed through, but with adjusted stamp values */
520
521 gst_pad_push_event (myvideosrcpad, gst_event_new_segment (&segment));
522
523 GST_BUFFER_TIMESTAMP (inbuffer) = GST_SECOND / 4;
524 GST_BUFFER_DURATION (inbuffer) = GST_SECOND;
525
526 /* take additional ref to keep it alive */
527 gst_buffer_ref (inbuffer);
528 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
529
530 /* pushing gives away one of the two references we have ... */
531 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
532
533 /* should be a new buffer for the stamp fix-up */
534 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
535 fail_unless_equals_int (g_list_length (buffers), 1);
536 outbuffer = GST_BUFFER_CAST (buffers->data);
537 outcaps = gst_pad_get_current_caps (mysinkpad);
538 fail_unless (outbuffer != inbuffer);
539 fail_unless (GST_BUFFER_TIMESTAMP (outbuffer) == GST_SECOND);
540 fail_unless (GST_BUFFER_DURATION (outbuffer) == (GST_SECOND / 4));
541 fail_unless (buffer_is_all_black (outbuffer, outcaps));
542 gst_caps_unref (outcaps);
543 /* and clean up */
544 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
545 g_list_free (buffers);
546 buffers = NULL;
547 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
548
549 /* cleanup */
550 cleanup_textoverlay (textoverlay);
551 gst_buffer_unref (inbuffer);
552 }
553
554 GST_END_TEST;
555
GST_START_TEST(test_video_passthrough_with_feature)556 GST_START_TEST (test_video_passthrough_with_feature)
557 {
558 GstElement *textoverlay;
559 GstBuffer *inbuffer, *outbuffer;
560 GstCaps *incaps, *outcaps;
561 GstVideoOverlayCompositionMeta *comp_meta;
562
563 textoverlay = setup_textoverlay_with_templates (&video_srctemplate,
564 NULL, &sinktemplate_with_features, TRUE);
565
566 /* set static text to render */
567 g_object_set (textoverlay, "text", "XLX", NULL);
568
569 fail_unless (gst_element_set_state (textoverlay,
570 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
571 "could not set to playing");
572
573 incaps = create_video_caps (VIDEO_CAPS_STRING);
574 gst_check_setup_events_textoverlay (myvideosrcpad, textoverlay, incaps,
575 GST_FORMAT_TIME, "video");
576 inbuffer = create_black_buffer (incaps);
577 gst_caps_unref (incaps);
578 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
579
580 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
581 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 10;
582
583 /* take additional ref to keep it alive */
584 gst_buffer_ref (inbuffer);
585 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
586
587 /* pushing gives away one of the two references we have ... */
588 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
589
590 /* should have been dropped in favour of a new writable buffer */
591 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
592 fail_unless_equals_int (g_list_length (buffers), 1);
593 outbuffer = GST_BUFFER_CAST (buffers->data);
594 outcaps = gst_pad_get_current_caps (mysinkpad);
595 fail_unless (outbuffer != inbuffer);
596
597 /* output buffer should be black */
598 fail_unless (buffer_is_all_black (outbuffer, outcaps) == TRUE);
599 gst_caps_unref (outcaps);
600
601 /* output buffer should have the composition meta */
602 comp_meta = gst_buffer_get_video_overlay_composition_meta (outbuffer);
603 fail_unless (comp_meta != NULL);
604
605 fail_unless (GST_BUFFER_TIMESTAMP (outbuffer) == 0);
606 fail_unless (GST_BUFFER_DURATION (outbuffer) == (GST_SECOND / 10));
607
608 /* and clean up */
609 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
610 g_list_free (buffers);
611 buffers = NULL;
612 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
613
614 /* cleanup */
615 cleanup_textoverlay (textoverlay);
616 gst_buffer_unref (inbuffer);
617 }
618
619 GST_END_TEST;
620
GST_START_TEST(test_video_passthrough_with_feature_and_unsupported_caps)621 GST_START_TEST (test_video_passthrough_with_feature_and_unsupported_caps)
622 {
623 GstElement *textoverlay;
624 GstBuffer *inbuffer, *outbuffer;
625 GstCaps *incaps, *outcaps;
626 GstVideoOverlayCompositionMeta *comp_meta;
627
628 textoverlay =
629 setup_textoverlay_with_templates (&unsupported_video_srctemplate, NULL,
630 &unsupported_sinktemplate_with_features, TRUE);
631
632 /* set static text to render */
633 g_object_set (textoverlay, "text", "XLX", NULL);
634
635 fail_unless (gst_element_set_state (textoverlay,
636 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
637 "could not set to playing");
638
639 incaps = create_video_caps (UNSUPPORTED_VIDEO_CAPS_STRING);
640 gst_check_setup_events_textoverlay (myvideosrcpad, textoverlay, incaps,
641 GST_FORMAT_TIME, "video");
642 inbuffer = create_black_buffer (incaps);
643 gst_caps_unref (incaps);
644 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
645
646 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
647 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 10;
648
649 /* take additional ref to keep it alive */
650 gst_buffer_ref (inbuffer);
651 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
652
653 /* pushing gives away one of the two references we have ... */
654 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
655
656 /* should have been dropped in favour of a new writable buffer */
657 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
658 fail_unless_equals_int (g_list_length (buffers), 1);
659 outbuffer = GST_BUFFER_CAST (buffers->data);
660 outcaps = gst_pad_get_current_caps (mysinkpad);
661 fail_unless (outbuffer != inbuffer);
662
663 /* output buffer should be black */
664 fail_unless (buffer_is_all_black (outbuffer, outcaps) == TRUE);
665 gst_caps_unref (outcaps);
666
667 /* output buffer should have the composition meta */
668 comp_meta = gst_buffer_get_video_overlay_composition_meta (outbuffer);
669 fail_unless (comp_meta != NULL);
670
671 fail_unless (GST_BUFFER_TIMESTAMP (outbuffer) == 0);
672 fail_unless (GST_BUFFER_DURATION (outbuffer) == (GST_SECOND / 10));
673
674 /* and clean up */
675 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
676 g_list_free (buffers);
677 buffers = NULL;
678 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
679
680 /* cleanup */
681 cleanup_textoverlay (textoverlay);
682 gst_buffer_unref (inbuffer);
683 }
684
685 GST_END_TEST;
686
687
GST_START_TEST(test_video_render_with_any_features_and_no_allocation_meta)688 GST_START_TEST (test_video_render_with_any_features_and_no_allocation_meta)
689 {
690 GstElement *textoverlay;
691 GstBuffer *inbuffer, *outbuffer;
692 GstCaps *incaps, *outcaps;
693 GstVideoOverlayCompositionMeta *comp_meta;
694
695 textoverlay =
696 setup_textoverlay_with_templates (&video_srctemplate,
697 NULL, &sinktemplate_any, FALSE);
698
699 /* set static text to render */
700 g_object_set (textoverlay, "text", "XLX", NULL);
701
702 fail_unless (gst_element_set_state (textoverlay,
703 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
704 "could not set to playing");
705
706 incaps = create_video_caps (VIDEO_CAPS_STRING);
707 gst_check_setup_events_textoverlay (myvideosrcpad, textoverlay, incaps,
708 GST_FORMAT_TIME, "video");
709 inbuffer = create_black_buffer (incaps);
710 gst_caps_unref (incaps);
711 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
712
713 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
714 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 10;
715
716 /* take additional ref to keep it alive */
717 gst_buffer_ref (inbuffer);
718 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
719
720 /* pushing gives away one of the two references we have ... */
721 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
722
723 /* should have been dropped in favour of a new writable buffer */
724 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
725 fail_unless_equals_int (g_list_length (buffers), 1);
726 outbuffer = GST_BUFFER_CAST (buffers->data);
727 outcaps = gst_pad_get_current_caps (mysinkpad);
728 fail_unless (outbuffer != inbuffer);
729
730 /* output buffer should have rendered text */
731 fail_if (buffer_is_all_black (outbuffer, outcaps));
732 gst_caps_unref (outcaps);
733
734 /* output buffer should not have the composition meta */
735 comp_meta = gst_buffer_get_video_overlay_composition_meta (outbuffer);
736 fail_unless (comp_meta == NULL);
737
738 fail_unless (GST_BUFFER_TIMESTAMP (outbuffer) == 0);
739 fail_unless (GST_BUFFER_DURATION (outbuffer) == (GST_SECOND / 10));
740
741 /* output caps shouldn't have the composition meta */
742 fail_if (_test_textoverlay_check_caps_has_feature (textoverlay, "src",
743 GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION));
744
745 /* and clean up */
746 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
747 g_list_free (buffers);
748 buffers = NULL;
749 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
750
751 /* cleanup */
752 cleanup_textoverlay (textoverlay);
753 gst_buffer_unref (inbuffer);
754 }
755
756 GST_END_TEST;
757
758
GST_START_TEST(test_video_render_static_text)759 GST_START_TEST (test_video_render_static_text)
760 {
761 GstElement *textoverlay;
762 GstBuffer *inbuffer, *outbuffer;
763 GstCaps *incaps, *outcaps;
764
765 textoverlay = setup_textoverlay (TRUE);
766
767 /* set static text to render */
768 g_object_set (textoverlay, "text", "XLX", NULL);
769
770 fail_unless (gst_element_set_state (textoverlay,
771 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
772 "could not set to playing");
773
774 incaps = create_video_caps (VIDEO_CAPS_STRING);
775 gst_check_setup_events_textoverlay (myvideosrcpad, textoverlay, incaps,
776 GST_FORMAT_TIME, "video");
777 inbuffer = create_black_buffer (incaps);
778 gst_caps_unref (incaps);
779 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
780
781 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
782 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 10;
783
784 /* take additional ref to keep it alive */
785 gst_buffer_ref (inbuffer);
786 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
787
788 /* pushing gives away one of the two references we have ... */
789 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
790
791 /* should have been dropped in favour of a new writable buffer */
792 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
793 fail_unless_equals_int (g_list_length (buffers), 1);
794 outbuffer = GST_BUFFER_CAST (buffers->data);
795 outcaps = gst_pad_get_current_caps (mysinkpad);
796 fail_unless (outbuffer != inbuffer);
797
798 /* there should be text rendered */
799 fail_unless (buffer_is_all_black (outbuffer, outcaps) == FALSE);
800 gst_caps_unref (outcaps);
801
802 fail_unless (GST_BUFFER_TIMESTAMP (outbuffer) == 0);
803 fail_unless (GST_BUFFER_DURATION (outbuffer) == (GST_SECOND / 10));
804
805 /* and clean up */
806 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
807 g_list_free (buffers);
808 buffers = NULL;
809 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
810
811 /* cleanup */
812 cleanup_textoverlay (textoverlay);
813 gst_buffer_unref (inbuffer);
814 }
815
816 GST_END_TEST;
817
818 static gpointer
test_video_waits_for_text_send_text_newsegment_thread(gpointer data)819 test_video_waits_for_text_send_text_newsegment_thread (gpointer data)
820 {
821 GstSegment segment;
822
823 g_usleep (1 * G_USEC_PER_SEC);
824
825 /* send an update newsegment; the video buffer should now be pushed through
826 * even though there is no text buffer queued at the moment */
827 GST_INFO ("Sending newsegment update on text pad");
828 gst_segment_init (&segment, GST_FORMAT_TIME);
829 segment.base = 35 * GST_SECOND;
830 segment.start = 35 * GST_SECOND;
831 segment.time = 35 * GST_SECOND;
832 gst_pad_push_event (mytextsrcpad, gst_event_new_segment (&segment));
833
834 return NULL;
835 }
836
837 static gpointer
test_video_waits_for_text_shutdown_element(gpointer data)838 test_video_waits_for_text_shutdown_element (gpointer data)
839 {
840 g_usleep (1 * G_USEC_PER_SEC);
841
842 GST_INFO ("Trying to shut down textoverlay element ...");
843 /* set to NULL state to make sure we can shut it down while it's
844 * blocking in the video chain function waiting for a text buffer */
845 gst_element_set_state (GST_ELEMENT (data), GST_STATE_NULL);
846 GST_INFO ("Done.");
847
848 return NULL;
849 }
850
GST_START_TEST(test_video_waits_for_text)851 GST_START_TEST (test_video_waits_for_text)
852 {
853 GstElement *textoverlay;
854 GstBuffer *inbuffer, *outbuffer, *tbuf;
855 GstCaps *caps, *incaps, *outcaps;
856 GThread *thread;
857
858 textoverlay = setup_textoverlay (FALSE);
859
860 fail_unless (gst_element_set_state (textoverlay,
861 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
862 "could not set to playing");
863
864 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, "utf8",
865 NULL);
866 gst_check_setup_events_textoverlay (mytextsrcpad, textoverlay, caps,
867 GST_FORMAT_TIME, "text");
868 gst_caps_unref (caps);
869
870 tbuf = create_text_buffer ("XLX", 1 * GST_SECOND, 5 * GST_SECOND);
871 gst_buffer_ref (tbuf);
872 ASSERT_BUFFER_REFCOUNT (tbuf, "tbuf", 2);
873
874 GST_LOG ("pushing text buffer");
875 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
876
877 /* it should be stuck in textoverlay until it gets a text buffer or a
878 * newsegment event that indicates it's not needed any longer */
879 fail_unless_equals_int (g_list_length (buffers), 0);
880
881 incaps = create_video_caps (VIDEO_CAPS_STRING);
882 gst_check_setup_events_textoverlay (myvideosrcpad, textoverlay, incaps,
883 GST_FORMAT_TIME, "video");
884 inbuffer = create_black_buffer (incaps);
885 gst_caps_unref (incaps);
886 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
887
888 GST_BUFFER_TIMESTAMP (inbuffer) = 0;
889 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 2;
890
891 /* pushing gives away one of the two references we have ... */
892 GST_LOG ("pushing video buffer 1");
893 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
894
895 /* video buffer should have gone through untainted, since the text is later */
896 fail_unless_equals_int (g_list_length (buffers), 1);
897
898 /* text should still be stuck in textoverlay */
899 ASSERT_MINI_OBJECT_REFCOUNT (gst_buffer_peek_memory (tbuf, 0), "tbuf-mem", 2);
900
901 /* there should be no text rendered */
902 outbuffer = GST_BUFFER_CAST (buffers->data);
903 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
904 outcaps = gst_pad_get_current_caps (mysinkpad);
905 fail_unless (buffer_is_all_black (outbuffer, outcaps));
906 gst_caps_unref (outcaps);
907
908 /* now, another video buffer */
909 inbuffer = create_black_buffer (incaps);
910 GST_BUFFER_TIMESTAMP (inbuffer) = GST_SECOND;
911 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 2;
912 ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
913
914 /* pushing gives away one of the two references we have ... */
915 GST_LOG ("pushing video buffer 2");
916 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
917
918 /* video buffer should have gone right away, with text rendered on it */
919 fail_unless_equals_int (g_list_length (buffers), 2);
920
921 /* text should still be stuck in textoverlay */
922 ASSERT_MINI_OBJECT_REFCOUNT (gst_buffer_peek_memory (tbuf, 0), "tbuf-mem", 2);
923
924 /* there should be text rendered */
925 outbuffer = GST_BUFFER_CAST (buffers->next->data);
926 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
927 outcaps = gst_pad_get_current_caps (mysinkpad);
928 fail_unless (buffer_is_all_black (outbuffer, outcaps) == FALSE);
929 gst_caps_unref (outcaps);
930
931 /* a third video buffer */
932 inbuffer = create_black_buffer (incaps);
933 GST_BUFFER_TIMESTAMP (inbuffer) = 30 * GST_SECOND;
934 GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 2;
935
936 /* video buffer #3: should not go through, it should discard the current
937 * text buffer as too old and then wait for the next text buffer (or a
938 * newsegment event to arrive); we spawn a background thread to send such
939 * a newsegment event after a second or so so we get back control */
940 thread =
941 g_thread_try_new ("gst-check",
942 test_video_waits_for_text_send_text_newsegment_thread, NULL, NULL);
943 fail_unless (thread != NULL);
944 g_thread_unref (thread);
945
946 GST_LOG ("pushing video buffer 3");
947 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
948
949 /* but the text should no longer be stuck in textoverlay */
950 ASSERT_MINI_OBJECT_REFCOUNT (gst_buffer_peek_memory (tbuf, 0), "tbuf-mem", 1);
951
952 /* video buffer should have gone through after newsegment event */
953 fail_unless_equals_int (g_list_length (buffers), 3);
954
955 /* ... and there should not be any text rendered on it */
956 outbuffer = GST_BUFFER_CAST (buffers->next->next->data);
957 ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
958 outcaps = gst_pad_get_current_caps (mysinkpad);
959 fail_unless (buffer_is_all_black (outbuffer, outcaps));
960 gst_caps_unref (outcaps);
961
962 /* a fourth video buffer */
963 inbuffer = create_black_buffer (incaps);
964 GST_BUFFER_TIMESTAMP (inbuffer) = 35 * GST_SECOND;
965 GST_BUFFER_DURATION (inbuffer) = GST_SECOND;
966
967 /* video buffer #4: should not go through, it should wait for the next
968 * text buffer (or a newsegment event) to arrive; we spawn a background
969 * thread to shut down the element while it's waiting to make sure that
970 * works ok */
971 thread = g_thread_try_new ("gst-check",
972 test_video_waits_for_text_shutdown_element, textoverlay, NULL);
973 fail_unless (thread != NULL);
974 g_thread_unref (thread);
975
976 GST_LOG ("pushing video buffer 4");
977 fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_FLUSHING);
978
979 /* and clean up */
980 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
981 g_list_free (buffers);
982 buffers = NULL;
983
984 /* cleanup */
985 cleanup_textoverlay (textoverlay);
986
987 /* give up our ref, textoverlay should've cleared its queued buffer by now */
988 ASSERT_BUFFER_REFCOUNT (tbuf, "tbuf", 1);
989 gst_buffer_unref (tbuf);
990 }
991
992 GST_END_TEST;
993
994 static gpointer
test_render_continuity_push_video_buffers_thread(gpointer data)995 test_render_continuity_push_video_buffers_thread (gpointer data)
996 {
997 /* push video buffers at 1fps */
998 guint frame_count = 0;
999 GstCaps *vcaps;
1000
1001 vcaps = create_video_caps (VIDEO_CAPS_STRING);
1002 gst_check_setup_events_textoverlay (myvideosrcpad, data, vcaps,
1003 GST_FORMAT_TIME, "video");
1004
1005 do {
1006 GstBuffer *vbuf;
1007
1008 vbuf = create_black_buffer (vcaps);
1009 ASSERT_BUFFER_REFCOUNT (vbuf, "vbuf", 1);
1010
1011 GST_BUFFER_TIMESTAMP (vbuf) = frame_count * GST_SECOND;
1012 GST_BUFFER_DURATION (vbuf) = GST_SECOND;
1013
1014 /* pushing gives away one of the two references we have ... */
1015 GST_LOG ("pushing video buffer %u @ %" GST_TIME_FORMAT, frame_count,
1016 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (vbuf)));
1017 fail_unless (gst_pad_push (myvideosrcpad, vbuf) == GST_FLOW_OK);
1018
1019 ++frame_count;
1020 } while (frame_count < 15);
1021
1022 gst_caps_unref (vcaps);
1023
1024 return NULL;
1025 }
1026
GST_START_TEST(test_render_continuity)1027 GST_START_TEST (test_render_continuity)
1028 {
1029 GThread *thread;
1030 GstElement *textoverlay;
1031 GstBuffer *tbuf;
1032 GstCaps *caps, *outcaps;
1033
1034 textoverlay = setup_textoverlay (FALSE);
1035
1036 fail_unless (gst_element_set_state (textoverlay,
1037 GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
1038 "could not set to playing");
1039
1040 thread = g_thread_try_new ("gst-check",
1041 test_render_continuity_push_video_buffers_thread, textoverlay, NULL);
1042 fail_unless (thread != NULL);
1043 g_thread_unref (thread);
1044
1045 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, "utf8",
1046 NULL);
1047 gst_check_setup_events_textoverlay (mytextsrcpad, textoverlay, caps,
1048 GST_FORMAT_TIME, "text");
1049 gst_caps_unref (caps);
1050
1051 tbuf = create_text_buffer ("XLX", 2 * GST_SECOND, GST_SECOND);
1052 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
1053 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
1054 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
1055
1056 tbuf = create_text_buffer ("XLX", 3 * GST_SECOND, 2 * GST_SECOND);
1057 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
1058 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
1059 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
1060
1061 tbuf = create_text_buffer ("XLX", 7 * GST_SECOND, GST_SECOND);
1062 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
1063 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
1064 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
1065
1066 tbuf = create_text_buffer ("XLX", 8 * GST_SECOND, GST_SECOND);
1067 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
1068 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
1069 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
1070
1071 tbuf = create_text_buffer ("XLX", 9 * GST_SECOND, GST_SECOND);
1072 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
1073 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
1074 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
1075
1076 tbuf = create_text_buffer ("XLX", 10 * GST_SECOND, 30 * GST_SECOND);
1077 GST_LOG ("pushing text buffer @ %" GST_TIME_FORMAT,
1078 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (tbuf)));
1079 fail_unless (gst_pad_push (mytextsrcpad, tbuf) == GST_FLOW_OK);
1080
1081 GST_LOG ("give the other thread some time to push through the remaining"
1082 "video buffers");
1083 g_usleep (G_USEC_PER_SEC);
1084 GST_LOG ("done");
1085
1086 /* we should have 15 buffers each with one second length now */
1087 fail_unless_equals_int (g_list_length (buffers), 15);
1088
1089 outcaps = gst_pad_get_current_caps (mysinkpad);
1090
1091 /* buffers 0 + 1 should be black */
1092 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers, 0)),
1093 outcaps));
1094 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers, 1)),
1095 outcaps));
1096
1097 /* buffers 2 - 4 should have text */
1098 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
1099 2)), outcaps) == FALSE);
1100 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
1101 3)), outcaps) == FALSE);
1102 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
1103 4)), outcaps) == FALSE);
1104
1105 /* buffers 5 + 6 should be black */
1106 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers, 5)),
1107 outcaps));
1108 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers, 6)),
1109 outcaps));
1110
1111 /* buffers 7 - last should have text */
1112 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
1113 7)), outcaps) == FALSE);
1114 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
1115 8)), outcaps) == FALSE);
1116 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
1117 9)), outcaps) == FALSE);
1118 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
1119 10)), outcaps) == FALSE);
1120 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
1121 11)), outcaps) == FALSE);
1122 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
1123 12)), outcaps) == FALSE);
1124 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
1125 13)), outcaps) == FALSE);
1126 fail_unless (buffer_is_all_black (GST_BUFFER (g_list_nth_data (buffers,
1127 14)), outcaps) == FALSE);
1128 gst_caps_unref (outcaps);
1129
1130 /* and clean up */
1131 g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
1132 g_list_free (buffers);
1133 buffers = NULL;
1134
1135 /* cleanup */
1136 cleanup_textoverlay (textoverlay);
1137 }
1138
1139 GST_END_TEST;
1140
1141 static Suite *
textoverlay_suite(void)1142 textoverlay_suite (void)
1143 {
1144 Suite *s = suite_create ("textoverlay");
1145 TCase *tc_chain = tcase_create ("general");
1146
1147 suite_add_tcase (s, tc_chain);
1148
1149 tcase_add_test (tc_chain, test_video_passthrough);
1150 tcase_add_test (tc_chain, test_video_passthrough_with_feature);
1151 tcase_add_test (tc_chain,
1152 test_video_passthrough_with_feature_and_unsupported_caps);
1153 tcase_add_test (tc_chain,
1154 test_video_render_with_any_features_and_no_allocation_meta);
1155 tcase_add_test (tc_chain, test_video_render_static_text);
1156 tcase_add_test (tc_chain, test_render_continuity);
1157 tcase_add_test (tc_chain, test_video_waits_for_text);
1158
1159 return s;
1160 }
1161
1162 GST_CHECK_MAIN (textoverlay);
1163