759688991794c503b6ff6fae13fad285ddbf4e5a
[framework/multimedia/gst-plugins-good0.10.git] / tests / check / elements / parser.c
1 /*
2  * GStreamer
3  *
4  * unit test for (audio) parser
5  *
6  * Copyright (C) 2008 Nokia Corporation. All rights reserved.
7  *
8  * Contact: Stefan Kost <stefan.kost@nokia.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 #include <gst/check/gstcheck.h>
27 #include "elements/parser.h"
28
29
30 /* context state variables */
31 const gchar *ctx_factory;
32 GstStaticPadTemplate *ctx_sink_template;
33 GstStaticPadTemplate *ctx_src_template;
34 GstCaps *ctx_input_caps;
35 GstCaps *ctx_output_caps;
36 guint ctx_discard = 0;
37 datablob ctx_headers[MAX_HEADERS] = { {NULL, 0}, };
38
39 gboolean ctx_no_metadata = FALSE;
40
41 /* helper variables */
42 GList *current_buf = NULL;
43
44 GstPad *srcpad, *sinkpad;
45 guint dataoffset = 0;
46 GstClockTime ts_counter = 0;
47 gint64 offset_counter = 0;
48 guint buffer_counter = 0;
49
50 typedef struct
51 {
52   guint discard;
53   guint buffers_before_offset_skip;
54   guint offset_skip_amount;
55   const guint8 *data_to_verify;
56   guint data_to_verify_size;
57   GstCaps *caps;
58   gboolean no_metadata;
59 } buffer_verify_data_s;
60
61 /* takes a copy of the passed buffer data */
62 static GstBuffer *
63 buffer_new (const unsigned char *buffer_data, guint size)
64 {
65   GstBuffer *buffer;
66
67   buffer = gst_buffer_new_and_alloc (size);
68   if (buffer_data) {
69     memcpy (GST_BUFFER_DATA (buffer), buffer_data, size);
70   } else {
71     guint i;
72     /* Create a recognizable pattern (loop 0x00 -> 0xff) in the data block */
73     for (i = 0; i < size; i++) {
74       GST_BUFFER_DATA (buffer)[i] = i % 0x100;
75     }
76   }
77
78   gst_buffer_set_caps (buffer, GST_PAD_CAPS (srcpad));
79   GST_BUFFER_OFFSET (buffer) = dataoffset;
80   dataoffset += size;
81   return buffer;
82 }
83
84 /*
85  * Adds buffer sizes together.
86  */
87 static void
88 buffer_count_size (void *buffer, void *user_data)
89 {
90   guint *sum = (guint *) user_data;
91   *sum += GST_BUFFER_SIZE (buffer);
92 }
93
94 /*
95  * Verify that given buffer contains predefined ADTS frame.
96  */
97 static void
98 buffer_verify_data (void *buffer, void *user_data)
99 {
100   buffer_verify_data_s *vdata;
101
102   if (!user_data) {
103     return;
104   }
105
106   vdata = (buffer_verify_data_s *) user_data;
107
108   GST_DEBUG ("discard: %d", vdata->discard);
109   if (vdata->discard) {
110     buffer_counter++;
111     if (buffer_counter == vdata->discard) {
112       buffer_counter = 0;
113       vdata->discard = 0;
114     }
115     return;
116   }
117
118   fail_unless (GST_BUFFER_SIZE (buffer) == vdata->data_to_verify_size);
119   fail_unless (memcmp (GST_BUFFER_DATA (buffer), vdata->data_to_verify,
120           vdata->data_to_verify_size) == 0);
121
122   if (vdata->buffers_before_offset_skip) {
123     /* This is for skipping the garbage in some test cases */
124     if (buffer_counter == vdata->buffers_before_offset_skip) {
125       offset_counter += vdata->offset_skip_amount;
126     }
127   }
128   if (!vdata->no_metadata) {
129     fail_unless (GST_BUFFER_TIMESTAMP (buffer) == ts_counter);
130     fail_unless (GST_BUFFER_DURATION (buffer) != 0);
131     fail_unless (GST_BUFFER_OFFSET (buffer) == offset_counter);
132   }
133
134   if (vdata->caps) {
135     GST_LOG ("%" GST_PTR_FORMAT " = %" GST_PTR_FORMAT " ?",
136         GST_BUFFER_CAPS (buffer), vdata->caps);
137     fail_unless (gst_caps_is_equal (GST_BUFFER_CAPS (buffer), vdata->caps));
138   }
139
140   ts_counter += GST_BUFFER_DURATION (buffer);
141   offset_counter += GST_BUFFER_SIZE (buffer);
142   buffer_counter++;
143 }
144
145 static GstElement *
146 setup_element (const gchar * factory, GstStaticPadTemplate * sink_template,
147     GstCaps * sink_caps, GstStaticPadTemplate * src_template,
148     GstCaps * src_caps)
149 {
150   GstElement *element;
151   GstBus *bus;
152
153   element = gst_check_setup_element (factory);
154   srcpad = gst_check_setup_src_pad (element, src_template, src_caps);
155   sinkpad = gst_check_setup_sink_pad (element, sink_template, sink_caps);
156   gst_pad_set_active (srcpad, TRUE);
157   gst_pad_set_active (sinkpad, TRUE);
158
159   bus = gst_bus_new ();
160   gst_element_set_bus (element, bus);
161
162   fail_unless (gst_element_set_state (element,
163           GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE,
164       "could not set to playing");
165
166   ts_counter = offset_counter = buffer_counter = 0;
167   buffers = NULL;
168   return element;
169 }
170
171 static void
172 cleanup_element (GstElement * element)
173 {
174   GstBus *bus;
175
176   /* Free parsed buffers */
177   gst_check_drop_buffers ();
178
179   bus = GST_ELEMENT_BUS (element);
180   gst_bus_set_flushing (bus, TRUE);
181   gst_object_unref (bus);
182
183   gst_pad_set_active (srcpad, FALSE);
184   gst_pad_set_active (sinkpad, FALSE);
185   gst_check_teardown_src_pad (element);
186   gst_check_teardown_sink_pad (element);
187   gst_check_teardown_element (element);
188 }
189
190 /* inits a standard test */
191 void
192 gst_parser_test_init (GstParserTest * ptest, guint8 * data, guint size,
193     guint num)
194 {
195   /* need these */
196   fail_unless (ctx_factory != NULL);
197   fail_unless (ctx_src_template != NULL);
198   fail_unless (ctx_sink_template != NULL);
199
200   /* basics */
201   memset (ptest, 0, sizeof (*ptest));
202   ptest->factory = ctx_factory;
203   ptest->sink_template = ctx_sink_template;
204   ptest->src_template = ctx_src_template;
205   ptest->framed = TRUE;
206   /* could be NULL if not relevant/needed */
207   ptest->src_caps = ctx_input_caps;
208   ptest->sink_caps = ctx_output_caps;
209   memcpy (ptest->headers, ctx_headers, sizeof (ptest->headers));
210   ptest->discard = ctx_discard;
211   /* some data that pleases caller */
212   ptest->series[0].data = data;
213   ptest->series[0].size = size;
214   ptest->series[0].num = num;
215   ptest->series[0].fpb = 1;
216   ptest->series[1].fpb = 1;
217   ptest->series[2].fpb = 1;
218   ptest->no_metadata = ctx_no_metadata;
219 }
220
221 /*
222  * Test if the parser pushes clean data properly.
223  */
224 void
225 gst_parser_test_run (GstParserTest * test, GstCaps ** out_caps)
226 {
227   buffer_verify_data_s vdata = { 0, 0, 0, NULL, 0, NULL, FALSE };
228   GstElement *element;
229   GstBuffer *buffer = NULL;
230   GstCaps *src_caps;
231   guint i, j, k;
232   guint frames = 0, size = 0;
233
234   element = setup_element (test->factory, test->sink_template, NULL,
235       test->src_template, test->src_caps);
236
237   /* push some setup headers */
238   for (j = 0; j < G_N_ELEMENTS (test->headers) && test->headers[j].data; j++) {
239     buffer = buffer_new (test->headers[j].data, test->headers[j].size);
240     fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
241   }
242
243   for (j = 0; j < 3; j++) {
244     for (i = 0; i < test->series[j].num; i++) {
245       /* sanity enforcing */
246       for (k = 0; k < MAX (1, test->series[j].fpb); k++) {
247         if (!k)
248           buffer = buffer_new (test->series[j].data, test->series[j].size);
249         else {
250           GstCaps *caps = gst_buffer_get_caps (buffer);
251
252           buffer = gst_buffer_join (buffer,
253               buffer_new (test->series[j].data, test->series[j].size));
254           if (caps) {
255             gst_buffer_set_caps (buffer, caps);
256             gst_caps_unref (caps);
257           }
258         }
259       }
260       fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
261       if (j == 0)
262         vdata.buffers_before_offset_skip++;
263       else if (j == 1)
264         vdata.offset_skip_amount += test->series[j].size * test->series[j].fpb;
265       if (j != 1) {
266         frames += test->series[j].fpb;
267         size += test->series[j].size * test->series[j].fpb;
268       }
269     }
270   }
271   gst_pad_push_event (srcpad, gst_event_new_eos ());
272
273   if (G_LIKELY (test->framed))
274     fail_unless_equals_int (g_list_length (buffers) - test->discard, frames);
275
276   /* if all frames are identical, do extended test,
277    * otherwise only verify total data size */
278   if (test->series[0].data && (!test->series[2].size ||
279           (test->series[0].size == test->series[2].size && test->series[2].data
280               && !memcmp (test->series[0].data, test->series[2].data,
281                   test->series[0].size)))) {
282     vdata.data_to_verify = test->series[0].data;
283     vdata.data_to_verify_size = test->series[0].size;
284     vdata.caps = test->sink_caps;
285     vdata.discard = test->discard;
286     vdata.no_metadata = test->no_metadata;
287     g_list_foreach (buffers, buffer_verify_data, &vdata);
288   } else {
289     guint datasum = 0;
290
291     g_list_foreach (buffers, buffer_count_size, &datasum);
292     size -= test->dropped;
293     fail_unless_equals_int (datasum, size);
294   }
295
296   src_caps = gst_pad_get_negotiated_caps (sinkpad);
297   GST_LOG ("output caps: %" GST_PTR_FORMAT, src_caps);
298
299   if (test->sink_caps) {
300     GST_LOG ("%" GST_PTR_FORMAT " = %" GST_PTR_FORMAT " ?", src_caps,
301         test->sink_caps);
302     fail_unless (gst_caps_is_equal (src_caps, test->sink_caps));
303   }
304
305   if (out_caps)
306     *out_caps = src_caps;
307   else
308     gst_caps_unref (src_caps);
309
310   cleanup_element (element);
311 }
312
313 /*
314  * Test if the parser pushes clean data properly.
315  */
316 void
317 gst_parser_test_normal (guint8 * data, guint size)
318 {
319   GstParserTest ptest;
320
321   gst_parser_test_init (&ptest, data, size, 10);
322   gst_parser_test_run (&ptest, NULL);
323 }
324
325 /*
326  * Test if parser drains its buffers properly. Even one single frame
327  * should be drained and pushed forward when EOS occurs. This single frame
328  * case is special, since normally the parser needs more data to be sure
329  * about stream format. But it should still push the frame forward in EOS.
330  */
331 void
332 gst_parser_test_drain_single (guint8 * data, guint size)
333 {
334   GstParserTest ptest;
335
336   gst_parser_test_init (&ptest, data, size, 1);
337   gst_parser_test_run (&ptest, NULL);
338 }
339
340 /*
341  * Make sure that parser does not drain garbage when EOS occurs.
342  */
343 void
344 gst_parser_test_drain_garbage (guint8 * data, guint size, guint8 * garbage,
345     guint gsize)
346 {
347   GstParserTest ptest;
348
349   gst_parser_test_init (&ptest, data, size, 1);
350   ptest.series[1].data = garbage;
351   ptest.series[1].size = gsize;
352   ptest.series[1].num = 1;
353   gst_parser_test_run (&ptest, NULL);
354 }
355
356 /*
357  * Test if parser splits a buffer that contains two frames into two
358  * separate buffers properly.
359  */
360 void
361 gst_parser_test_split (guint8 * data, guint size)
362 {
363   GstParserTest ptest;
364
365   gst_parser_test_init (&ptest, data, size, 10);
366   ptest.series[0].fpb = 2;
367   gst_parser_test_run (&ptest, NULL);
368 }
369
370 /*
371  * Test if the parser skips garbage between frames properly.
372  */
373 void
374 gst_parser_test_skip_garbage (guint8 * data, guint size, guint8 * garbage,
375     guint gsize)
376 {
377   GstParserTest ptest;
378
379   gst_parser_test_init (&ptest, data, size, 10);
380   ptest.series[1].data = garbage;
381   ptest.series[1].size = gsize;
382   ptest.series[1].num = 1;
383   ptest.series[2].data = data;
384   ptest.series[2].size = size;
385   ptest.series[2].num = 10;
386   gst_parser_test_run (&ptest, NULL);
387 }
388
389 /*
390  * Test if the src caps are set according to stream format.
391  */
392 void
393 gst_parser_test_output_caps (guint8 * data, guint size,
394     const gchar * input_caps, const gchar * output_caps)
395 {
396   GstParserTest ptest;
397
398   gst_parser_test_init (&ptest, data, size, 10);
399   if (input_caps) {
400     ptest.src_caps = gst_caps_from_string (input_caps);
401     fail_unless (ptest.src_caps != NULL);
402   }
403   if (output_caps) {
404     ptest.sink_caps = gst_caps_from_string (output_caps);
405     fail_unless (ptest.sink_caps != NULL);
406   }
407   gst_parser_test_run (&ptest, NULL);
408   if (ptest.sink_caps)
409     gst_caps_unref (ptest.sink_caps);
410   if (ptest.src_caps)
411     gst_caps_unref (ptest.src_caps);
412 }
413
414 /*
415  * Test if the src caps are set according to stream format.
416  */
417 GstCaps *
418 gst_parser_test_get_output_caps (guint8 * data, guint size,
419     const gchar * input_caps)
420 {
421   GstParserTest ptest;
422   GstCaps *out_caps;
423
424   gst_parser_test_init (&ptest, data, size, 10);
425   if (input_caps) {
426     ptest.src_caps = gst_caps_from_string (input_caps);
427     fail_unless (ptest.src_caps != NULL);
428   }
429   gst_parser_test_run (&ptest, &out_caps);
430   if (ptest.src_caps)
431     gst_caps_unref (ptest.src_caps);
432
433   return out_caps;
434 }