bf61022260871c4003107326f7119d1f50522155
[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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, 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
39   GST_DEBUG ("setup_appsink");
40   appsink = gst_check_setup_element ("appsink");
41   mysrcpad = gst_check_setup_src_pad (appsink, &srctemplate);
42   gst_pad_set_active (mysrcpad, TRUE);
43
44   return appsink;
45 }
46
47 static void
48 cleanup_appsink (GstElement * appsink)
49 {
50   GST_DEBUG ("cleanup_appsink");
51
52   gst_check_teardown_src_pad (appsink);
53   gst_check_teardown_element (appsink);
54 }
55
56 /* This function does an operation to it's indata argument and returns it.
57  * The exact operation performed doesn't matter. Currently it multiplies with
58  * two, but it could do anything. The idea is to use the function to verify
59  * that the code calling it gets run. */
60 static gint
61 operate_on_data (gint indata)
62 {
63   return indata * 2;
64 }
65
66 static GstFlowReturn
67 callback_function (GstAppSink * appsink, gpointer callback_data)
68 {
69   global_testdata = operate_on_data (*((gint *) callback_data));
70
71   return GST_FLOW_OK;
72 }
73
74 static void
75 notify_function (gpointer callback_data)
76 {
77   global_testdata = operate_on_data (*((gint *) callback_data));
78 }
79
80 GST_START_TEST (test_non_clients)
81 {
82   GstElement *sink;
83   GstBuffer *buffer;
84   GstCaps *caps;
85
86   sink = setup_appsink ();
87
88   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
89
90   caps = gst_caps_from_string ("application/x-gst-check");
91   buffer = gst_buffer_new_and_alloc (4);
92   gst_pad_set_caps (mysrcpad, caps);
93   gst_caps_unref (caps);
94   fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
95
96   GST_DEBUG ("cleaning up appsink");
97   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
98   cleanup_appsink (sink);
99 }
100
101 GST_END_TEST;
102
103 /* Verifies that the handoff callback gets run one time when passing a buffer */
104 GST_START_TEST (test_handoff_callback)
105 {
106   GstElement *sink;
107   GstBuffer *buffer;
108   GstCaps *caps;
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   caps = gst_caps_from_string ("application/x-gst-check");
124   buffer = gst_buffer_new_and_alloc (4);
125   gst_pad_set_caps (mysrcpad, caps);
126   gst_caps_unref (caps);
127   /* Pushing a buffer should run our callback */
128   fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
129
130   testdata = operate_on_data (testdata);
131
132   /* If both test_data & global_testdata have been operated on, we're happy. */
133   fail_unless (testdata == global_testdata);
134
135   GST_DEBUG ("cleaning up appsink");
136   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
137   cleanup_appsink (sink);
138 }
139
140 GST_END_TEST;
141
142 /* Verifies that the notify function gets executed when the sink is destroyed */
143 GST_START_TEST (test_notify0)
144 {
145   GstElement *sink;
146   gint testdata;
147   GstAppSinkCallbacks callbacks = { NULL };
148
149   sink = gst_element_factory_make ("appsink", NULL);
150
151   global_testdata = 0;
152   testdata = 17;                /* Arbitrary value */
153
154   gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks,
155       &testdata, (*notify_function));
156
157   GST_DEBUG ("cleaning up appsink");
158   /* Destroying sink should call our notify_function */
159   gst_object_unref (sink);
160
161   testdata = operate_on_data (testdata);
162
163   /* If both test_data & global_testdata have been operated on, we're happy. */
164   fail_unless (testdata == global_testdata);
165 }
166
167 GST_END_TEST;
168
169
170 /* Verifies that the notify function gets executed when
171  * gst_app_sink_set_callbacks () gets called */
172 GST_START_TEST (test_notify1)
173 {
174   GstElement *sink;
175   gint testdata;
176   GstAppSinkCallbacks callbacks = { NULL };
177
178   sink = gst_element_factory_make ("appsink", NULL);
179
180   global_testdata = 0;
181   testdata = 42;                /* Arbitrary value */
182
183   gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks,
184       &testdata, (*notify_function));
185   /* Setting new callbacks should trigger the destroy of the old data */
186   gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks, &testdata, NULL);
187
188   testdata = operate_on_data (testdata);
189
190   /* If both test_data & global_testdata have been operated on, we're happy. */
191   fail_unless (testdata == global_testdata);
192
193   GST_DEBUG ("cleaning up appsink");
194   gst_object_unref (sink);
195 }
196
197 GST_END_TEST;
198
199 static GstBufferList *mylist;
200 static GstCaps *mycaps;
201
202 static gint values[] = { 1, 2, 4 };
203
204 static GstBufferList *
205 create_buffer_list (void)
206 {
207   guint len;
208   GstBuffer *buffer;
209
210   mylist = gst_buffer_list_new ();
211   fail_if (mylist == NULL);
212
213   mycaps = gst_caps_from_string ("application/x-gst-check");
214   fail_if (mycaps == NULL);
215
216   len = gst_buffer_list_length (mylist);
217   fail_if (len != 0);
218
219   buffer = gst_buffer_new_and_alloc (sizeof (gint));
220   gst_buffer_fill (buffer, 0, &values[0], sizeof (gint));
221   gst_buffer_list_add (mylist, buffer);
222
223   buffer = gst_buffer_new_and_alloc (sizeof (gint));
224   gst_buffer_fill (buffer, 0, &values[1], sizeof (gint));
225   gst_buffer_list_add (mylist, buffer);
226
227   buffer = gst_buffer_new_and_alloc (sizeof (gint));
228   gst_buffer_fill (buffer, 0, &values[2], sizeof (gint));
229   gst_buffer_list_add (mylist, buffer);
230
231   gst_pad_set_caps (mysrcpad, mycaps);
232   gst_caps_unref (mycaps);
233
234   return mylist;
235 }
236
237 static GstFlowReturn
238 callback_function_sample (GstAppSink * appsink, gpointer p_counter)
239 {
240   GstSample *sample;
241   GstBuffer *buf;
242   gint *p_int_counter = p_counter;
243
244   sample = gst_app_sink_pull_sample (appsink);
245   buf = gst_sample_get_buffer (sample);
246   fail_unless (GST_IS_BUFFER (buf));
247
248   /* buffer list has 3 buffers in two groups */
249   switch (*p_int_counter) {
250     case 0:
251       fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
252       gst_check_buffer_data (buf, &values[0], sizeof (gint));
253       break;
254     case 1:
255       fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
256       gst_check_buffer_data (buf, &values[1], sizeof (gint));
257       break;
258     case 2:
259       fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
260       gst_check_buffer_data (buf, &values[2], sizeof (gint));
261       break;
262     default:
263       g_warn_if_reached ();
264       break;
265   }
266
267   gst_sample_unref (sample);
268
269   *p_int_counter += 1;
270
271   return GST_FLOW_OK;
272 }
273
274 GST_START_TEST (test_buffer_list_fallback)
275 {
276   GstElement *sink;
277   GstBufferList *list;
278   GstAppSinkCallbacks callbacks = { NULL };
279   gint counter = 0;
280
281   sink = setup_appsink ();
282
283   callbacks.new_sample = callback_function_sample;
284
285   gst_app_sink_set_callbacks (GST_APP_SINK (sink), &callbacks, &counter, NULL);
286
287   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
288
289   list = create_buffer_list ();
290   fail_unless (gst_pad_push_list (mysrcpad, list) == GST_FLOW_OK);
291
292   fail_unless_equals_int (counter, 3);
293
294   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
295   cleanup_appsink (sink);
296 }
297
298 GST_END_TEST;
299
300 GST_START_TEST (test_buffer_list_fallback_signal)
301 {
302   GstElement *sink;
303   GstBufferList *list;
304   gint counter = 0;
305
306   sink = setup_appsink ();
307
308   /* C calling convention to the rescue.. */
309   g_signal_connect (sink, "new-sample", G_CALLBACK (callback_function_sample),
310       &counter);
311
312   g_object_set (sink, "emit-signals", TRUE, NULL);
313
314   ASSERT_SET_STATE (sink, GST_STATE_PLAYING, GST_STATE_CHANGE_ASYNC);
315
316   list = create_buffer_list ();
317   fail_unless (gst_pad_push_list (mysrcpad, list) == GST_FLOW_OK);
318
319   fail_unless_equals_int (counter, 3);
320
321   ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
322   cleanup_appsink (sink);
323 }
324
325 GST_END_TEST;
326
327 static Suite *
328 appsink_suite (void)
329 {
330   Suite *s = suite_create ("appsink");
331   TCase *tc_chain = tcase_create ("general");
332
333   suite_add_tcase (s, tc_chain);
334   tcase_add_test (tc_chain, test_non_clients);
335   tcase_add_test (tc_chain, test_handoff_callback);
336   tcase_add_test (tc_chain, test_notify0);
337   tcase_add_test (tc_chain, test_notify1);
338   tcase_add_test (tc_chain, test_buffer_list_fallback);
339   tcase_add_test (tc_chain, test_buffer_list_fallback_signal);
340
341   return s;
342 }
343
344 GST_CHECK_MAIN (appsink);