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)
39 GList *current_buf = NULL;
41 GstPad *srcpad, *sinkpad;
43 GstClockTime ts_counter = 0;
44 gint64 offset_counter = 0;
45 guint buffer_counter = 0;
47 static GstStaticPadTemplate sinktemplate_nb = GST_STATIC_PAD_TEMPLATE ("sink",
50 GST_STATIC_CAPS (SINK_CAPS_NB)
53 static GstStaticPadTemplate sinktemplate_wb = GST_STATIC_PAD_TEMPLATE ("sink",
56 GST_STATIC_CAPS (SINK_CAPS_WB)
59 static GstStaticPadTemplate sinktemplate_any = GST_STATIC_PAD_TEMPLATE ("sink",
62 GST_STATIC_CAPS (SINK_CAPS_ANY)
65 static GstStaticPadTemplate srctemplate_nb = GST_STATIC_PAD_TEMPLATE ("src",
68 GST_STATIC_CAPS (SRC_CAPS_NB)
71 static GstStaticPadTemplate srctemplate_wb = GST_STATIC_PAD_TEMPLATE ("src",
74 GST_STATIC_CAPS (SRC_CAPS_WB)
77 static GstStaticPadTemplate srctemplate_any = GST_STATIC_PAD_TEMPLATE ("src",
80 GST_STATIC_CAPS (SRC_CAPS_ANY)
85 guint buffers_before_offset_skip;
86 guint offset_skip_amount;
87 } buffer_verify_data_s;
90 * Create a GstBuffer of the given data and set the caps, if not NULL.
93 buffer_new (const unsigned char *buffer_data, guint size,
94 const gchar * caps_str)
99 buffer = gst_buffer_new_and_alloc (size);
100 memcpy (GST_BUFFER_DATA (buffer), buffer_data, size);
102 caps = gst_caps_from_string (caps_str);
103 gst_buffer_set_caps (buffer, caps);
104 gst_caps_unref (caps);
106 GST_BUFFER_OFFSET (buffer) = dataoffset;
113 * Unrefs given buffer.
116 buffer_unref (void *buffer, void *user_data)
118 gst_buffer_unref (GST_BUFFER (buffer));
123 * Verify that given buffer contains predefined AMR-NB frame.
126 buffer_verify_nb (void *buffer, void *user_data)
128 fail_unless (memcmp (GST_BUFFER_DATA (buffer), frame_data_nb,
129 FRAME_DATA_NB_LEN) == 0);
130 fail_unless (GST_BUFFER_TIMESTAMP (buffer) == ts_counter);
131 fail_unless (GST_BUFFER_DURATION (buffer) == AMR_FRAME_DURATION);
132 ts_counter += AMR_FRAME_DURATION;
135 buffer_verify_data_s *vdata = (buffer_verify_data_s *) user_data;
137 /* This is for skipping the garbage in some test cases */
138 if (buffer_counter == vdata->buffers_before_offset_skip) {
139 offset_counter += vdata->offset_skip_amount;
142 fail_unless (GST_BUFFER_OFFSET (buffer) == offset_counter);
143 offset_counter += FRAME_DATA_NB_LEN;
149 * Verify that given buffer contains predefined AMR-WB frame.
152 buffer_verify_wb (void *buffer, void *user_data)
154 fail_unless (memcmp (GST_BUFFER_DATA (buffer), frame_data_wb,
155 FRAME_DATA_WB_LEN) == 0);
156 fail_unless (GST_BUFFER_TIMESTAMP (buffer) == ts_counter);
157 fail_unless (GST_BUFFER_DURATION (buffer) == AMR_FRAME_DURATION);
160 buffer_verify_data_s *vdata = (buffer_verify_data_s *) user_data;
162 /* This is for skipping the garbage in some test cases */
163 if (buffer_counter == vdata->buffers_before_offset_skip) {
164 offset_counter += vdata->offset_skip_amount;
167 fail_unless (GST_BUFFER_OFFSET (buffer) == offset_counter);
168 offset_counter += FRAME_DATA_WB_LEN;
169 ts_counter += AMR_FRAME_DURATION;
174 * Create a parser and pads according to given templates.
177 setup_amrparse (GstStaticPadTemplate * srctemplate,
178 GstStaticPadTemplate * sinktemplate)
180 GstElement *amrparse;
183 GST_DEBUG ("setup_amrparse");
184 amrparse = gst_check_setup_element ("amrparse");
185 srcpad = gst_check_setup_src_pad (amrparse, srctemplate, NULL);
186 sinkpad = gst_check_setup_sink_pad (amrparse, sinktemplate, NULL);
187 gst_pad_set_active (srcpad, TRUE);
188 gst_pad_set_active (sinkpad, TRUE);
190 bus = gst_bus_new ();
191 gst_element_set_bus (amrparse, bus);
193 fail_unless (gst_element_set_state (amrparse,
194 GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE,
195 "could not set to playing");
197 ts_counter = offset_counter = buffer_counter = 0;
204 * Delete parser and all related resources.
207 cleanup_amrparse (GstElement * amrparse)
211 /* free parsed buffers */
212 g_list_foreach (buffers, buffer_unref, NULL);
213 g_list_free (buffers);
216 bus = GST_ELEMENT_BUS (amrparse);
217 gst_bus_set_flushing (bus, TRUE);
218 gst_object_unref (bus);
220 GST_DEBUG ("cleanup_amrparse");
221 gst_pad_set_active (srcpad, FALSE);
222 gst_pad_set_active (sinkpad, FALSE);
223 gst_check_teardown_src_pad (amrparse);
224 gst_check_teardown_sink_pad (amrparse);
225 gst_check_teardown_element (amrparse);
232 * Test if NB parser manages to find all frames and pushes them forward.
234 GST_START_TEST (test_parse_nb_normal)
236 GstElement *amrparse;
240 amrparse = setup_amrparse (&srctemplate_nb, &sinktemplate_nb);
242 /* Push the header */
243 buffer = buffer_new (frame_hdr_nb, FRAME_HDR_NB_LEN, SRC_CAPS_NB);
244 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
245 offset_counter = FRAME_HDR_NB_LEN;
247 for (i = 0; i < 10; i++) {
248 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, SRC_CAPS_NB);
249 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
251 gst_pad_push_event (srcpad, gst_event_new_eos ());
253 fail_unless_equals_int (g_list_length (buffers), 10);
254 g_list_foreach (buffers, buffer_verify_nb, NULL);
256 cleanup_amrparse (amrparse);
263 * Test if NB parser drains its buffers properly. Even one single buffer
264 * should be drained and pushed forward when EOS occurs. This single buffer
265 * case is special, since normally the parser needs more data to be sure
266 * about stream format. But it should still push the frame forward in EOS.
268 GST_START_TEST (test_parse_nb_drain_single)
270 GstElement *amrparse;
273 amrparse = setup_amrparse (&srctemplate_nb, &sinktemplate_nb);
275 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, SRC_CAPS_NB);
276 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
277 gst_pad_push_event (srcpad, gst_event_new_eos ());
279 fail_unless_equals_int (g_list_length (buffers), 1);
280 g_list_foreach (buffers, buffer_verify_nb, NULL);
282 cleanup_amrparse (amrparse);
289 * Make sure that parser does not drain garbage when EOS occurs.
291 GST_START_TEST (test_parse_nb_drain_garbage)
293 GstElement *amrparse;
297 amrparse = setup_amrparse (&srctemplate_nb, &sinktemplate_nb);
299 for (i = 0; i < 10; i++) {
300 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, SRC_CAPS_NB);
301 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
304 /* Now push one garbage frame and then EOS */
305 buffer = buffer_new (garbage_frame, GARBAGE_FRAME_LEN, SRC_CAPS_NB);
306 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
307 gst_pad_push_event (srcpad, gst_event_new_eos ());
309 /* parser should have pushed only the valid frames */
310 fail_unless_equals_int (g_list_length (buffers), 10);
311 g_list_foreach (buffers, buffer_verify_nb, NULL);
313 cleanup_amrparse (amrparse);
320 * Test if NB parser splits a buffer that contains two frames into two
321 * separate buffers properly.
323 GST_START_TEST (test_parse_nb_split)
325 GstElement *amrparse;
329 amrparse = setup_amrparse (&srctemplate_nb, &sinktemplate_nb);
331 for (i = 0; i < 10; i++) {
332 /* Put two frames in one buffer */
333 buffer = buffer_new (frame_data_nb, 2 * FRAME_DATA_NB_LEN, SRC_CAPS_NB);
334 memcpy (GST_BUFFER_DATA (buffer) + FRAME_DATA_NB_LEN,
335 frame_data_nb, FRAME_DATA_NB_LEN);
336 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
338 gst_pad_push_event (srcpad, gst_event_new_eos ());
340 fail_unless_equals_int (g_list_length (buffers), 20);
342 /* Does output buffers contain correct frame data? */
343 g_list_foreach (buffers, buffer_verify_nb, NULL);
345 cleanup_amrparse (amrparse);
352 * Test if NB parser detects the format correctly.
354 GST_START_TEST (test_parse_nb_detect_stream)
356 GstElement *amrparse;
358 GstCaps *caps, *mycaps;
361 amrparse = setup_amrparse (&srctemplate_any, &sinktemplate_any);
363 /* Push the header */
364 buffer = buffer_new (frame_hdr_nb, FRAME_HDR_NB_LEN, NULL);
365 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
367 for (i = 0; i < 10; i++) {
368 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, NULL);
369 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
371 gst_pad_push_event (srcpad, gst_event_new_eos ());
373 caps = GST_PAD_CAPS (sinkpad);
374 mycaps = gst_caps_from_string (SINK_CAPS_NB);
375 fail_unless (gst_caps_is_equal (caps, mycaps));
376 gst_caps_unref (mycaps);
378 cleanup_amrparse (amrparse);
385 * Test if NB parser skips garbage in the datastream correctly and still
386 * finds all correct frames.
388 GST_START_TEST (test_parse_nb_skip_garbage)
390 buffer_verify_data_s vdata = { 5, GARBAGE_FRAME_LEN };
391 GstElement *amrparse;
395 amrparse = setup_amrparse (&srctemplate_nb, &sinktemplate_nb);
397 /* First push 5 healthy frames */
398 for (i = 0; i < 5; i++) {
399 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, SRC_CAPS_NB);
400 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
403 /* Then push some garbage */
404 buffer = buffer_new (garbage_frame, GARBAGE_FRAME_LEN, SRC_CAPS_NB);
405 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
407 /* Again, healthy frames */
408 for (i = 0; i < 5; i++) {
409 buffer = buffer_new (frame_data_nb, FRAME_DATA_NB_LEN, SRC_CAPS_NB);
410 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
413 gst_pad_push_event (srcpad, gst_event_new_eos ());
415 /* Did it find all 10 healthy frames? */
416 fail_unless_equals_int (g_list_length (buffers), 10);
417 g_list_foreach (buffers, buffer_verify_nb, &vdata);
419 cleanup_amrparse (amrparse);
426 * Test if WB parser manages to find all frames and pushes them forward.
428 GST_START_TEST (test_parse_wb_normal)
430 GstElement *amrparse;
434 amrparse = setup_amrparse (&srctemplate_wb, &sinktemplate_wb);
436 /* Push the header */
437 buffer = buffer_new (frame_hdr_wb, FRAME_HDR_WB_LEN, SRC_CAPS_WB);
438 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
439 offset_counter = FRAME_HDR_WB_LEN;
441 for (i = 0; i < 10; i++) {
442 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, SRC_CAPS_WB);
443 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
445 gst_pad_push_event (srcpad, gst_event_new_eos ());
447 fail_unless_equals_int (g_list_length (buffers), 10);
448 g_list_foreach (buffers, buffer_verify_wb, NULL);
450 cleanup_amrparse (amrparse);
457 * Test if WB parser drains its buffers properly. Even one single buffer
458 * should be drained and pushed forward when EOS occurs. This single buffer
459 * case is special, since normally the parser needs more data to be sure
460 * about stream format. But it should still push the frame forward in EOS.
462 GST_START_TEST (test_parse_wb_drain_single)
464 GstElement *amrparse;
467 amrparse = setup_amrparse (&srctemplate_wb, &sinktemplate_wb);
469 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, SRC_CAPS_WB);
470 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
471 gst_pad_push_event (srcpad, gst_event_new_eos ());
473 fail_unless_equals_int (g_list_length (buffers), 1);
474 g_list_foreach (buffers, buffer_verify_wb, NULL);
476 cleanup_amrparse (amrparse);
483 * Make sure that parser does not drain garbage when EOS occurs.
485 GST_START_TEST (test_parse_wb_drain_garbage)
487 GstElement *amrparse;
491 amrparse = setup_amrparse (&srctemplate_wb, &sinktemplate_wb);
493 for (i = 0; i < 10; i++) {
494 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, SRC_CAPS_WB);
495 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
498 /* Now push one garbage frame and then EOS */
499 buffer = buffer_new (garbage_frame, GARBAGE_FRAME_LEN, SRC_CAPS_WB);
500 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
501 gst_pad_push_event (srcpad, gst_event_new_eos ());
503 /* parser should have pushed only the valid frames */
504 fail_unless_equals_int (g_list_length (buffers), 10);
505 g_list_foreach (buffers, buffer_verify_wb, NULL);
507 cleanup_amrparse (amrparse);
514 * Test if WB parser splits a buffer that contains two frames into two
515 * separate buffers properly.
517 GST_START_TEST (test_parse_wb_split)
519 GstElement *amrparse;
523 amrparse = setup_amrparse (&srctemplate_wb, &sinktemplate_wb);
525 for (i = 0; i < 10; i++) {
526 /* Put two frames in one buffer */
527 buffer = buffer_new (frame_data_wb, 2 * FRAME_DATA_WB_LEN, SRC_CAPS_WB);
528 memcpy (GST_BUFFER_DATA (buffer) + FRAME_DATA_WB_LEN,
529 frame_data_wb, FRAME_DATA_WB_LEN);
530 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
532 gst_pad_push_event (srcpad, gst_event_new_eos ());
534 fail_unless_equals_int (g_list_length (buffers), 20);
536 /* Does output buffers contain correct frame data? */
537 g_list_foreach (buffers, buffer_verify_wb, NULL);
539 cleanup_amrparse (amrparse);
546 * Test if WB parser detects the format correctly.
548 GST_START_TEST (test_parse_wb_detect_stream)
550 GstElement *amrparse;
552 GstCaps *caps, *mycaps;
555 amrparse = setup_amrparse (&srctemplate_any, &sinktemplate_any);
557 /* Push the header */
558 buffer = buffer_new (frame_hdr_wb, FRAME_HDR_WB_LEN, NULL);
559 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
561 for (i = 0; i < 10; i++) {
562 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, NULL);
563 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
565 gst_pad_push_event (srcpad, gst_event_new_eos ());
567 caps = GST_PAD_CAPS (sinkpad);
568 mycaps = gst_caps_from_string (SINK_CAPS_WB);
569 fail_unless (gst_caps_is_equal (caps, mycaps));
570 gst_caps_unref (mycaps);
572 cleanup_amrparse (amrparse);
579 * Test if WB parser skips garbage in the datastream correctly and still
580 * finds all correct frames.
582 GST_START_TEST (test_parse_wb_skip_garbage)
584 buffer_verify_data_s vdata = { 5, GARBAGE_FRAME_LEN };
585 GstElement *amrparse;
589 amrparse = setup_amrparse (&srctemplate_wb, &sinktemplate_wb);
591 /* First push 5 healthy frames */
592 for (i = 0; i < 5; i++) {
593 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, SRC_CAPS_WB);
594 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
597 /* Then push some garbage */
598 buffer = buffer_new (garbage_frame, GARBAGE_FRAME_LEN, SRC_CAPS_WB);
599 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
601 /* Again, healthy frames */
602 for (i = 0; i < 5; i++) {
603 buffer = buffer_new (frame_data_wb, FRAME_DATA_WB_LEN, SRC_CAPS_WB);
604 fail_unless_equals_int (gst_pad_push (srcpad, buffer), GST_FLOW_OK);
607 gst_pad_push_event (srcpad, gst_event_new_eos ());
609 /* Did it find all 10 healthy frames? */
610 fail_unless_equals_int (g_list_length (buffers), 10);
611 g_list_foreach (buffers, buffer_verify_wb, &vdata);
613 cleanup_amrparse (amrparse);
623 amrparse_suite (void)
625 Suite *s = suite_create ("amrparse");
626 TCase *tc_chain = tcase_create ("general");
628 suite_add_tcase (s, tc_chain);
630 tcase_add_test (tc_chain, test_parse_nb_normal);
631 tcase_add_test (tc_chain, test_parse_nb_drain_single);
632 tcase_add_test (tc_chain, test_parse_nb_drain_garbage);
633 tcase_add_test (tc_chain, test_parse_nb_split);
634 tcase_add_test (tc_chain, test_parse_nb_detect_stream);
635 tcase_add_test (tc_chain, test_parse_nb_skip_garbage);
638 tcase_add_test (tc_chain, test_parse_wb_normal);
639 tcase_add_test (tc_chain, test_parse_wb_drain_single);
640 tcase_add_test (tc_chain, test_parse_wb_drain_garbage);
641 tcase_add_test (tc_chain, test_parse_wb_split);
642 tcase_add_test (tc_chain, test_parse_wb_detect_stream);
643 tcase_add_test (tc_chain, test_parse_wb_skip_garbage);
649 * - Both push- and pull-modes need to be tested
653 GST_CHECK_MAIN (amrparse);