3 * unit test for vorbisenc
5 * Copyright (C) 2006 Andy Wingo <wingo at pobox.com>
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.
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.
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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #include <gst/check/gstcheck.h>
24 #include <gst/check/gstbufferstraw.h>
26 #ifndef GST_DISABLE_PARSE
28 #define TIMESTAMP_OFFSET G_GINT64_CONSTANT(3249870963)
31 check_buffer_timestamp (GstBuffer * buffer, GstClockTime timestamp)
33 fail_unless (GST_BUFFER_TIMESTAMP (buffer) == timestamp,
34 "expected timestamp %" GST_TIME_FORMAT
35 ", but got timestamp %" GST_TIME_FORMAT,
36 GST_TIME_ARGS (timestamp), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
40 check_buffer_duration (GstBuffer * buffer, GstClockTime duration)
42 fail_unless (GST_BUFFER_DURATION (buffer) == duration,
43 "expected duration %" GST_TIME_FORMAT
44 ", but got duration %" GST_TIME_FORMAT,
45 GST_TIME_ARGS (duration), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
49 check_buffer_granulepos (GstBuffer * buffer, gint64 granulepos)
51 GstClockTime clocktime;
53 fail_unless (GST_BUFFER_OFFSET_END (buffer) == granulepos,
54 "expected granulepos %" G_GUINT64_FORMAT
55 ", but got granulepos %" G_GUINT64_FORMAT,
56 granulepos, GST_BUFFER_OFFSET_END (buffer));
58 /* contrary to what we record as TIMESTAMP, we can use OFFSET to check
59 * the granulepos correctly here */
60 clocktime = gst_util_uint64_scale (GST_BUFFER_OFFSET_END (buffer), 44100,
63 fail_unless (clocktime == GST_BUFFER_OFFSET (buffer),
64 "expected OFFSET set to clocktime %" GST_TIME_FORMAT
65 ", but got %" GST_TIME_FORMAT,
66 GST_TIME_ARGS (clocktime), GST_TIME_ARGS (GST_BUFFER_OFFSET (buffer)));
69 /* this check is here to check that the granulepos we derive from the timestamp
70 is about correct. This is "about correct" because you can't precisely go from
71 timestamp to granulepos due to the downward-rounding characteristics of
72 gst_util_uint64_scale, so you check if granulepos is equal to the number, or
73 the number plus one. */
75 check_buffer_granulepos_from_endtime (GstBuffer * buffer, GstClockTime endtime)
77 gint64 granulepos, expected;
79 granulepos = GST_BUFFER_OFFSET_END (buffer);
80 expected = gst_util_uint64_scale (endtime, 44100, GST_SECOND);
82 fail_unless (granulepos == expected || granulepos == expected + 1,
83 "expected granulepos %" G_GUINT64_FORMAT
84 " or %" G_GUINT64_FORMAT
85 ", but got granulepos %" G_GUINT64_FORMAT,
86 expected, expected + 1, granulepos);
89 GST_START_TEST (test_granulepos_offset)
97 pipe_str = g_strdup_printf ("audiotestsrc timestamp-offset=%" G_GUINT64_FORMAT
98 " ! audio/x-raw-int,rate=44100"
99 " ! audioconvert ! vorbisenc ! fakesink", TIMESTAMP_OFFSET);
101 bin = gst_parse_launch (pipe_str, &error);
102 fail_unless (bin != NULL, "Error parsing pipeline: %s",
103 error ? error->message : "(invalid error)");
108 GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
110 fail_unless (sink != NULL, "Could not get fakesink out of bin");
111 pad = gst_element_get_static_pad (sink, "sink");
112 fail_unless (pad != NULL, "Could not get pad out of fakesink");
113 gst_object_unref (sink);
116 gst_buffer_straw_start_pipeline (bin, pad);
118 /* header packets should have timestamp == NONE, granulepos 0 */
119 buffer = gst_buffer_straw_get_buffer (bin, pad);
120 GST_DEBUG ("Got buffer in test");
121 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
122 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
123 check_buffer_granulepos (buffer, 0);
124 gst_buffer_unref (buffer);
125 GST_DEBUG ("Unreffed buffer in test");
127 buffer = gst_buffer_straw_get_buffer (bin, pad);
128 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
129 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
130 check_buffer_granulepos (buffer, 0);
131 gst_buffer_unref (buffer);
133 buffer = gst_buffer_straw_get_buffer (bin, pad);
134 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
135 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
136 check_buffer_granulepos (buffer, 0);
137 gst_buffer_unref (buffer);
140 GstClockTime next_timestamp;
141 gint64 last_granulepos = 0;
143 /* first buffer should have timestamp of TIMESTAMP_OFFSET, granulepos to
144 * match the timestamp of the end of the last sample in the output buffer.
145 * Note that one cannot go timestamp->granulepos->timestamp and get the same
146 * value due to loss of precision with granulepos. vorbisenc does take care
147 * to timestamp correctly based on the offset of the input data however, so
148 * it does do sub-granulepos timestamping. */
149 buffer = gst_buffer_straw_get_buffer (bin, pad);
150 last_granulepos = GST_BUFFER_OFFSET_END (buffer);
151 check_buffer_timestamp (buffer, TIMESTAMP_OFFSET);
152 /* don't really have a good way of checking duration... */
153 check_buffer_granulepos_from_endtime (buffer,
154 TIMESTAMP_OFFSET + GST_BUFFER_DURATION (buffer));
156 next_timestamp = TIMESTAMP_OFFSET + GST_BUFFER_DURATION (buffer);
158 gst_buffer_unref (buffer);
160 /* check continuity with the next buffer */
161 buffer = gst_buffer_straw_get_buffer (bin, pad);
162 check_buffer_timestamp (buffer, next_timestamp);
163 check_buffer_duration (buffer,
164 gst_util_uint64_scale (GST_BUFFER_OFFSET_END (buffer), GST_SECOND,
166 - gst_util_uint64_scale (last_granulepos, GST_SECOND, 44100));
167 check_buffer_granulepos_from_endtime (buffer,
168 next_timestamp + GST_BUFFER_DURATION (buffer));
170 gst_buffer_unref (buffer);
173 gst_buffer_straw_stop_pipeline (bin, pad);
175 gst_object_unref (pad);
176 gst_object_unref (bin);
181 GST_START_TEST (test_timestamps)
187 GError *error = NULL;
189 pipe_str = g_strdup_printf ("audiotestsrc"
190 " ! audio/x-raw-int,rate=44100 ! audioconvert ! vorbisenc ! fakesink");
192 bin = gst_parse_launch (pipe_str, &error);
193 fail_unless (bin != NULL, "Error parsing pipeline: %s",
194 error ? error->message : "(invalid error)");
199 GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
201 fail_unless (sink != NULL, "Could not get fakesink out of bin");
202 pad = gst_element_get_static_pad (sink, "sink");
203 fail_unless (pad != NULL, "Could not get pad out of fakesink");
204 gst_object_unref (sink);
207 gst_buffer_straw_start_pipeline (bin, pad);
209 /* check header packets */
210 buffer = gst_buffer_straw_get_buffer (bin, pad);
211 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
212 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
213 check_buffer_granulepos (buffer, 0);
214 gst_buffer_unref (buffer);
216 buffer = gst_buffer_straw_get_buffer (bin, pad);
217 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
218 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
219 check_buffer_granulepos (buffer, 0);
220 gst_buffer_unref (buffer);
222 buffer = gst_buffer_straw_get_buffer (bin, pad);
223 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
224 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
225 check_buffer_granulepos (buffer, 0);
226 gst_buffer_unref (buffer);
229 GstClockTime next_timestamp;
230 gint64 last_granulepos;
232 /* first buffer has timestamp 0 */
233 buffer = gst_buffer_straw_get_buffer (bin, pad);
234 last_granulepos = GST_BUFFER_OFFSET_END (buffer);
235 check_buffer_timestamp (buffer, 0);
236 /* don't really have a good way of checking duration... */
237 check_buffer_granulepos_from_endtime (buffer, GST_BUFFER_DURATION (buffer));
239 next_timestamp = GST_BUFFER_DURATION (buffer);
241 gst_buffer_unref (buffer);
243 /* check continuity with the next buffer */
244 buffer = gst_buffer_straw_get_buffer (bin, pad);
245 check_buffer_timestamp (buffer, next_timestamp);
246 check_buffer_duration (buffer,
247 gst_util_uint64_scale (GST_BUFFER_OFFSET_END (buffer), GST_SECOND,
249 - gst_util_uint64_scale (last_granulepos, GST_SECOND, 44100));
250 check_buffer_granulepos_from_endtime (buffer,
251 next_timestamp + GST_BUFFER_DURATION (buffer));
253 gst_buffer_unref (buffer);
256 gst_buffer_straw_stop_pipeline (bin, pad);
258 gst_object_unref (pad);
259 gst_object_unref (bin);
265 drop_second_data_buffer (GstPad * droppad, GstBuffer * buffer, gpointer unused)
267 return !(GST_BUFFER_OFFSET (buffer) == 4096);
270 GST_START_TEST (test_discontinuity)
273 GstPad *pad, *droppad;
276 GError *error = NULL;
279 /* make audioencoder act sufficiently pedantic */
280 pipe_str = g_strdup_printf ("audiotestsrc samplesperbuffer=1024"
281 " ! audio/x-raw-int,rate=44100" " ! audioconvert "
282 " ! vorbisenc tolerance=10000000 ! fakesink");
284 bin = gst_parse_launch (pipe_str, &error);
285 fail_unless (bin != NULL, "Error parsing pipeline: %s",
286 error ? error->message : "(invalid error)");
289 /* the plan: same as test_timestamps, but dropping a buffer and seeing if
290 vorbisenc correctly notes the discontinuity */
292 /* get the pad to use to drop buffers */
294 GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "vorbisenc0");
296 fail_unless (sink != NULL, "Could not get vorbisenc out of bin");
297 droppad = gst_element_get_static_pad (sink, "sink");
298 fail_unless (droppad != NULL, "Could not get pad out of vorbisenc");
299 gst_object_unref (sink);
304 GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
306 fail_unless (sink != NULL, "Could not get fakesink out of bin");
307 pad = gst_element_get_static_pad (sink, "sink");
308 fail_unless (pad != NULL, "Could not get pad out of fakesink");
309 gst_object_unref (sink);
312 drop_id = gst_pad_add_buffer_probe (droppad,
313 G_CALLBACK (drop_second_data_buffer), NULL);
314 gst_buffer_straw_start_pipeline (bin, pad);
316 /* check header packets */
317 buffer = gst_buffer_straw_get_buffer (bin, pad);
318 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
319 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
320 check_buffer_granulepos (buffer, 0);
321 gst_buffer_unref (buffer);
323 buffer = gst_buffer_straw_get_buffer (bin, pad);
324 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
325 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
326 check_buffer_granulepos (buffer, 0);
327 gst_buffer_unref (buffer);
329 buffer = gst_buffer_straw_get_buffer (bin, pad);
330 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
331 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
332 check_buffer_granulepos (buffer, 0);
333 gst_buffer_unref (buffer);
336 GstClockTime next_timestamp = 0;
337 gint64 last_granulepos = 0, granulepos;
340 for (i = 0; i < 10; i++) {
341 buffer = gst_buffer_straw_get_buffer (bin, pad);
342 granulepos = GST_BUFFER_OFFSET_END (buffer);
343 /* discont is either at start, or following gap */
344 if (GST_BUFFER_IS_DISCONT (buffer)) {
345 if (next_timestamp) {
346 fail_unless (granulepos - last_granulepos > 1024,
347 "expected discont of at least 1024 samples");
348 next_timestamp = GST_BUFFER_TIMESTAMP (buffer);
351 check_buffer_timestamp (buffer, next_timestamp);
352 next_timestamp += GST_BUFFER_DURATION (buffer);
353 last_granulepos = granulepos;
354 gst_buffer_unref (buffer);
358 gst_buffer_straw_stop_pipeline (bin, pad);
359 gst_pad_remove_buffer_probe (droppad, drop_id);
361 gst_object_unref (droppad);
362 gst_object_unref (pad);
363 gst_object_unref (bin);
368 #endif /* #ifndef GST_DISABLE_PARSE */
371 vorbisenc_suite (void)
373 Suite *s = suite_create ("vorbisenc");
374 TCase *tc_chain = tcase_create ("general");
376 suite_add_tcase (s, tc_chain);
377 #ifndef GST_DISABLE_PARSE
378 tcase_add_test (tc_chain, test_granulepos_offset);
379 tcase_add_test (tc_chain, test_timestamps);
380 tcase_add_test (tc_chain, test_discontinuity);
387 main (int argc, char **argv)
391 Suite *s = vorbisenc_suite ();
392 SRunner *sr = srunner_create (s);
394 gst_check_init (&argc, &argv);
396 srunner_run_all (sr, CK_NORMAL);
397 nf = srunner_ntests_failed (sr);