1 /*
2  * GStreamer
3  *
4  * unit test for flacparse
5  *
6  * Copyright (C) 2010 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 "parser.h"
28 
29 #define SRC_CAPS_TMPL  "audio/x-flac, framed=(boolean)false"
30 #define SINK_CAPS_TMPL  "audio/x-flac, framed=(boolean)true"
31 
32 GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
33     GST_PAD_SINK,
34     GST_PAD_ALWAYS,
35     GST_STATIC_CAPS (SINK_CAPS_TMPL)
36     );
37 
38 GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
39     GST_PAD_SRC,
40     GST_PAD_ALWAYS,
41     GST_STATIC_CAPS (SRC_CAPS_TMPL)
42     );
43 
44 /* some data */
45 static guint8 streaminfo_header[] = {
46   0x7f, 0x46, 0x4c, 0x41, 0x43, 0x01, 0x00, 0x00,
47   0x02, 0x66, 0x4c, 0x61, 0x43, 0x00, 0x00, 0x00,
48   0x22, 0x12, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00,
49   0x00, 0x00, 0x00, 0x0a, 0xc4, 0x40, 0xf0, 0x00,
50   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52   0x00, 0x00, 0x00
53 };
54 
55 static guint8 comment_header[] = {
56   0x84, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
57   0x00, 0x00, 0x00, 0x00
58 };
59 
60 static guint8 flac_frame[] = {
61   0xff, 0xf8, 0xa9, 0x08, 0x00, 0x50, 0x18, 0x06,
62   0x6a, 0x0c, 0xce, 0x13, 0x24, 0x19, 0x68, 0x00,
63   0x46, 0x23, 0x08, 0xca, 0xcb, 0x58, 0x9c, 0x26,
64   0x92, 0x30, 0xa6, 0x29, 0x8a, 0xca, 0xd1, 0x18,
65   0xae, 0x26, 0x5c, 0x90, 0x60, 0xbf, 0x11, 0xad,
66   0x43, 0x02, 0x06, 0x26, 0xbd, 0x35, 0xdd, 0xa3,
67   0x11, 0xa6, 0x4d, 0x18, 0x8c, 0x9a, 0xe4, 0x62,
68   0xd9, 0x23, 0x11, 0x8b, 0xcb, 0x56, 0x55, 0x45,
69   0xc2, 0x18, 0x56, 0xa2, 0xe2, 0xe1, 0x18, 0x99,
70   0x54, 0x98, 0x46, 0x4d, 0x08, 0x70, 0x9a, 0x64,
71   0xc4, 0x18, 0x4f, 0x27, 0x64, 0x31, 0x66, 0x27,
72   0x79, 0x19, 0x3c, 0x8c, 0x8c, 0xa3, 0x44, 0x18,
73   0x23, 0xd2, 0x6b, 0x8b, 0x64, 0x8c, 0x21, 0x84,
74   0xd6, 0x23, 0x13, 0x13, 0x2d, 0x44, 0xca, 0x5a,
75   0x23, 0x09, 0x93, 0x25, 0x18, 0x10, 0x61, 0x38,
76   0xb4, 0x60, 0x8f, 0x2c, 0x8d, 0x26, 0xb4, 0xc9,
77   0xd9, 0x19, 0x19, 0x34, 0xd7, 0x31, 0x06, 0x10,
78   0xc4, 0x30, 0x83, 0x17, 0xe2, 0x0c, 0x2c, 0xc4,
79   0xc8, 0xc9, 0x3c, 0x5e, 0x93, 0x11, 0x8a, 0x62,
80   0x64, 0x8c, 0x26, 0x23, 0x22, 0x30, 0x9a, 0x58,
81   0x86, 0x04, 0x18, 0x4c, 0xab, 0x2b, 0x26, 0x5c,
82   0x46, 0x88, 0xcb, 0xb1, 0x0d, 0x26, 0xbb, 0x5e,
83   0x8c, 0xa7, 0x64, 0x31, 0x3d, 0x31, 0x06, 0x26,
84   0x43, 0x17, 0xa3, 0x08, 0x61, 0x06, 0x17, 0xc4,
85   0x62, 0xec, 0x4d, 0x4b, 0x2e, 0x2d, 0x4a, 0x94,
86   0xa4, 0xc2, 0x31, 0x4c, 0x4c, 0x20, 0xc0, 0x83,
87   0x14, 0x8c, 0x27, 0x8b, 0x31, 0x23, 0x2f, 0x23,
88   0x11, 0x91, 0x94, 0x65, 0x1a, 0x20, 0xc2, 0x18,
89   0x86, 0x51, 0x88, 0x62, 0x7c, 0x43, 0x2e, 0xa3,
90   0x04, 0x18, 0x8c, 0x20, 0xc2, 0xf5, 0xaa, 0x94,
91   0xc2, 0x31, 0x32, 0xd2, 0xb2, 0xa2, 0x30, 0xba,
92   0x10, 0xc2, 0xb5, 0x89, 0xa5, 0x18, 0x10, 0x62,
93   0x9a, 0x10, 0x61, 0x19, 0x72, 0x71, 0x1a, 0xb9,
94   0x0c, 0x23, 0x46, 0x10, 0x62, 0x78, 0x81, 0x82,
95   0x3d, 0x75, 0xea, 0x6b, 0x51, 0x8b, 0x61, 0x06,
96   0x08, 0x62, 0x32, 0x5e, 0x84, 0x18, 0x27, 0x25,
97   0xc2, 0x6a, 0x4b, 0x51, 0x31, 0x34, 0x5e, 0x29,
98   0xa1, 0x3c, 0x4d, 0x26, 0x23, 0x10, 0xc2, 0x6b,
99   0xb1, 0x0d, 0x11, 0xae, 0x46, 0x88, 0x31, 0x35,
100   0xb1, 0x06, 0x08, 0x79, 0x7e, 0x4f, 0x53, 0x23,
101   0x29, 0xa4, 0x30, 0x20, 0x30, 0x23, 0x5a, 0xb2,
102   0xc8, 0x60, 0x9c, 0x93, 0x13, 0x17, 0x92, 0x98,
103   0x46, 0x13, 0x54, 0x53, 0x08, 0xcb, 0x13, 0xa1,
104   0x1a, 0x89, 0xe5, 0x46, 0x08, 0x18, 0x10, 0x30,
105   0x9d, 0x68, 0xc2, 0x1c, 0x46, 0x46, 0xae, 0x62,
106   0x1a, 0x46, 0x4e, 0x4d, 0x34, 0x8c, 0xbd, 0x26,
107   0xc0, 0x40, 0x62, 0xc9, 0xa9, 0x31, 0x74, 0xa8,
108   0x99, 0x52, 0xb0, 0x8c, 0xa9, 0x29, 0x84, 0x61,
109   0x19, 0x54, 0x43, 0x02, 0x06, 0x04, 0x32, 0xe5,
110   0x18, 0x21, 0x91, 0x8b, 0xf2, 0xcc, 0x10, 0x30,
111   0x8e, 0x23, 0xc4, 0x76, 0x43, 0x08, 0x30, 0x83,
112   0x08, 0x62, 0x6c, 0x4e, 0xe2, 0x35, 0x96, 0xd0,
113   0x8e, 0x89, 0x97, 0x42, 0x18, 0x91, 0x84, 0x61,
114   0x3c, 0x26, 0xa5, 0x2c, 0x4e, 0x17, 0x94, 0xb8,
115   0xb5, 0xa4, 0xcb, 0x88, 0xc9, 0x84, 0x18, 0xb9,
116   0x84, 0x19, 0x23, 0x2d, 0xa4, 0x64, 0x62, 0x18,
117   0x86, 0x53, 0x93, 0xcb, 0x30, 0x8f, 0x2f, 0x93,
118   0x55, 0xc4, 0xd7, 0x08, 0x62, 0xb8, 0x46, 0x84,
119   0x68, 0xa3, 0x02, 0xaf, 0x33
120 };
121 
122 static guint8 garbage_frame[] = {
123   0xff, 0xff, 0xff, 0xff, 0xff
124 };
125 
126 
GST_START_TEST(test_parse_flac_normal)127 GST_START_TEST (test_parse_flac_normal)
128 {
129   gst_parser_test_normal (flac_frame, sizeof (flac_frame));
130 }
131 
132 GST_END_TEST;
133 
134 
GST_START_TEST(test_parse_flac_drain_single)135 GST_START_TEST (test_parse_flac_drain_single)
136 {
137   gst_parser_test_drain_single (flac_frame, sizeof (flac_frame));
138 }
139 
140 GST_END_TEST;
141 
142 
GST_START_TEST(test_parse_flac_drain_garbage)143 GST_START_TEST (test_parse_flac_drain_garbage)
144 {
145   /* We always output the after frame garbage too because we
146    * have no way of detecting it
147    */
148 #if 0
149   gst_parser_test_drain_garbage (flac_frame, sizeof (flac_frame),
150       garbage_frame, sizeof (garbage_frame));
151 #endif
152   guint8 frame[sizeof (flac_frame) + sizeof (garbage_frame)];
153 
154   memcpy (frame, flac_frame, sizeof (flac_frame));
155   memcpy (frame + sizeof (flac_frame), garbage_frame, sizeof (garbage_frame));
156 
157   gst_parser_test_drain_single (frame, sizeof (frame));
158 }
159 
160 GST_END_TEST;
161 
162 
GST_START_TEST(test_parse_flac_split)163 GST_START_TEST (test_parse_flac_split)
164 {
165   gst_parser_test_split (flac_frame, sizeof (flac_frame));
166 }
167 
168 GST_END_TEST;
169 
170 
GST_START_TEST(test_parse_flac_skip_garbage)171 GST_START_TEST (test_parse_flac_skip_garbage)
172 {
173   /* We always include the garbage into the frame because
174    * we have no easy way for finding the real end of the
175    * frame. The decoder will later skip the garbage
176    */
177 #if 0
178   gst_parser_test_skip_garbage (flac_frame, sizeof (flac_frame),
179       garbage_frame, sizeof (garbage_frame));
180 #endif
181   guint8 frame[sizeof (flac_frame) + sizeof (garbage_frame)];
182 
183   memcpy (frame, flac_frame, sizeof (flac_frame));
184   memcpy (frame + sizeof (flac_frame), garbage_frame, sizeof (garbage_frame));
185 
186   gst_parser_test_normal (frame, sizeof (frame));
187 }
188 
189 GST_END_TEST;
190 
191 
192 #define structure_get_int(s,f) \
193     (g_value_get_int(gst_structure_get_value(s,f)))
194 #define fail_unless_structure_field_int_equals(s,field,num) \
195     fail_unless_equals_int (structure_get_int(s,field), num)
196 /*
197  * Test if the parser handles raw stream and codec_data info properly.
198  */
GST_START_TEST(test_parse_flac_detect_stream)199 GST_START_TEST (test_parse_flac_detect_stream)
200 {
201   GstCaps *caps;
202   GstStructure *s;
203   const GValue *streamheader;
204   GArray *bufarr;
205   gint i;
206 
207   /* Push random data. It should get through since the parser should be
208    * initialized because it got codec_data in the caps */
209   caps = gst_parser_test_get_output_caps (flac_frame, sizeof (flac_frame),
210       SRC_CAPS_TMPL);
211   fail_unless (caps != NULL);
212 
213   /* Check that the negotiated caps are as expected */
214   /* When codec_data is present, parser assumes that data is version 4 */
215   GST_LOG ("flac output caps: %" GST_PTR_FORMAT, caps);
216   s = gst_caps_get_structure (caps, 0);
217   fail_unless (gst_structure_has_name (s, "audio/x-flac"));
218   fail_unless_structure_field_int_equals (s, "channels", 1);
219   fail_unless_structure_field_int_equals (s, "rate", 44100);
220   fail_unless (gst_structure_has_field (s, "streamheader"));
221   streamheader = gst_structure_get_value (s, "streamheader");
222   fail_unless (G_VALUE_TYPE (streamheader) == GST_TYPE_ARRAY);
223   bufarr = g_value_peek_pointer (streamheader);
224   fail_unless (bufarr->len == 2);
225   for (i = 0; i < bufarr->len; i++) {
226     GstBuffer *buf;
227     GValue *bufval = &g_array_index (bufarr, GValue, i);
228 
229     fail_unless (G_VALUE_TYPE (bufval) == GST_TYPE_BUFFER);
230     buf = g_value_peek_pointer (bufval);
231     if (i == 0) {
232       fail_unless (gst_buffer_get_size (buf) == sizeof (streaminfo_header));
233       fail_unless (gst_buffer_memcmp (buf, 0, streaminfo_header,
234               sizeof (streaminfo_header)) == 0);
235     } else if (i == 1) {
236       fail_unless (gst_buffer_get_size (buf) == sizeof (comment_header));
237       fail_unless (gst_buffer_memcmp (buf, 0, comment_header,
238               sizeof (comment_header)) == 0);
239     }
240   }
241 
242   gst_caps_unref (caps);
243 }
244 
245 GST_END_TEST;
246 
247 static Suite *
flacparse_suite(void)248 flacparse_suite (void)
249 {
250   Suite *s = suite_create ("flacparse");
251   TCase *tc_chain = tcase_create ("general");
252 
253 
254   /* init test context */
255   ctx_factory = "flacparse";
256   ctx_sink_template = &sinktemplate;
257   ctx_src_template = &srctemplate;
258   ctx_discard = 3;
259   ctx_headers[0].data = streaminfo_header;
260   ctx_headers[0].size = sizeof (streaminfo_header);
261   ctx_headers[1].data = comment_header;
262   ctx_headers[1].size = sizeof (comment_header);
263 
264   /* custom offsets, and ts always repeatedly 0 */
265   ctx_no_metadata = TRUE;
266   suite_add_tcase (s, tc_chain);
267   tcase_add_test (tc_chain, test_parse_flac_normal);
268   tcase_add_test (tc_chain, test_parse_flac_drain_single);
269   tcase_add_test (tc_chain, test_parse_flac_drain_garbage);
270   tcase_add_test (tc_chain, test_parse_flac_split);
271   tcase_add_test (tc_chain, test_parse_flac_skip_garbage);
272 
273   /* Other tests */
274   tcase_add_test (tc_chain, test_parse_flac_detect_stream);
275 
276   return s;
277 }
278 
279 
280 /*
281  * TODO:
282  *   - Both push- and pull-modes need to be tested
283  *      * Pull-mode & EOS
284  */
285 GST_CHECK_MAIN (flacparse);
286