• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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