Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / 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) == 1024);
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   pipe_str = g_strdup_printf ("audiotestsrc samplesperbuffer=1024"
280       " ! audio/x-raw-int,rate=44100" " ! audioconvert ! vorbisenc ! fakesink");
281
282   bin = gst_parse_launch (pipe_str, &error);
283   fail_unless (bin != NULL, "Error parsing pipeline: %s",
284       error ? error->message : "(invalid error)");
285   g_free (pipe_str);
286
287   /* the plan: same as test_timestamps, but dropping a buffer and seeing if
288      vorbisenc correctly notes the discontinuity */
289
290   /* get the pad to use to drop buffers */
291   {
292     GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "vorbisenc0");
293
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);
298   }
299
300   /* get the pad */
301   {
302     GstElement *sink = gst_bin_get_by_name (GST_BIN (bin), "fakesink0");
303
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);
308   }
309
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);
313
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);
320
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);
326
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);
332
333   /* two phases: continuous granulepos values up to 1024, then a first
334      discontinuous granulepos whose granulepos corresponds to a gap ending at
335      2048. */
336   {
337     GstClockTime next_timestamp = 0;
338     gint64 last_granulepos = 0;
339
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);
347     }
348
349     fail_unless (last_granulepos == 1024,
350         "unexpected granulepos: %" G_GUINT64_FORMAT, last_granulepos);
351   }
352
353   {
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.
358      */
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);
365   }
366
367   gst_buffer_straw_stop_pipeline (bin, pad);
368   gst_pad_remove_buffer_probe (droppad, drop_id);
369
370   gst_object_unref (droppad);
371   gst_object_unref (pad);
372   gst_object_unref (bin);
373 }
374
375 GST_END_TEST;
376
377 #endif /* #ifndef GST_DISABLE_PARSE */
378
379 static Suite *
380 vorbisenc_suite (void)
381 {
382   Suite *s = suite_create ("vorbisenc");
383   TCase *tc_chain = tcase_create ("general");
384
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);
390 #endif
391
392   return s;
393 }
394
395 int
396 main (int argc, char **argv)
397 {
398   int nf;
399
400   Suite *s = vorbisenc_suite ();
401   SRunner *sr = srunner_create (s);
402
403   gst_check_init (&argc, &argv);
404
405   srunner_run_all (sr, CK_NORMAL);
406   nf = srunner_ntests_failed (sr);
407   srunner_free (sr);
408
409   return nf;
410 }