aabeb00d2821195027162e5fec4a675b2e5c927e
[platform/upstream/gstreamer.git] / tests / check / elements / appsink.c
1 /* GStreamer
2  *
3  * Copyright (C) 2009, Axis Communications AB, LUND, SWEDEN
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 #include <gst/check/gstcheck.h>
22 #include <gst/app/gstappsink.h>
23
24 gint global_testdata;
25
26 static GstPad *mysrcpad;
27
28 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
29     GST_PAD_SRC,
30     GST_PAD_ALWAYS,
31     GST_STATIC_CAPS ("application/x-gst-check")
32     );
33
34 static GstElement *
35 setup_appsink (void)
36 {
37   GstElement *appsink;
38   GstCaps *caps;
39
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);
44
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);
48
49   return appsink;
50 }
51
52 static void
53 cleanup_appsink (GstElement * appsink)
54 {
55   GST_DEBUG ("cleanup_appsink");
56
57   gst_check_teardown_src_pad (appsink);
58   gst_check_teardown_element (appsink);
59 }
60
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. */
65 static gint
66 operate_on_data (gint indata)
67 {
68   return indata * 2;
69 }
70
71 static GstFlowReturn
72 callback_function (GstAppSink * appsink, gpointer callback_data)
73 {
74   global_testdata = operate_on_data (*((gint *) callback_data));
75
76   return GST_FLOW_OK;
77 }
78
79 static void
80 notify_function (gpointer callback_data)
81 {
82   global_testdata = operate_on_data (*((gint *) callback_data));
83 }
84
85 GST_START_TEST (test_non_clients)
86 {
87   GstElement *sink;
88   GstBuffer *buffer;
89
90   sink = setup_appsink ();
91
92   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
93
94   buffer = gst_buffer_new_and_alloc (4);
95   fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
96
97   GST_DEBUG ("cleaning up appsink");
98   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
99   cleanup_appsink (sink);
100 }
101
102 GST_END_TEST;
103
104 /* Verifies that the handoff callback gets run one time when passing a buffer */
105 GST_START_TEST (test_handoff_callback)
106 {
107   GstElement *sink;
108   GstBuffer *buffer;
109   gint testdata;
110   GstAppSinkCallbacks callbacks = { NULL };
111
112   sink = setup_appsink ();
113
114   global_testdata = 0;
115   testdata = 5;                 /* Arbitrary value */
116
117   callbacks.new_sample = callback_function;
118
119   gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks, &testdata, NULL);
120
121   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
122
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);
126
127   testdata = operate_on_data (testdata);
128
129   /* If both test_data & global_testdata have been operated on, we're happy. */
130   fail_unless (testdata == global_testdata);
131
132   GST_DEBUG ("cleaning up appsink");
133   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
134   cleanup_appsink (sink);
135 }
136
137 GST_END_TEST;
138
139 /* Verifies that the notify function gets executed when the sink is destroyed */
140 GST_START_TEST (test_notify0)
141 {
142   GstElement *sink;
143   gint testdata;
144   GstAppSinkCallbacks callbacks = { NULL };
145
146   sink = gst_element_factory_make ("appsink", NULL);
147
148   global_testdata = 0;
149   testdata = 17;                /* Arbitrary value */
150
151   gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks,
152       &testdata, (*notify_function));
153
154   GST_DEBUG ("cleaning up appsink");
155   /* Destroying sink should call our notify_function */
156   gst_object_unref (sink);
157
158   testdata = operate_on_data (testdata);
159
160   /* If both test_data & global_testdata have been operated on, we're happy. */
161   fail_unless (testdata == global_testdata);
162 }
163
164 GST_END_TEST;
165
166
167 /* Verifies that the notify function gets executed when
168  * gst_app_sink_set_callbacks () gets called */
169 GST_START_TEST (test_notify1)
170 {
171   GstElement *sink;
172   gint testdata;
173   GstAppSinkCallbacks callbacks = { NULL };
174
175   sink = gst_element_factory_make ("appsink", NULL);
176
177   global_testdata = 0;
178   testdata = 42;                /* Arbitrary value */
179
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);
184
185   testdata = operate_on_data (testdata);
186
187   /* If both test_data & global_testdata have been operated on, we're happy. */
188   fail_unless (testdata == global_testdata);
189
190   GST_DEBUG ("cleaning up appsink");
191   gst_object_unref (sink);
192 }
193
194 GST_END_TEST;
195
196 static const gint values[] = { 1, 2, 4 };
197
198 static GstBufferList *
199 create_buffer_list (void)
200 {
201   guint len;
202   GstBuffer *buffer;
203   GstBufferList *mylist;
204
205   mylist = gst_buffer_list_new ();
206   fail_if (mylist == NULL);
207
208   len = gst_buffer_list_length (mylist);
209   fail_if (len != 0);
210
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);
214
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);
218
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);
222
223   return mylist;
224 }
225
226 static GstFlowReturn
227 callback_function_sample (GstAppSink * appsink, gpointer p_counter)
228 {
229   GstSample *sample;
230   GstBuffer *buf;
231   gint *p_int_counter = p_counter;
232
233   sample = gst_app_sink_pull_sample (appsink);
234   buf = gst_sample_get_buffer (sample);
235   fail_unless (GST_IS_BUFFER (buf));
236
237   /* buffer list has 3 buffers in two groups */
238   switch (*p_int_counter) {
239     case 0:
240       fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
241       gst_check_buffer_data (buf, &values[0], sizeof (gint));
242       break;
243     case 1:
244       fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
245       gst_check_buffer_data (buf, &values[1], sizeof (gint));
246       break;
247     case 2:
248       fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
249       gst_check_buffer_data (buf, &values[2], sizeof (gint));
250       break;
251     default:
252       g_warn_if_reached ();
253       break;
254   }
255
256   gst_sample_unref (sample);
257
258   *p_int_counter += 1;
259
260   return GST_FLOW_OK;
261 }
262
263 GST_START_TEST (test_buffer_list_fallback)
264 {
265   GstElement *sink;
266   GstBufferList *list;
267   GstAppSinkCallbacks callbacks = { NULL };
268   gint counter = 0;
269
270   sink = setup_appsink ();
271
272   callbacks.new_sample = callback_function_sample;
273
274   gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks, &counter, NULL);
275
276   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
277
278   list = create_buffer_list ();
279   fail_unless (gst_pad_push_list (mysrcpad, list) == GST_FLOW_OK);
280
281   fail_unless_equals_int (counter, 3);
282
283   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
284   cleanup_appsink (sink);
285 }
286
287 GST_END_TEST;
288
289 GST_START_TEST (test_buffer_list_fallback_signal)
290 {
291   GstElement *sink;
292   GstBufferList *list;
293   gint counter = 0;
294
295   sink = setup_appsink ();
296
297   /* C calling convention to the rescue.. */
298   g_signal_connect (sink, "new-sample", G_CALLBACK (callback_function_sample),
299       &counter);
300
301   g_object_set (sink, "emit-signals", TRUE, NULL);
302
303   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
304
305   list = create_buffer_list ();
306   fail_unless (gst_pad_push_list (mysrcpad, list) == GST_FLOW_OK);
307
308   fail_unless_equals_int (counter, 3);
309
310   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
311   cleanup_appsink (sink);
312 }
313
314 GST_END_TEST;
315
316 GST_START_TEST (test_segment)
317 {
318   GstElement *sink;
319   GstSegment segment;
320   GstBuffer *buffer;
321   GstSample *pulled_preroll;
322   GstSample *pulled_sample;
323
324   sink = setup_appsink ();
325
326   gst_segment_init (&segment, GST_FORMAT_TIME);
327   segment.start = 2 * GST_SECOND;
328   fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
329
330   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
331
332   buffer = gst_buffer_new_and_alloc (4);
333   fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
334
335   g_signal_emit_by_name (sink, "pull-preroll", &pulled_preroll);
336   fail_unless (gst_segment_is_equal (&segment,
337           gst_sample_get_segment (pulled_preroll)));
338   gst_sample_unref (pulled_preroll);
339
340   g_signal_emit_by_name (sink, "pull-sample", &pulled_sample);
341   fail_unless (gst_segment_is_equal (&segment,
342           gst_sample_get_segment (pulled_sample)));
343   gst_sample_unref (pulled_sample);
344
345   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
346   cleanup_appsink (sink);
347 }
348
349 GST_END_TEST;
350
351 GST_START_TEST (test_pull_with_timeout)
352 {
353   GstElement *sink;
354   GstBuffer *buffer;
355   GstSample *s;
356   guint64 t1, tdiff;
357
358   sink = setup_appsink ();
359
360   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
361
362   /* Check that it actually waits for a bit */
363   t1 = gst_util_get_timestamp ();
364   s = gst_app_sink_try_pull_preroll (GST_APP_SINK (sink), GST_SECOND / 20);
365   tdiff = gst_util_get_timestamp () - t1;
366   GST_LOG ("tdiff: %" GST_TIME_FORMAT, GST_TIME_ARGS (tdiff));
367   fail_unless (s == NULL);
368   fail_unless (tdiff > (GST_SECOND / (20 * 2)));
369
370   buffer = gst_buffer_new_and_alloc (4);
371   fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
372
373   s = gst_app_sink_try_pull_preroll (GST_APP_SINK (sink), GST_SECOND / 20);
374   fail_unless (s != NULL);
375   gst_sample_unref (s);
376
377   s = gst_app_sink_try_pull_sample (GST_APP_SINK (sink), 500 * GST_SECOND);
378   fail_unless (s != NULL);
379   gst_sample_unref (s);
380
381   /* No waiting */
382   s = gst_app_sink_try_pull_sample (GST_APP_SINK (sink), 0);
383   fail_unless (s == NULL);
384
385   /* Check that it actually waits for a bit */
386   t1 = gst_util_get_timestamp ();
387   s = gst_app_sink_try_pull_sample (GST_APP_SINK (sink), GST_SECOND / 20);
388   tdiff = gst_util_get_timestamp () - t1;
389   GST_LOG ("tdiff: %" GST_TIME_FORMAT, GST_TIME_ARGS (tdiff));
390   fail_unless (s == NULL);
391   fail_unless (tdiff > (GST_SECOND / (20 * 2)));
392
393   /* No waiting, with buffer pending */
394   buffer = gst_buffer_new_and_alloc (5);
395   fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
396   s = gst_app_sink_try_pull_sample (GST_APP_SINK (sink), 0);
397   fail_unless (s != NULL);
398   gst_sample_unref (s);
399
400   /* With timeout, with buffer pending */
401   buffer = gst_buffer_new_and_alloc (6);
402   fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
403   s = gst_app_sink_try_pull_sample (GST_APP_SINK (sink), GST_SECOND / 20);
404   fail_unless (s != NULL);
405   gst_sample_unref (s);
406
407   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
408   cleanup_appsink (sink);
409 }
410
411 GST_END_TEST;
412
413 static Suite *
414 appsink_suite (void)
415 {
416   Suite *s = suite_create ("appsink");
417   TCase *tc_chain = tcase_create ("general");
418
419   suite_add_tcase (s, tc_chain);
420   tcase_add_test (tc_chain, test_non_clients);
421   tcase_add_test (tc_chain, test_handoff_callback);
422   tcase_add_test (tc_chain, test_notify0);
423   tcase_add_test (tc_chain, test_notify1);
424   tcase_add_test (tc_chain, test_buffer_list_fallback);
425   tcase_add_test (tc_chain, test_buffer_list_fallback_signal);
426   tcase_add_test (tc_chain, test_segment);
427   tcase_add_test (tc_chain, test_pull_with_timeout);
428
429   return s;
430 }
431
432 GST_CHECK_MAIN (appsink);