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) == 1024);
270 GST_START_TEST (test_discontinuity)
273 GstPad *pad, *droppad;
276 GError *error = NULL;
279 pipe_str = g_strdup_printf ("audiotestsrc samplesperbuffer=1024"
280 " ! audio/x-raw-int,rate=44100" " ! audioconvert ! vorbisenc ! fakesink");
282 bin = gst_parse_launch (pipe_str, &error);
283 fail_unless (bin != NULL, "Error parsing pipeline: %s",
284 error ? error->message : "(invalid error)");
287 /* the plan: same as test_timestamps, but dropping a buffer and seeing if
288 vorbisenc correctly notes the discontinuity */
290 /* get the pad to use to drop buffers */
292 GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "vorbisenc0");
294 fail_unless (sink != NULL, "Could not get vorbisenc out of bin");
295 droppad = gst_element_get_static_pad (sink, "sink");
296 fail_unless (droppad != NULL, "Could not get pad out of vorbisenc");
297 gst_object_unref (sink);
302 GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
304 fail_unless (sink != NULL, "Could not get fakesink out of bin");
305 pad = gst_element_get_static_pad (sink, "sink");
306 fail_unless (pad != NULL, "Could not get pad out of fakesink");
307 gst_object_unref (sink);
310 drop_id = gst_pad_add_buffer_probe (droppad,
311 G_CALLBACK (drop_second_data_buffer), NULL);
312 gst_buffer_straw_start_pipeline (bin, pad);
314 /* check header packets */
315 buffer = gst_buffer_straw_get_buffer (bin, pad);
316 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
317 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
318 check_buffer_granulepos (buffer, 0);
319 gst_buffer_unref (buffer);
321 buffer = gst_buffer_straw_get_buffer (bin, pad);
322 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
323 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
324 check_buffer_granulepos (buffer, 0);
325 gst_buffer_unref (buffer);
327 buffer = gst_buffer_straw_get_buffer (bin, pad);
328 check_buffer_timestamp (buffer, GST_CLOCK_TIME_NONE);
329 check_buffer_duration (buffer, GST_CLOCK_TIME_NONE);
330 check_buffer_granulepos (buffer, 0);
331 gst_buffer_unref (buffer);
333 /* two phases: continuous granulepos values up to 1024, then a first
334 discontinuous granulepos whose granulepos corresponds to a gap ending at
337 GstClockTime next_timestamp = 0;
338 gint64 last_granulepos = 0;
340 while (last_granulepos < 1024) {
341 buffer = gst_buffer_straw_get_buffer (bin, pad);
342 last_granulepos = GST_BUFFER_OFFSET_END (buffer);
343 check_buffer_timestamp (buffer, next_timestamp);
344 fail_if (GST_BUFFER_IS_DISCONT (buffer), "expected continuous buffer");
345 next_timestamp += GST_BUFFER_DURATION (buffer);
346 gst_buffer_unref (buffer);
349 fail_unless (last_granulepos == 1024,
350 "unexpected granulepos: %" G_GUINT64_FORMAT, last_granulepos);
354 buffer = gst_buffer_straw_get_buffer (bin, pad);
355 /* The first buffer after the discontinuity will produce zero output
356 * samples (because of the overlap/add), so it won't increment the
357 * granulepos, which should be 2048 after the discontinuity.
359 fail_unless (GST_BUFFER_OFFSET_END (buffer) == 2048,
360 "expected granulepos after gap: %" G_GUINT64_FORMAT,
361 GST_BUFFER_OFFSET_END (buffer));
362 fail_unless (GST_BUFFER_IS_DISCONT (buffer),
363 "expected discontinuous buffer");
364 gst_buffer_unref (buffer);
367 gst_buffer_straw_stop_pipeline (bin, pad);
368 gst_pad_remove_buffer_probe (droppad, drop_id);
370 gst_object_unref (droppad);
371 gst_object_unref (pad);
372 gst_object_unref (bin);
377 #endif /* #ifndef GST_DISABLE_PARSE */
380 vorbisenc_suite (void)
382 Suite *s = suite_create ("vorbisenc");
383 TCase *tc_chain = tcase_create ("general");
385 suite_add_tcase (s, tc_chain);
386 #ifndef GST_DISABLE_PARSE
387 tcase_add_test (tc_chain, test_granulepos_offset);
388 tcase_add_test (tc_chain, test_timestamps);
389 tcase_add_test (tc_chain, test_discontinuity);
396 main (int argc, char **argv)
400 Suite *s = vorbisenc_suite ();
401 SRunner *sr = srunner_create (s);
403 gst_check_init (&argc, &argv);
405 srunner_run_all (sr, CK_NORMAL);
406 nf = srunner_ntests_failed (sr);