tizen 2.0 init
[framework/multimedia/gst-plugins-base0.10.git] / tests / check / pipelines / vorbisenc.c
1 /* GStreamer
2  *
3  * unit test for vorbisenc
4  *
5  * Copyright (C) 2006 Andy Wingo <wingo at pobox.com>
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., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <gst/check/gstcheck.h>
24 #include <gst/check/gstbufferstraw.h>
25
26 #ifndef GST_DISABLE_PARSE
27
28 #define TIMESTAMP_OFFSET G_GINT64_CONSTANT(3249870963)
29
30 static void
31 check_buffer_timestamp (GstBuffer * buffer, GstClockTime timestamp)
32 {
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)));
37 }
38
39 static void
40 check_buffer_duration (GstBuffer * buffer, GstClockTime duration)
41 {
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)));
46 }
47
48 static void
49 check_buffer_granulepos (GstBuffer * buffer, gint64 granulepos)
50 {
51   GstClockTime clocktime;
52
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));
57
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,
61       GST_SECOND);
62
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)));
67 }
68
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. */
74 static void
75 check_buffer_granulepos_from_endtime (GstBuffer * buffer, GstClockTime endtime)
76 {
77   gint64 granulepos, expected;
78
79   granulepos = GST_BUFFER_OFFSET_END (buffer);
80   expected = gst_util_uint64_scale (endtime, 44100, GST_SECOND);
81
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);
87 }
88
89 GST_START_TEST (test_granulepos_offset)
90 {
91   GstElement *bin;
92   GstPad *pad;
93   gchar *pipe_str;
94   GstBuffer *buffer;
95   GError *error = NULL;
96
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);
100
101   bin = gst_parse_launch (pipe_str, &error);
102   fail_unless (bin != NULL, "Error parsing pipeline: %s",
103       error ? error->message : "(invalid error)");
104   g_free (pipe_str);
105
106   /* get the pad */
107   {
108     GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
109
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);
114   }
115
116   gst_buffer_straw_start_pipeline (bin, pad);
117
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");
126
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);
132
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);
138
139   {
140     GstClockTime next_timestamp;
141     gint64 last_granulepos = 0;
142
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));
155
156     next_timestamp = TIMESTAMP_OFFSET + GST_BUFFER_DURATION (buffer);
157
158     gst_buffer_unref (buffer);
159
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,
165             44100)
166         - gst_util_uint64_scale (last_granulepos, GST_SECOND, 44100));
167     check_buffer_granulepos_from_endtime (buffer,
168         next_timestamp + GST_BUFFER_DURATION (buffer));
169
170     gst_buffer_unref (buffer);
171   }
172
173   gst_buffer_straw_stop_pipeline (bin, pad);
174
175   gst_object_unref (pad);
176   gst_object_unref (bin);
177 }
178
179 GST_END_TEST;
180
181 GST_START_TEST (test_timestamps)
182 {
183   GstElement *bin;
184   GstPad *pad;
185   gchar *pipe_str;
186   GstBuffer *buffer;
187   GError *error = NULL;
188
189   pipe_str = g_strdup_printf ("audiotestsrc"
190       " ! audio/x-raw-int,rate=44100 ! audioconvert ! vorbisenc ! fakesink");
191
192   bin = gst_parse_launch (pipe_str, &error);
193   fail_unless (bin != NULL, "Error parsing pipeline: %s",
194       error ? error->message : "(invalid error)");
195   g_free (pipe_str);
196
197   /* get the pad */
198   {
199     GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
200
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);
205   }
206
207   gst_buffer_straw_start_pipeline (bin, pad);
208
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);
215
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);
221
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);
227
228   {
229     GstClockTime next_timestamp;
230     gint64 last_granulepos;
231
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));
238
239     next_timestamp = GST_BUFFER_DURATION (buffer);
240
241     gst_buffer_unref (buffer);
242
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,
248             44100)
249         - gst_util_uint64_scale (last_granulepos, GST_SECOND, 44100));
250     check_buffer_granulepos_from_endtime (buffer,
251         next_timestamp + GST_BUFFER_DURATION (buffer));
252
253     gst_buffer_unref (buffer);
254   }
255
256   gst_buffer_straw_stop_pipeline (bin, pad);
257
258   gst_object_unref (pad);
259   gst_object_unref (bin);
260 }
261
262 GST_END_TEST;
263
264 static gboolean
265 drop_second_data_buffer (GstPad * droppad, GstBuffer * buffer, gpointer unused)
266 {
267   return !(GST_BUFFER_OFFSET (buffer) == 4096);
268 }
269
270 GST_START_TEST (test_discontinuity)
271 {
272   GstElement *bin;
273   GstPad *pad, *droppad;
274   gchar *pipe_str;
275   GstBuffer *buffer;
276   GError *error = NULL;
277   guint drop_id;
278
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");
283
284   bin = gst_parse_launch (pipe_str, &error);
285   fail_unless (bin != NULL, "Error parsing pipeline: %s",
286       error ? error->message : "(invalid error)");
287   g_free (pipe_str);
288
289   /* the plan: same as test_timestamps, but dropping a buffer and seeing if
290      vorbisenc correctly notes the discontinuity */
291
292   /* get the pad to use to drop buffers */
293   {
294     GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "vorbisenc0");
295
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);
300   }
301
302   /* get the pad */
303   {
304     GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
305
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);
310   }
311
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);
315
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);
322
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);
328
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);
334
335   {
336     GstClockTime next_timestamp = 0;
337     gint64 last_granulepos = 0, granulepos;
338     gint i;
339
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);
349         }
350       }
351       check_buffer_timestamp (buffer, next_timestamp);
352       next_timestamp += GST_BUFFER_DURATION (buffer);
353       last_granulepos = granulepos;
354       gst_buffer_unref (buffer);
355     }
356   }
357
358   gst_buffer_straw_stop_pipeline (bin, pad);
359   gst_pad_remove_buffer_probe (droppad, drop_id);
360
361   gst_object_unref (droppad);
362   gst_object_unref (pad);
363   gst_object_unref (bin);
364 }
365
366 GST_END_TEST;
367
368 #endif /* #ifndef GST_DISABLE_PARSE */
369
370 static Suite *
371 vorbisenc_suite (void)
372 {
373   Suite *s = suite_create ("vorbisenc");
374   TCase *tc_chain = tcase_create ("general");
375
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);
381 #endif
382
383   return s;
384 }
385
386 int
387 main (int argc, char **argv)
388 {
389   int nf;
390
391   Suite *s = vorbisenc_suite ();
392   SRunner *sr = srunner_create (s);
393
394   gst_check_init (&argc, &argv);
395
396   srunner_run_all (sr, CK_NORMAL);
397   nf = srunner_ntests_failed (sr);
398   srunner_free (sr);
399
400   return nf;
401 }