1 /* GStreamer
2 *
3 * unit test for vorbisdec
4 *
5 * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <glib.h>
27
28 #include <vorbis/codec.h>
29 #include <vorbis/vorbisenc.h>
30
31 #include <gst/gsttagsetter.h>
32 #include <gst/check/gstcheck.h>
33
34 /* a valid first header packet */
35 static guchar identification_header[30] = {
36 1, /* packet_type */
37 'v', 'o', 'r', 'b', 'i', 's',
38 0, 0, 0, 0, /* vorbis_version */
39 2, /* audio_channels */
40 0x44, 0xac, 0, 0, /* sample_rate */
41 0xff, 0xff, 0xff, 0xff, /* bitrate_maximum */
42 0x00, 0xee, 0x02, 0x00, /* bitrate_nominal */
43 0xff, 0xff, 0xff, 0xff, /* bitrate_minimum */
44 0xb8, /* blocksize_0, blocksize_1 */
45 0x01 /* framing_flag */
46 };
47
48 static guchar artist_comment_header[] = {
49 3, /* packet_type */
50 'v', 'o', 'r', 'b', 'i', 's',
51 2, 0, 0, 0, /* vendor_length */
52 'm', 'e',
53 1, 0, 0, 0, /* user_comment_list_length */
54 9, 0, 0, 0, /* length comment[0] */
55 'A', 'R', 'T', 'I', 'S', 'T', '=', 'm', 'e',
56 0x01, /* framing bit */
57 };
58
59 static guchar title_comment_header[] = {
60 3, /* packet_type */
61 'v', 'o', 'r', 'b', 'i', 's',
62 2, 0, 0, 0, /* vendor_length */
63 'm', 'e',
64 1, 0, 0, 0, /* user_comment_list_length */
65 12, 0, 0, 0, /* length comment[0] */
66 'T', 'I', 'T', 'L', 'E', '=', 'f', 'o', 'o', 'b', 'a', 'r',
67 0x01, /* framing bit */
68 };
69
70 static guchar empty_comment_header[] = {
71 3, /* packet_type */
72 'v', 'o', 'r', 'b', 'i', 's',
73 2, 0, 0, 0, /* vendor_length */
74 'm', 'e',
75 0, 0, 0, 0, /* user_comment_list_length */
76 0x01, /* framing bit */
77 };
78
79
80 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
81 GST_PAD_SINK,
82 GST_PAD_ALWAYS,
83 GST_STATIC_CAPS_ANY);
84 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
85 GST_PAD_SRC,
86 GST_PAD_ALWAYS,
87 GST_STATIC_CAPS_ANY);
88
89 static GstPad *mysrcpad, *mysinkpad;
90 static GAsyncQueue *pending_buffers;
91 static gulong id;
92
93
94 static GstElement *
setup_vorbistag(void)95 setup_vorbistag (void)
96 {
97 GstElement *vorbistag;
98 GstCaps *caps;
99
100 GST_DEBUG ("setup_vorbistag");
101 vorbistag = gst_check_setup_element ("vorbistag");
102 mysrcpad = gst_check_setup_src_pad (vorbistag, &srctemplate);
103 mysinkpad = gst_check_setup_sink_pad (vorbistag, &sinktemplate);
104 gst_pad_set_active (mysrcpad, TRUE);
105
106 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
107 gst_check_setup_events (mysrcpad, vorbistag, caps, GST_FORMAT_TIME);
108 gst_caps_unref (caps);
109
110 gst_pad_set_active (mysinkpad, TRUE);
111
112 return vorbistag;
113 }
114
115 static void
cleanup_vorbistag(GstElement * vorbistag)116 cleanup_vorbistag (GstElement * vorbistag)
117 {
118 GST_DEBUG ("cleanup_vorbistag");
119 gst_element_set_state (vorbistag, GST_STATE_NULL);
120
121 gst_pad_set_active (mysrcpad, FALSE);
122 gst_pad_set_active (mysinkpad, FALSE);
123 gst_check_drop_buffers ();
124 gst_check_teardown_src_pad (vorbistag);
125 gst_check_teardown_sink_pad (vorbistag);
126 gst_check_teardown_element (vorbistag);
127 }
128
129
130 static GstPadProbeReturn
buffer_probe(GstPad * pad,GstPadProbeInfo * info,gpointer unused)131 buffer_probe (GstPad * pad, GstPadProbeInfo * info, gpointer unused)
132 {
133 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
134
135 g_async_queue_push (pending_buffers, gst_buffer_ref (buffer));
136
137 return GST_PAD_PROBE_OK;
138 }
139
140 static void
start_pipeline(GstElement * element)141 start_pipeline (GstElement * element)
142 {
143 id = gst_pad_add_probe (mysinkpad, GST_PAD_PROBE_TYPE_BUFFER,
144 (GstPadProbeCallback) buffer_probe, NULL, NULL);
145
146 pending_buffers = g_async_queue_new ();
147 gst_element_set_state (element, GST_STATE_PLAYING);
148 }
149
150 static GstBuffer *
get_buffer(void)151 get_buffer (void)
152 {
153 return GST_BUFFER (g_async_queue_pop (pending_buffers));
154 }
155
156 static void
stop_pipeline(GstElement * element)157 stop_pipeline (GstElement * element)
158 {
159 GstBuffer *buf;
160
161 while ((buf = g_async_queue_try_pop (pending_buffers)))
162 gst_buffer_unref (buf);
163
164 gst_pad_remove_probe (mysinkpad, id);
165 id = 0;
166
167 gst_element_set_state (element, GST_STATE_NULL);
168
169 while ((buf = g_async_queue_try_pop (pending_buffers)))
170 gst_buffer_unref (buf);
171
172 g_async_queue_unref (pending_buffers);
173 pending_buffers = NULL;
174 }
175
176 static void
compare_buffer(GstBuffer * buf,const guint8 * data,gsize size)177 compare_buffer (GstBuffer * buf, const guint8 * data, gsize size)
178 {
179 GstMapInfo map;
180
181 gst_buffer_map (buf, &map, GST_MAP_READ);
182 fail_unless_equals_int (map.size, size);
183 fail_unless_equals_int (memcmp (map.data, data, size), 0);
184 gst_buffer_unmap (buf, &map);
185 }
186
187 static vorbis_comment vc;
188 static vorbis_dsp_state vd;
189 static vorbis_info vi;
190 static vorbis_block vb;
191
192 static GstBuffer *
_create_codebook_header_buffer(void)193 _create_codebook_header_buffer (void)
194 {
195 GstBuffer *buffer;
196 ogg_packet header;
197 ogg_packet header_comm;
198 ogg_packet header_code;
199
200 vorbis_info_init (&vi);
201 vorbis_encode_setup_vbr (&vi, 1, 44000, 0.5);
202 vorbis_encode_setup_init (&vi);
203 vorbis_analysis_init (&vd, &vi);
204 vorbis_block_init (&vd, &vb);
205 vorbis_comment_init (&vc);
206 vorbis_analysis_headerout (&vd, &vc, &header, &header_comm, &header_code);
207
208 buffer = gst_buffer_new_and_alloc (header_code.bytes);
209 gst_buffer_fill (buffer, 0, header_code.packet, header_code.bytes);
210
211 return buffer;
212 }
213
214 static GstBuffer *
_create_audio_buffer(void)215 _create_audio_buffer (void)
216 {
217 GstBuffer *buffer;
218 ogg_packet packet;
219 float **vorbis_buffer G_GNUC_UNUSED;
220
221 vorbis_buffer = vorbis_analysis_buffer (&vd, 0);
222 vorbis_analysis_wrote (&vd, 0);
223 vorbis_analysis_blockout (&vd, &vb);
224 vorbis_analysis (&vb, NULL);
225 vorbis_bitrate_addblock (&vb);
226 vorbis_bitrate_flushpacket (&vd, &packet);
227 buffer = gst_buffer_new_and_alloc (packet.bytes);
228 gst_buffer_fill (buffer, 0, packet.packet, packet.bytes);
229 GST_DEBUG ("%p %ld", packet.packet, packet.bytes);
230
231 vorbis_comment_clear (&vc);
232 vorbis_block_clear (&vb);
233 vorbis_dsp_clear (&vd);
234 vorbis_info_clear (&vi);
235
236 return buffer;
237 }
238
239
GST_START_TEST(test_empty_tags_set)240 GST_START_TEST (test_empty_tags_set)
241 {
242 GstTagList *tags;
243 GstElement *vorbistag;
244 GstBuffer *inbuffer, *outbuffer;
245
246 vorbistag = setup_vorbistag ();
247
248 tags = gst_tag_list_new_empty ();
249 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, "foobar", NULL);
250 gst_tag_setter_merge_tags (GST_TAG_SETTER (vorbistag), tags,
251 GST_TAG_MERGE_REPLACE);
252 gst_tag_setter_set_tag_merge_mode (GST_TAG_SETTER (vorbistag),
253 GST_TAG_MERGE_KEEP_ALL);
254 gst_tag_list_unref (tags);
255
256 start_pipeline (vorbistag);
257
258 /* send identification header */
259 inbuffer = gst_buffer_new_and_alloc (sizeof (identification_header));
260 gst_buffer_fill (inbuffer, 0, identification_header,
261 sizeof (identification_header));
262 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
263
264 /* send empty comment buffer */
265 inbuffer = gst_buffer_new_and_alloc (sizeof (empty_comment_header));
266 gst_buffer_fill (inbuffer, 0, empty_comment_header,
267 sizeof (empty_comment_header));
268 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
269
270 /* send minimal codebook header and audio packers */
271 inbuffer = _create_codebook_header_buffer ();
272 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
273 inbuffer = _create_audio_buffer ();
274 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
275
276
277 /* check identification header is unchanged */
278 outbuffer = get_buffer ();
279 compare_buffer (outbuffer, identification_header,
280 sizeof (identification_header));
281 gst_buffer_unref (outbuffer);
282
283 /* check comment header is correct */
284 outbuffer = get_buffer ();
285 compare_buffer (outbuffer, title_comment_header,
286 sizeof (title_comment_header));
287 gst_buffer_unref (outbuffer);
288
289 stop_pipeline (vorbistag);
290 cleanup_vorbistag (vorbistag);
291 }
292
293 GST_END_TEST;
294
295
GST_START_TEST(test_filled_tags_unset)296 GST_START_TEST (test_filled_tags_unset)
297 {
298 GstTagList *tags;
299 GstElement *vorbistag;
300 GstBuffer *inbuffer, *outbuffer;
301
302 vorbistag = setup_vorbistag ();
303
304 tags = gst_tag_list_new_empty ();
305 gst_tag_setter_merge_tags (GST_TAG_SETTER (vorbistag), tags,
306 GST_TAG_MERGE_REPLACE);
307 gst_tag_setter_set_tag_merge_mode (GST_TAG_SETTER (vorbistag),
308 GST_TAG_MERGE_KEEP_ALL);
309 gst_tag_list_unref (tags);
310
311 start_pipeline (vorbistag);
312
313 /* send identification header */
314 inbuffer = gst_buffer_new_and_alloc (sizeof (identification_header));
315 gst_buffer_fill (inbuffer, 0, identification_header,
316 sizeof (identification_header));
317 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
318
319 /* send empty comment buffer */
320 inbuffer = gst_buffer_new_and_alloc (sizeof (title_comment_header));
321 gst_buffer_fill (inbuffer, 0, title_comment_header,
322 sizeof (title_comment_header));
323 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
324
325 /* send minimal codebook header and audio packers */
326 inbuffer = _create_codebook_header_buffer ();
327 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
328 inbuffer = _create_audio_buffer ();
329 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
330
331
332 /* check identification header is unchanged */
333 outbuffer = get_buffer ();
334 compare_buffer (outbuffer, identification_header,
335 sizeof (identification_header));
336 gst_buffer_unref (outbuffer);
337
338 /* check comment header is correct */
339 outbuffer = get_buffer ();
340 compare_buffer (outbuffer, empty_comment_header,
341 sizeof (empty_comment_header));
342 gst_buffer_unref (outbuffer);
343
344 stop_pipeline (vorbistag);
345 cleanup_vorbistag (vorbistag);
346 }
347
348 GST_END_TEST;
349
350
GST_START_TEST(test_filled_tags_change)351 GST_START_TEST (test_filled_tags_change)
352 {
353 GstTagList *tags;
354 GstElement *vorbistag;
355 GstBuffer *inbuffer, *outbuffer;
356
357 vorbistag = setup_vorbistag ();
358
359 tags = gst_tag_list_new_empty ();
360 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_TITLE, "foobar", NULL);
361 gst_tag_setter_merge_tags (GST_TAG_SETTER (vorbistag), tags,
362 GST_TAG_MERGE_REPLACE);
363 gst_tag_setter_set_tag_merge_mode (GST_TAG_SETTER (vorbistag),
364 GST_TAG_MERGE_KEEP_ALL);
365 gst_tag_list_unref (tags);
366
367 start_pipeline (vorbistag);
368
369 /* send identification header */
370 inbuffer = gst_buffer_new_and_alloc (sizeof (identification_header));
371 gst_buffer_fill (inbuffer, 0, identification_header,
372 sizeof (identification_header));
373 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
374
375 /* send empty comment buffer */
376 inbuffer = gst_buffer_new_and_alloc (sizeof (artist_comment_header));
377 gst_buffer_fill (inbuffer, 0, artist_comment_header,
378 sizeof (artist_comment_header));
379 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
380
381 /* send minimal codebook header and audio packers */
382 inbuffer = _create_codebook_header_buffer ();
383 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
384 inbuffer = _create_audio_buffer ();
385 fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
386
387
388 /* check identification header is unchanged */
389 outbuffer = get_buffer ();
390 compare_buffer (outbuffer, identification_header,
391 sizeof (identification_header));
392 gst_buffer_unref (outbuffer);
393
394 /* check comment header is correct */
395 outbuffer = get_buffer ();
396 compare_buffer (outbuffer, title_comment_header,
397 sizeof (title_comment_header));
398 gst_buffer_unref (outbuffer);
399
400 stop_pipeline (vorbistag);
401 cleanup_vorbistag (vorbistag);
402 }
403
404 GST_END_TEST;
405
406
407
408 static Suite *
vorbistag_suite(void)409 vorbistag_suite (void)
410 {
411 Suite *s = suite_create ("vorbistag");
412 TCase *tc_chain = tcase_create ("general");
413
414 suite_add_tcase (s, tc_chain);
415 tcase_add_test (tc_chain, test_empty_tags_set);
416 tcase_add_test (tc_chain, test_filled_tags_unset);
417 tcase_add_test (tc_chain, test_filled_tags_change);
418
419 return s;
420 }
421
422 GST_CHECK_MAIN (vorbistag)
423