3 * Copyright (C) 2009, Axis Communications AB, LUND, SWEDEN
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., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
21 #include <gst/check/gstcheck.h>
22 #include <gst/app/gstappsink.h>
26 static GstPad *mysrcpad;
28 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
31 GST_STATIC_CAPS ("application/x-gst-check")
40 GST_DEBUG ("setup_appsink");
41 appsink = gst_check_setup_element ("appsink");
42 mysrcpad = gst_check_setup_src_pad (appsink, &srctemplate);
43 gst_pad_set_active (mysrcpad, TRUE);
45 caps = gst_caps_new_empty_simple ("application/x-gst-check");
46 gst_check_setup_events (mysrcpad, appsink, caps, GST_FORMAT_TIME);
47 gst_caps_unref (caps);
53 cleanup_appsink (GstElement * appsink)
55 GST_DEBUG ("cleanup_appsink");
57 gst_check_teardown_src_pad (appsink);
58 gst_check_teardown_element (appsink);
61 /* This function does an operation to it's indata argument and returns it.
62 * The exact operation performed doesn't matter. Currently it multiplies with
63 * two, but it could do anything. The idea is to use the function to verify
64 * that the code calling it gets run. */
66 operate_on_data (gint indata)
72 callback_function (GstAppSink * appsink, gpointer callback_data)
74 global_testdata = operate_on_data (*((gint *) callback_data));
80 notify_function (gpointer callback_data)
82 global_testdata = operate_on_data (*((gint *) callback_data));
85 GST_START_TEST (test_non_clients)
90 sink = setup_appsink ();
92 ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
94 buffer = gst_buffer_new_and_alloc (4);
95 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
97 GST_DEBUG ("cleaning up appsink");
98 ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
99 cleanup_appsink (sink);
104 /* Verifies that the handoff callback gets run one time when passing a buffer */
105 GST_START_TEST (test_handoff_callback)
110 GstAppSinkCallbacks callbacks = { NULL };
112 sink = setup_appsink ();
115 testdata = 5; /* Arbitrary value */
117 callbacks.new_sample = callback_function;
119 gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks, &testdata, NULL);
121 ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
123 buffer = gst_buffer_new_and_alloc (4);
124 /* Pushing a buffer should run our callback */
125 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
127 testdata = operate_on_data (testdata);
129 /* If both test_data & global_testdata have been operated on, we're happy. */
130 fail_unless (testdata == global_testdata);
132 GST_DEBUG ("cleaning up appsink");
133 ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
134 cleanup_appsink (sink);
139 /* Verifies that the notify function gets executed when the sink is destroyed */
140 GST_START_TEST (test_notify0)
144 GstAppSinkCallbacks callbacks = { NULL };
146 sink = gst_element_factory_make ("appsink", NULL);
149 testdata = 17; /* Arbitrary value */
151 gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks,
152 &testdata, (*notify_function));
154 GST_DEBUG ("cleaning up appsink");
155 /* Destroying sink should call our notify_function */
156 gst_object_unref (sink);
158 testdata = operate_on_data (testdata);
160 /* If both test_data & global_testdata have been operated on, we're happy. */
161 fail_unless (testdata == global_testdata);
167 /* Verifies that the notify function gets executed when
168 * gst_app_sink_set_callbacks () gets called */
169 GST_START_TEST (test_notify1)
173 GstAppSinkCallbacks callbacks = { NULL };
175 sink = gst_element_factory_make ("appsink", NULL);
178 testdata = 42; /* Arbitrary value */
180 gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks,
181 &testdata, (*notify_function));
182 /* Setting new callbacks should trigger the destroy of the old data */
183 gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks, &testdata, NULL);
185 testdata = operate_on_data (testdata);
187 /* If both test_data & global_testdata have been operated on, we're happy. */
188 fail_unless (testdata == global_testdata);
190 GST_DEBUG ("cleaning up appsink");
191 gst_object_unref (sink);
196 static const gint values[] = { 1, 2, 4 };
198 static GstBufferList *
199 create_buffer_list (void)
203 GstBufferList *mylist;
205 mylist = gst_buffer_list_new ();
206 fail_if (mylist == NULL);
208 len = gst_buffer_list_length (mylist);
211 buffer = gst_buffer_new_and_alloc (sizeof (gint));
212 gst_buffer_fill (buffer, 0, &values[0], sizeof (gint));
213 gst_buffer_list_add (mylist, buffer);
215 buffer = gst_buffer_new_and_alloc (sizeof (gint));
216 gst_buffer_fill (buffer, 0, &values[1], sizeof (gint));
217 gst_buffer_list_add (mylist, buffer);
219 buffer = gst_buffer_new_and_alloc (sizeof (gint));
220 gst_buffer_fill (buffer, 0, &values[2], sizeof (gint));
221 gst_buffer_list_add (mylist, buffer);
227 callback_function_sample_fallback (GstAppSink * appsink, gpointer p_counter)
231 gint *p_int_counter = p_counter;
233 sample = gst_app_sink_pull_sample (appsink);
234 buf = gst_sample_get_buffer (sample);
235 fail_unless (GST_IS_BUFFER (buf));
237 /* buffer list has 3 buffers in two groups */
238 switch (*p_int_counter) {
240 fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
241 gst_check_buffer_data (buf, &values[0], sizeof (gint));
244 fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
245 gst_check_buffer_data (buf, &values[1], sizeof (gint));
248 fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
249 gst_check_buffer_data (buf, &values[2], sizeof (gint));
252 g_warn_if_reached ();
256 gst_sample_unref (sample);
264 callback_function_sample (GstAppSink * appsink, gpointer p_counter)
268 gint *p_int_counter = p_counter;
272 sample = gst_app_sink_pull_sample (appsink);
273 list = gst_sample_get_buffer_list (sample);
274 fail_unless (GST_IS_BUFFER_LIST (list));
275 len = gst_buffer_list_length (list);
276 fail_unless_equals_int (len, 3);
278 for (i = 0; i < len; i++) {
279 GstBuffer *buf = gst_buffer_list_get (list, i);
280 fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
281 gst_check_buffer_data (buf, &values[i], sizeof (gint));
284 gst_sample_unref (sample);
291 GST_START_TEST (test_buffer_list_fallback)
295 GstAppSinkCallbacks callbacks = { NULL };
297 gboolean buffer_list_support;
299 sink = setup_appsink ();
301 /* verify that the buffer list support is disabled per default */
302 g_object_get (sink, "buffer-list", &buffer_list_support, NULL);
303 fail_unless (buffer_list_support == FALSE);
306 callbacks.new_sample = callback_function_sample_fallback;
308 gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks, &counter, NULL);
310 ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
312 list = create_buffer_list ();
313 fail_unless (gst_pad_push_list (mysrcpad, list) == GST_FLOW_OK);
315 fail_unless_equals_int (counter, 3);
317 ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
318 cleanup_appsink (sink);
323 GST_START_TEST (test_buffer_list_support)
327 GstAppSinkCallbacks callbacks = { NULL };
330 sink = setup_appsink ();
332 /* enable buffer list support */
333 g_object_set (sink, "buffer-list", TRUE, NULL);
335 callbacks.new_sample = callback_function_sample;
337 gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks, &counter, NULL);
339 ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
341 list = create_buffer_list ();
342 fail_unless (gst_pad_push_list (mysrcpad, list) == GST_FLOW_OK);
344 fail_unless_equals_int (counter, 1);
346 ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
347 cleanup_appsink (sink);
352 GST_START_TEST (test_buffer_list_fallback_signal)
358 sink = setup_appsink ();
360 /* C calling convention to the rescue.. */
361 g_signal_connect (sink, "new-sample",
362 G_CALLBACK (callback_function_sample_fallback), &counter);
364 g_object_set (sink, "emit-signals", TRUE, NULL);
366 ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
368 list = create_buffer_list ();
369 fail_unless (gst_pad_push_list (mysrcpad, list) == GST_FLOW_OK);
371 fail_unless_equals_int (counter, 3);
373 ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
374 cleanup_appsink (sink);
379 GST_START_TEST (test_buffer_list_signal)
385 sink = setup_appsink ();
387 /* enable buffer list support */
388 g_object_set (sink, "buffer-list", TRUE, NULL);
390 /* C calling convention to the rescue.. */
391 g_signal_connect (sink, "new-sample", G_CALLBACK (callback_function_sample),
394 g_object_set (sink, "emit-signals", TRUE, NULL);
396 ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
398 list = create_buffer_list ();
399 fail_unless (gst_pad_push_list (mysrcpad, list) == GST_FLOW_OK);
401 fail_unless_equals_int (counter, 1);
403 ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
404 cleanup_appsink (sink);
409 GST_START_TEST (test_segment)
414 GstSample *pulled_preroll;
415 GstSample *pulled_sample;
417 sink = setup_appsink ();
419 gst_segment_init (&segment, GST_FORMAT_TIME);
420 segment.start = 2 * GST_SECOND;
421 fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
423 ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
425 buffer = gst_buffer_new_and_alloc (4);
426 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
428 g_signal_emit_by_name (sink, "pull-preroll", &pulled_preroll);
429 fail_unless (gst_segment_is_equal (&segment,
430 gst_sample_get_segment (pulled_preroll)));
431 gst_sample_unref (pulled_preroll);
433 g_signal_emit_by_name (sink, "pull-sample", &pulled_sample);
434 fail_unless (gst_segment_is_equal (&segment,
435 gst_sample_get_segment (pulled_sample)));
436 gst_sample_unref (pulled_sample);
438 ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
439 cleanup_appsink (sink);
444 GST_START_TEST (test_pull_with_timeout)
451 sink = setup_appsink ();
453 ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
455 /* Check that it actually waits for a bit */
456 t1 = gst_util_get_timestamp ();
457 s = gst_app_sink_try_pull_preroll (GST_APP_SINK (sink), GST_SECOND / 20);
458 tdiff = gst_util_get_timestamp () - t1;
459 GST_LOG ("tdiff: %" GST_TIME_FORMAT, GST_TIME_ARGS (tdiff));
460 fail_unless (s == NULL);
461 fail_unless (tdiff > (GST_SECOND / (20 * 2)));
463 buffer = gst_buffer_new_and_alloc (4);
464 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
466 s = gst_app_sink_try_pull_preroll (GST_APP_SINK (sink), GST_SECOND / 20);
467 fail_unless (s != NULL);
468 gst_sample_unref (s);
470 s = gst_app_sink_try_pull_sample (GST_APP_SINK (sink), 500 * GST_SECOND);
471 fail_unless (s != NULL);
472 gst_sample_unref (s);
475 s = gst_app_sink_try_pull_sample (GST_APP_SINK (sink), 0);
476 fail_unless (s == NULL);
478 /* Check that it actually waits for a bit */
479 t1 = gst_util_get_timestamp ();
480 s = gst_app_sink_try_pull_sample (GST_APP_SINK (sink), GST_SECOND / 20);
481 tdiff = gst_util_get_timestamp () - t1;
482 GST_LOG ("tdiff: %" GST_TIME_FORMAT, GST_TIME_ARGS (tdiff));
483 fail_unless (s == NULL);
484 fail_unless (tdiff > (GST_SECOND / (20 * 2)));
486 /* No waiting, with buffer pending */
487 buffer = gst_buffer_new_and_alloc (5);
488 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
489 s = gst_app_sink_try_pull_sample (GST_APP_SINK (sink), 0);
490 fail_unless (s != NULL);
491 gst_sample_unref (s);
493 /* With timeout, with buffer pending */
494 buffer = gst_buffer_new_and_alloc (6);
495 fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
496 s = gst_app_sink_try_pull_sample (GST_APP_SINK (sink), GST_SECOND / 20);
497 fail_unless (s != NULL);
498 gst_sample_unref (s);
500 ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
501 cleanup_appsink (sink);
509 Suite *s = suite_create ("appsink");
510 TCase *tc_chain = tcase_create ("general");
512 suite_add_tcase (s, tc_chain);
513 tcase_add_test (tc_chain, test_non_clients);
514 tcase_add_test (tc_chain, test_handoff_callback);
515 tcase_add_test (tc_chain, test_notify0);
516 tcase_add_test (tc_chain, test_notify1);
517 tcase_add_test (tc_chain, test_buffer_list_fallback);
518 tcase_add_test (tc_chain, test_buffer_list_support);
519 tcase_add_test (tc_chain, test_buffer_list_fallback_signal);
520 tcase_add_test (tc_chain, test_buffer_list_signal);
521 tcase_add_test (tc_chain, test_segment);
522 tcase_add_test (tc_chain, test_pull_with_timeout);
527 GST_CHECK_MAIN (appsink);