1 /*
2  * GStreamer
3  *
4  * unit test for aacparse
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., 51 Franklin St, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25 
26 #include <gst/check/gstcheck.h>
27 #include <gst/check/check.h>
28 #include "parser.h"
29 
30 #define SRC_CAPS_CDATA "audio/mpeg, mpegversion=(int)4, framed=(boolean)false, codec_data=(buffer)1190"
31 #define SRC_CAPS_TMPL  "audio/mpeg, framed=(boolean)false, mpegversion=(int){2,4}"
32 #define SRC_CAPS_RAW   "audio/mpeg, mpegversion=(int)4, framed=(boolean)true, stream-format=(string)raw, rate=(int)48000, channels=(int)2, codec_data=(buffer)1190"
33 
34 #define SINK_CAPS \
35     "audio/mpeg, framed=(boolean)true"
36 #define SINK_CAPS_MPEG2 \
37     "audio/mpeg, framed=(boolean)true, mpegversion=2, rate=48000, channels=2"
38 #define SINK_CAPS_MPEG4 \
39     "audio/mpeg, framed=(boolean)true, mpegversion=4, rate=96000, channels=2"
40 #define SINK_CAPS_TMPL  "audio/mpeg, framed=(boolean)true, mpegversion=(int){2,4}"
41 
42 GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
43     GST_PAD_SINK,
44     GST_PAD_ALWAYS,
45     GST_STATIC_CAPS (SINK_CAPS_TMPL)
46     );
47 
48 GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
49     GST_PAD_SRC,
50     GST_PAD_ALWAYS,
51     GST_STATIC_CAPS (SRC_CAPS_TMPL)
52     );
53 
54 /* some data */
55 static guint8 adif_header[] = {
56   'A', 'D', 'I', 'F'
57 };
58 
59 static guint8 adts_frame_mpeg2[] = {
60   0xff, 0xf9, 0x4c, 0x80, 0x01, 0xff, 0xfc, 0x21, 0x10, 0xd3, 0x20, 0x0c,
61   0x32, 0x00, 0xc7
62 };
63 
64 static guint8 adts_frame_mpeg4[] = {
65   0xff, 0xf1, 0x4c, 0x80, 0x01, 0xff, 0xfc, 0x21, 0x10, 0xd3, 0x20, 0x0c,
66   0x32, 0x00, 0xc7
67 };
68 
69 static guint8 garbage_frame[] = {
70   0xff, 0xff, 0xff, 0xff, 0xff
71 };
72 
73 static guint8 raw_frame_short[] = {
74   0x27, 0x00, 0x03, 0x20, 0x64, 0x1c
75 };
76 
77 /*
78  * Test if the parser pushes data with ADIF header properly and detects the
79  * stream to MPEG4 properly.
80  */
GST_START_TEST(test_parse_adif_normal)81 GST_START_TEST (test_parse_adif_normal)
82 {
83   GstParserTest ptest;
84 
85   /* ADIF header */
86   gst_parser_test_init (&ptest, adif_header, sizeof (adif_header), 1);
87   /* well, no garbage, followed by random data */
88   ptest.series[2].size = 100;
89   ptest.series[2].num = 3;
90   /* and we do not really expect output frames */
91   ptest.framed = FALSE;
92   /* Check that the negotiated caps are as expected */
93   /* For ADIF parser assumes that data is always version 4 */
94   ptest.sink_caps =
95       gst_caps_from_string (SINK_CAPS_MPEG4 ", stream-format=(string)adif");
96 
97   gst_parser_test_run (&ptest, NULL);
98 
99   gst_caps_unref (ptest.sink_caps);
100 }
101 
102 GST_END_TEST;
103 
104 
GST_START_TEST(test_parse_adts_normal)105 GST_START_TEST (test_parse_adts_normal)
106 {
107   gst_parser_test_normal (adts_frame_mpeg4, sizeof (adts_frame_mpeg4));
108 }
109 
110 GST_END_TEST;
111 
112 
GST_START_TEST(test_parse_adts_drain_single)113 GST_START_TEST (test_parse_adts_drain_single)
114 {
115   gst_parser_test_drain_single (adts_frame_mpeg4, sizeof (adts_frame_mpeg4));
116 }
117 
118 GST_END_TEST;
119 
120 
GST_START_TEST(test_parse_adts_drain_garbage)121 GST_START_TEST (test_parse_adts_drain_garbage)
122 {
123   gst_parser_test_drain_garbage (adts_frame_mpeg4, sizeof (adts_frame_mpeg4),
124       garbage_frame, sizeof (garbage_frame));
125 }
126 
127 GST_END_TEST;
128 
129 
GST_START_TEST(test_parse_adts_split)130 GST_START_TEST (test_parse_adts_split)
131 {
132   gst_parser_test_split (adts_frame_mpeg4, sizeof (adts_frame_mpeg4));
133 }
134 
135 GST_END_TEST;
136 
137 
GST_START_TEST(test_parse_adts_skip_garbage)138 GST_START_TEST (test_parse_adts_skip_garbage)
139 {
140   gst_parser_test_skip_garbage (adts_frame_mpeg4, sizeof (adts_frame_mpeg4),
141       garbage_frame, sizeof (garbage_frame));
142 }
143 
144 GST_END_TEST;
145 
146 
147 /*
148  * Test if the src caps are set according to stream format (MPEG version).
149  */
GST_START_TEST(test_parse_adts_detect_mpeg_version)150 GST_START_TEST (test_parse_adts_detect_mpeg_version)
151 {
152   gst_parser_test_output_caps (adts_frame_mpeg2, sizeof (adts_frame_mpeg2),
153       NULL,
154       SINK_CAPS_MPEG2
155       ", stream-format=(string)adts, level=(string)2, profile=(string)lc");
156 }
157 
158 GST_END_TEST;
159 
160 /*
161  * Test if the parser correctly handles short raw frames and doesn't
162  * concatenate them.
163  */
GST_START_TEST(test_parse_raw_short)164 GST_START_TEST (test_parse_raw_short)
165 {
166   GstHarness *h = gst_harness_new ("aacparse");
167   GstBuffer *in_buf;
168 
169   g_object_set (h->element, "disable-passthrough", TRUE, NULL);
170   gst_harness_set_src_caps_str (h, SRC_CAPS_RAW);
171 
172   in_buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
173       raw_frame_short, sizeof raw_frame_short, 0, sizeof raw_frame_short,
174       NULL, NULL);
175 
176   gst_harness_push (h, gst_buffer_ref (in_buf));
177   fail_unless_equals_int (gst_harness_buffers_received (h), 1);
178 
179   gst_harness_push (h, in_buf);
180   fail_unless_equals_int (gst_harness_buffers_received (h), 2);
181 
182   gst_harness_push_event (h, gst_event_new_eos ());
183   fail_unless_equals_int (gst_harness_buffers_received (h), 2);
184 
185   gst_harness_teardown (h);
186 }
187 
188 GST_END_TEST;
189 
190 #define structure_get_int(s,f) \
191     (g_value_get_int(gst_structure_get_value(s,f)))
192 #define fail_unless_structure_field_int_equals(s,field,num) \
193     fail_unless_equals_int (structure_get_int(s,field), num)
194 /*
195  * Test if the parser handles raw stream and codec_data info properly.
196  */
GST_START_TEST(test_parse_handle_codec_data)197 GST_START_TEST (test_parse_handle_codec_data)
198 {
199   GstCaps *caps;
200   GstStructure *s;
201   const gchar *stream_format;
202 
203   /* Push random data. It should get through since the parser should be
204    * initialized because it got codec_data in the caps */
205   caps = gst_parser_test_get_output_caps (NULL, 100, SRC_CAPS_CDATA);
206   fail_unless (caps != NULL);
207 
208   /* Check that the negotiated caps are as expected */
209   /* When codec_data is present, parser assumes that data is version 4 */
210   GST_LOG ("aac output caps: %" GST_PTR_FORMAT, caps);
211   s = gst_caps_get_structure (caps, 0);
212   fail_unless (gst_structure_has_name (s, "audio/mpeg"));
213   fail_unless_structure_field_int_equals (s, "mpegversion", 4);
214   fail_unless_structure_field_int_equals (s, "channels", 2);
215   fail_unless_structure_field_int_equals (s, "rate", 48000);
216   fail_unless (gst_structure_has_field (s, "codec_data"));
217   fail_unless (gst_structure_has_field (s, "stream-format"));
218   stream_format = gst_structure_get_string (s, "stream-format");
219   fail_unless (strcmp (stream_format, "raw") == 0);
220 
221   gst_caps_unref (caps);
222 }
223 
224 GST_END_TEST;
225 
GST_START_TEST(test_parse_proxy_constraints)226 GST_START_TEST (test_parse_proxy_constraints)
227 {
228   GstCaps *caps, *resultcaps;
229   GstElement *parse, *filter;
230   GstPad *sinkpad;
231   GstStructure *s;
232 
233   parse = gst_element_factory_make ("aacparse", NULL);
234   filter = gst_element_factory_make ("capsfilter", NULL);
235 
236   /* constraint on rate and version */
237   caps = gst_caps_from_string ("audio/mpeg,mpegversion=2,rate=44100");
238   g_object_set (filter, "caps", caps, NULL);
239   gst_caps_unref (caps);
240 
241   gst_element_link (parse, filter);
242 
243   sinkpad = gst_element_get_static_pad (parse, "sink");
244   caps = gst_pad_query_caps (sinkpad, NULL);
245   GST_LOG ("caps %" GST_PTR_FORMAT, caps);
246 
247   fail_unless (gst_caps_get_size (caps) == 1);
248 
249   /* getcaps should proxy the rate constraint */
250   s = gst_caps_get_structure (caps, 0);
251   fail_unless (gst_structure_has_name (s, "audio/mpeg"));
252   fail_unless_structure_field_int_equals (s, "rate", 44100);
253   gst_caps_unref (caps);
254 
255   /* should accept without the constraint */
256   caps = gst_caps_from_string ("audio/mpeg,mpegversion=2");
257   resultcaps = gst_pad_query_caps (sinkpad, caps);
258   fail_if (gst_caps_is_empty (resultcaps));
259   gst_caps_unref (resultcaps);
260   gst_caps_unref (caps);
261 
262   /* should not accept with conflicting version */
263   caps = gst_caps_from_string ("audio/mpeg,mpegversion=4");
264   resultcaps = gst_pad_query_caps (sinkpad, caps);
265   fail_unless (gst_caps_is_empty (resultcaps));
266   gst_caps_unref (resultcaps);
267   gst_caps_unref (caps);
268 
269   gst_object_unref (sinkpad);
270 
271   gst_object_unref (filter);
272   gst_object_unref (parse);
273 }
274 
275 GST_END_TEST;
276 
277 static Suite *
aacparse_suite(void)278 aacparse_suite (void)
279 {
280   Suite *s = suite_create ("aacparse");
281   TCase *tc_chain = tcase_create ("general");
282 
283   /* init test context */
284   ctx_factory = "aacparse";
285   ctx_sink_template = &sinktemplate;
286   ctx_src_template = &srctemplate;
287 
288   suite_add_tcase (s, tc_chain);
289   /* ADIF tests */
290   tcase_add_test (tc_chain, test_parse_adif_normal);
291 
292   /* ADTS tests */
293   tcase_add_test (tc_chain, test_parse_adts_normal);
294   tcase_add_test (tc_chain, test_parse_adts_drain_single);
295   tcase_add_test (tc_chain, test_parse_adts_drain_garbage);
296   tcase_add_test (tc_chain, test_parse_adts_split);
297   tcase_add_test (tc_chain, test_parse_adts_skip_garbage);
298   tcase_add_test (tc_chain, test_parse_adts_detect_mpeg_version);
299 
300   /* Raw tests */
301   tcase_add_test (tc_chain, test_parse_raw_short);
302 
303   /* Other tests */
304   tcase_add_test (tc_chain, test_parse_handle_codec_data);
305 
306   /* caps tests */
307   tcase_add_test (tc_chain, test_parse_proxy_constraints);
308 
309   return s;
310 }
311 
312 
313 /*
314  * TODO:
315  *   - Both push- and pull-modes need to be tested
316  *      * Pull-mode & EOS
317  */
318 GST_CHECK_MAIN (aacparse);
319