4 * unit test for amrparse
6 * Copyright (C) 2008 Nokia Corporation. All rights reserved.
8 * Contact: Stefan Kost <stefan.kost@nokia.com>
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.
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.
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.
26 #include <gst/check/gstcheck.h>
27 #include "amrparse_data.h"
29 #define SRC_CAPS_NB "audio/x-amr-nb-sh"
30 #define SRC_CAPS_WB "audio/x-amr-wb-sh"
31 #define SRC_CAPS_ANY "ANY"
33 #define SINK_CAPS_NB "audio/AMR, rate=8000 , channels=1"
34 #define SINK_CAPS_WB "audio/AMR-WB, rate=16000 , channels=1"
35 #define SINK_CAPS_ANY "ANY"
37 #define AMR_FRAME_DURATION (GST_SECOND/50)
40 GList *current_buf = NULL;
42 GstPad *srcpad, *sinkpad;
44 GstClockTime ts_counter = 0;
45 gint64 offset_counter = 0;
46 guint buffer_counter = 0;
48 static GstStaticPadTemplate sinktemplate_nb = GST_STATIC_PAD_TEMPLATE ("sink",
51 GST_STATIC_CAPS (SINK_CAPS_NB)
54 static GstStaticPadTemplate sinktemplate_wb = GST_STATIC_PAD_TEMPLATE ("sink",
57 GST_STATIC_CAPS (SINK_CAPS_WB)
60 static GstStaticPadTemplate sinktemplate_any = GST_STATIC_PAD_TEMPLATE ("sink",
63 GST_STATIC_CAPS (SINK_CAPS_ANY)
66 static GstStaticPadTemplate srctemplate_nb = GST_STATIC_PAD_TEMPLATE ("src",
69 GST_STATIC_CAPS (SRC_CAPS_NB)
72 static GstStaticPadTemplate srctemplate_wb = GST_STATIC_PAD_TEMPLATE ("src",
75 GST_STATIC_CAPS (SRC_CAPS_WB)
78 static GstStaticPadTemplate srctemplate_any = GST_STATIC_PAD_TEMPLATE ("src",
81 GST_STATIC_CAPS (SRC_CAPS_ANY)
86 guint buffers_before_offset_skip;
87 guint offset_skip_amount;
88 } buffer_verify_data_s;
91 * Create a GstBuffer of the given data and set the caps, if not NULL.
94 buffer_new (const unsigned char *buffer_data, guint size,
95 const gchar * caps_str)
100 buffer = gst_buffer_new_and_alloc (size);
101 memcpy (GST_BUFFER_DATA (buffer), buffer_data, size);
103 caps = gst_caps_from_string (caps_str);
104 gst_buffer_set_caps (buffer, caps);
105 gst_caps_unref (caps);
107 GST_BUFFER_OFFSET (buffer) = dataoffset;
114 * Unrefs given buffer.
117 buffer_unref (void *buffer, void *user_data)
119 gst_buffer_unref (GST_BUFFER (buffer));
124 * Verify that given buffer contains predefined AMR-NB frame.
127 buffer_verify_nb (void *buffer, void *user_data)
129 fail_unless (memcmp (GST_BUFFER_DATA (buffer), frame_data_nb,
130 FRAME_DATA_NB_LEN) == 0);
131 fail_unless (GST_BUFFER_TIMESTAMP (buffer) == ts_counter);
132 fail_unless (GST_BUFFER_DURATION (buffer) == AMR_FRAME_DURATION);
133 ts_counter += AMR_FRAME_DURATION;
136 buffer_verify_data_s *vdata = (buffer_verify_data_s *) user_data;
138 /* This is for skipping the garbage in some test cases */
139 if (buffer_counter == vdata->buffers_before_offset_skip) {
140 offset_counter += vdata->offset_skip_amount;
143 fail_unless (GST_BUFFER_OFFSET (buffer) == offset_counter);
144 offset_counter += FRAME_DATA_NB_LEN;
150 * Verify that given buffer contains predefined AMR-WB frame.
153 buffer_verify_wb (void *buffer, void *user_data)
155 fail_unless (memcmp (GST_BUFFER_DATA (buffer), frame_data_wb,
156 FRAME_DATA_WB_LEN) == 0);
157 fail_unless (GST_BUFFER_TIMESTAMP (buffer) == ts_counter);
158 fail_unless (GST_BUFFER_DURATION (buffer) == AMR_FRAME_DURATION);
161 buffer_verify_data_s *vdata = (buffer_verify_data_s *) user_data;
163 /* This is for skipping the garbage in some test cases */
164 if (buffer_counter == vdata->buffers_before_offset_skip) {
165 offset_counter += vdata->offset_skip_amount;
168 fail_unless (GST_BUFFER_OFFSET (buffer) == offset_counter);
169 offset_counter += FRAME_DATA_WB_LEN;
170 ts_counter += AMR_FRAME_DURATION;
175 * Create a parser and pads according to given templates.
178 setup_amrparse (GstStaticPadTemplate * srctemplate,
179 GstStaticPadTemplate * sinktemplate)
181 GstElement *amrparse;
184 GST_DEBUG ("setup_amrparse");
185 amrparse = gst_check_setup_element ("amrparse");
186 srcpad = gst_check_setup_src_pad (amrparse, srctemplate, NULL);
187 sinkpad = gst_check_setup_sink_pad (amrparse, sinktemplate, NULL);
188 gst_pad_set_active (srcpad, TRUE);
189 gst_pad_set_active (sinkpad, TRUE);
191 bus = gst_bus_new ();
192 gst_element_set_bus (amrparse, bus);
194 fail_unless (gst_element_set_state (amrparse,
195 GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE,
196 "could not set to playing");
198 ts_counter = offset_counter = buffer_counter = 0;
205 * Delete parser and all related resources.
208 cleanup_amrparse (GstElement * amrparse)
212 /* free parsed buffers */
213 g_list_foreach (buffers, buffer_unref, NULL);
214 g_list_free (buffers);
217 bus = GST_ELEMENT_BUS (amrparse);
218 gst_bus_set_flushing (bus, TRUE);
219 gst_object_unref (bus);
221 GST_DEBUG ("cleanup_amrparse");
222 gst_pad_set_active (srcpad, FALSE);
223 gst_pad_set_active (sinkpad, FALSE);
224 gst_check_teardown_src_pad (amrparse);
225 gst_check_teardown_sink_pad (amrparse);
226 gst_check_teardown_element (amrparse);
233 * Test if NB parser manages to find all frames and pushes them forward.
235 GST_START_TEST (test_parse_nb_normal)
237 GstElement *amrparse;
241 amrparse = setup_amrparse (&srctemplate_nb, &sinktemplate_nb);
243 /* Push the header */
244 buffer = buffer_new (frame_hdr_nb, FRAME_HDR_NB_LEN, SRC_CAPS_NB);
245 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
246 offset_counter = FRAME_HDR_NB_LEN;
248 for (i = 0; i < 10; i++) {
249 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, SRC_CAPS_NB);
250 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
252 gst_pad_push_event (srcpad, gst_event_new_eos ());
254 fail_unless_equals_int (g_list_length (buffers), 10);
255 g_list_foreach (buffers, buffer_verify_nb, NULL);
257 cleanup_amrparse (amrparse);
264 * Test if NB parser drains its buffers properly. Even one single buffer
265 * should be drained and pushed forward when EOS occurs. This single buffer
266 * case is special, since normally the parser needs more data to be sure
267 * about stream format. But it should still push the frame forward in EOS.
269 GST_START_TEST (test_parse_nb_drain_single)
271 GstElement *amrparse;
274 amrparse = setup_amrparse (&srctemplate_nb, &sinktemplate_nb);
276 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, SRC_CAPS_NB);
277 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
278 gst_pad_push_event (srcpad, gst_event_new_eos ());
280 fail_unless_equals_int (g_list_length (buffers), 1);
281 g_list_foreach (buffers, buffer_verify_nb, NULL);
283 cleanup_amrparse (amrparse);
290 * Make sure that parser does not drain garbage when EOS occurs.
292 GST_START_TEST (test_parse_nb_drain_garbage)
294 GstElement *amrparse;
298 amrparse = setup_amrparse (&srctemplate_nb, &sinktemplate_nb);
300 for (i = 0; i < 10; i++) {
301 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, SRC_CAPS_NB);
302 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
305 /* Now push one garbage frame and then EOS */
306 buffer = buffer_new (garbage_frame, GARBAGE_FRAME_LEN, SRC_CAPS_NB);
307 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
308 gst_pad_push_event (srcpad, gst_event_new_eos ());
310 /* parser should have pushed only the valid frames */
311 fail_unless_equals_int (g_list_length (buffers), 10);
312 g_list_foreach (buffers, buffer_verify_nb, NULL);
314 cleanup_amrparse (amrparse);
321 * Test if NB parser splits a buffer that contains two frames into two
322 * separate buffers properly.
324 GST_START_TEST (test_parse_nb_split)
326 GstElement *amrparse;
330 amrparse = setup_amrparse (&srctemplate_nb, &sinktemplate_nb);
332 for (i = 0; i < 10; i++) {
333 /* Put two frames in one buffer */
334 buffer = buffer_new (frame_data_nb, 2 * FRAME_DATA_NB_LEN, SRC_CAPS_NB);
335 memcpy (GST_BUFFER_DATA (buffer) + FRAME_DATA_NB_LEN,
336 frame_data_nb, FRAME_DATA_NB_LEN);
337 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
339 gst_pad_push_event (srcpad, gst_event_new_eos ());
341 fail_unless_equals_int (g_list_length (buffers), 20);
343 /* Does output buffers contain correct frame data? */
344 g_list_foreach (buffers, buffer_verify_nb, NULL);
346 cleanup_amrparse (amrparse);
353 * Test if NB parser detects the format correctly.
355 GST_START_TEST (test_parse_nb_detect_stream)
357 GstElement *amrparse;
359 GstCaps *caps, *mycaps;
362 amrparse = setup_amrparse (&srctemplate_any, &sinktemplate_any);
364 /* Push the header */
365 buffer = buffer_new (frame_hdr_nb, FRAME_HDR_NB_LEN, NULL);
366 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
368 for (i = 0; i < 10; i++) {
369 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, NULL);
370 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
372 gst_pad_push_event (srcpad, gst_event_new_eos ());
374 caps = GST_PAD_CAPS (sinkpad);
375 mycaps = gst_caps_from_string (SINK_CAPS_NB);
376 fail_unless (gst_caps_is_equal (caps, mycaps));
377 gst_caps_unref (mycaps);
379 cleanup_amrparse (amrparse);
386 * Test if NB parser skips garbage in the datastream correctly and still
387 * finds all correct frames.
389 GST_START_TEST (test_parse_nb_skip_garbage)
391 buffer_verify_data_s vdata = { 5, GARBAGE_FRAME_LEN };
392 GstElement *amrparse;
396 amrparse = setup_amrparse (&srctemplate_nb, &sinktemplate_nb);
398 /* First push 5 healthy frames */
399 for (i = 0; i < 5; i++) {
400 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, SRC_CAPS_NB);
401 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
404 /* Then push some garbage */
405 buffer = buffer_new (garbage_frame, GARBAGE_FRAME_LEN, SRC_CAPS_NB);
406 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
408 /* Again, healthy frames */
409 for (i = 0; i < 5; i++) {
410 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, SRC_CAPS_NB);
411 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
414 gst_pad_push_event (srcpad, gst_event_new_eos ());
416 /* Did it find all 10 healthy frames? */
417 fail_unless_equals_int (g_list_length (buffers), 10);
418 g_list_foreach (buffers, buffer_verify_nb, &vdata);
420 cleanup_amrparse (amrparse);
427 * Test if WB parser manages to find all frames and pushes them forward.
429 GST_START_TEST (test_parse_wb_normal)
431 GstElement *amrparse;
435 amrparse = setup_amrparse (&srctemplate_wb, &sinktemplate_wb);
437 /* Push the header */
438 buffer = buffer_new (frame_hdr_wb, FRAME_HDR_WB_LEN, SRC_CAPS_WB);
439 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
440 offset_counter = FRAME_HDR_WB_LEN;
442 for (i = 0; i < 10; i++) {
443 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, SRC_CAPS_WB);
444 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
446 gst_pad_push_event (srcpad, gst_event_new_eos ());
448 fail_unless_equals_int (g_list_length (buffers), 10);
449 g_list_foreach (buffers, buffer_verify_wb, NULL);
451 cleanup_amrparse (amrparse);
458 * Test if WB parser drains its buffers properly. Even one single buffer
459 * should be drained and pushed forward when EOS occurs. This single buffer
460 * case is special, since normally the parser needs more data to be sure
461 * about stream format. But it should still push the frame forward in EOS.
463 GST_START_TEST (test_parse_wb_drain_single)
465 GstElement *amrparse;
468 amrparse = setup_amrparse (&srctemplate_wb, &sinktemplate_wb);
470 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, SRC_CAPS_WB);
471 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
472 gst_pad_push_event (srcpad, gst_event_new_eos ());
474 fail_unless_equals_int (g_list_length (buffers), 1);
475 g_list_foreach (buffers, buffer_verify_wb, NULL);
477 cleanup_amrparse (amrparse);
484 * Make sure that parser does not drain garbage when EOS occurs.
486 GST_START_TEST (test_parse_wb_drain_garbage)
488 GstElement *amrparse;
492 amrparse = setup_amrparse (&srctemplate_wb, &sinktemplate_wb);
494 for (i = 0; i < 10; i++) {
495 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, SRC_CAPS_WB);
496 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
499 /* Now push one garbage frame and then EOS */
500 buffer = buffer_new (garbage_frame, GARBAGE_FRAME_LEN, SRC_CAPS_WB);
501 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
502 gst_pad_push_event (srcpad, gst_event_new_eos ());
504 /* parser should have pushed only the valid frames */
505 fail_unless_equals_int (g_list_length (buffers), 10);
506 g_list_foreach (buffers, buffer_verify_wb, NULL);
508 cleanup_amrparse (amrparse);
515 * Test if WB parser splits a buffer that contains two frames into two
516 * separate buffers properly.
518 GST_START_TEST (test_parse_wb_split)
520 GstElement *amrparse;
524 amrparse = setup_amrparse (&srctemplate_wb, &sinktemplate_wb);
526 for (i = 0; i < 10; i++) {
527 /* Put two frames in one buffer */
528 buffer = buffer_new (frame_data_wb, 2 * FRAME_DATA_WB_LEN, SRC_CAPS_WB);
529 memcpy (GST_BUFFER_DATA (buffer) + FRAME_DATA_WB_LEN,
530 frame_data_wb, FRAME_DATA_WB_LEN);
531 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
533 gst_pad_push_event (srcpad, gst_event_new_eos ());
535 fail_unless_equals_int (g_list_length (buffers), 20);
537 /* Does output buffers contain correct frame data? */
538 g_list_foreach (buffers, buffer_verify_wb, NULL);
540 cleanup_amrparse (amrparse);
547 * Test if WB parser detects the format correctly.
549 GST_START_TEST (test_parse_wb_detect_stream)
551 GstElement *amrparse;
553 GstCaps *caps, *mycaps;
556 amrparse = setup_amrparse (&srctemplate_any, &sinktemplate_any);
558 /* Push the header */
559 buffer = buffer_new (frame_hdr_wb, FRAME_HDR_WB_LEN, NULL);
560 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
562 for (i = 0; i < 10; i++) {
563 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, NULL);
564 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
566 gst_pad_push_event (srcpad, gst_event_new_eos ());
568 caps = GST_PAD_CAPS (sinkpad);
569 mycaps = gst_caps_from_string (SINK_CAPS_WB);
570 fail_unless (gst_caps_is_equal (caps, mycaps));
571 gst_caps_unref (mycaps);
573 cleanup_amrparse (amrparse);
580 * Test if WB parser skips garbage in the datastream correctly and still
581 * finds all correct frames.
583 GST_START_TEST (test_parse_wb_skip_garbage)
585 buffer_verify_data_s vdata = { 5, GARBAGE_FRAME_LEN };
586 GstElement *amrparse;
590 amrparse = setup_amrparse (&srctemplate_wb, &sinktemplate_wb);
592 /* First push 5 healthy frames */
593 for (i = 0; i < 5; i++) {
594 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, SRC_CAPS_WB);
595 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
598 /* Then push some garbage */
599 buffer = buffer_new (garbage_frame, GARBAGE_FRAME_LEN, SRC_CAPS_WB);
600 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
602 /* Again, healthy frames */
603 for (i = 0; i < 5; i++) {
604 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, SRC_CAPS_WB);
605 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
608 gst_pad_push_event (srcpad, gst_event_new_eos ());
610 /* Did it find all 10 healthy frames? */
611 fail_unless_equals_int (g_list_length (buffers), 10);
612 g_list_foreach (buffers, buffer_verify_wb, &vdata);
614 cleanup_amrparse (amrparse);
624 amrparse_suite (void)
626 Suite *s = suite_create ("amrparse");
627 TCase *tc_chain = tcase_create ("general");
629 suite_add_tcase (s, tc_chain);
631 tcase_add_test (tc_chain, test_parse_nb_normal);
632 tcase_add_test (tc_chain, test_parse_nb_drain_single);
633 tcase_add_test (tc_chain, test_parse_nb_drain_garbage);
634 tcase_add_test (tc_chain, test_parse_nb_split);
635 tcase_add_test (tc_chain, test_parse_nb_detect_stream);
636 tcase_add_test (tc_chain, test_parse_nb_skip_garbage);
639 tcase_add_test (tc_chain, test_parse_wb_normal);
640 tcase_add_test (tc_chain, test_parse_wb_drain_single);
641 tcase_add_test (tc_chain, test_parse_wb_drain_garbage);
642 tcase_add_test (tc_chain, test_parse_wb_split);
643 tcase_add_test (tc_chain, test_parse_wb_detect_stream);
644 tcase_add_test (tc_chain, test_parse_wb_skip_garbage);
650 * - Both push- and pull-modes need to be tested
654 GST_CHECK_MAIN (amrparse);