upload tizen1.0 source
[framework/multimedia/gst-plugins-good0.10.git] / tests / check / elements / cmmlenc.c
1 /*
2  * cmmlenc.c - GStreamer CMML decoder test suite
3  * Copyright (C) 2005 Alessandro Decina
4  * 
5  * Authors:
6  *   Alessandro Decina <alessandro@nnva.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include <gst/check/gstcheck.h>
25
26 #include <gst/tag/tag.h>
27
28 #define SINK_CAPS "text/x-cmml"
29 #define SRC_CAPS "text/x-cmml"
30
31 #define IDENT_HEADER \
32   "CMML\x00\x00\x00\x00"\
33   "\x03\x00\x00\x00"\
34   "\xe8\x03\x00\x00\x00\x00\x00\x00"\
35   "\x01\x00\x00\x00\x00\x00\x00\x00"\
36   "\x20"
37
38 #define XML_PREAMBLE \
39   "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"\
40   "<!DOCTYPE cmml SYSTEM \"cmml.dtd\">\n"
41
42 #define START_TAG \
43   "<cmml>"
44
45 #define PROCESSING_INSTRUCTION \
46   "<?cmml ?>"
47
48 #define PREAMBLE \
49   XML_PREAMBLE START_TAG
50
51 #define PREAMBLE_ENCODED \
52   XML_PREAMBLE PROCESSING_INSTRUCTION
53
54 #define STREAM_TAG \
55   "<stream timebase=\"10\">"\
56      "<import src=\"test.ogg\"/>"\
57      "<import src=\"test1.ogg\"/>"\
58    "</stream>"
59
60 #define STREAM_TAG_ENCODED STREAM_TAG
61
62 #define HEAD_TAG \
63   "<head>"\
64     "<title>The Research Hunter</title>"\
65     "<meta name=\"DC.audience\" content=\"General\"/>"\
66     "<meta name=\"DC.author\" content=\"CSIRO Publishing\"/>"\
67     "<meta name=\"DC.format\" content=\"video\"/>"\
68     "<meta name=\"DC.language\" content=\"English\"/>"\
69     "<meta name=\"DC.publisher\" content=\"CSIRO Australia\"/>"\
70   "</head>"
71
72 #define HEAD_TAG_ENCODED HEAD_TAG
73
74 #define CLIP_TEMPLATE \
75   "<clip id=\"%s\" track=\"%s\" start=\"%s\">"\
76     "<a href=\"http://www.annodex.org/\">http://www.annodex.org</a>"\
77     "<img src=\"images/index.jpg\"/>"\
78     "<desc>Annodex Foundation</desc>"\
79     "<meta name=\"test\" content=\"test content\"/>"\
80   "</clip>"
81
82 #define ENDED_CLIP_TEMPLATE \
83   "<clip id=\"%s\" track=\"%s\" start=\"%s\" end=\"%s\">"\
84     "<a href=\"http://www.annodex.org/\">http://www.annodex.org</a>"\
85     "<img src=\"images/index.jpg\"/>"\
86     "<desc>Annodex Foundation</desc>"\
87     "<meta name=\"test\" content=\"test content\"/>"\
88   "</clip>"
89
90 #define CLIP_TEMPLATE_ENCODED \
91   "<clip id=\"%s\" track=\"%s\">"\
92     "<a href=\"http://www.annodex.org/\">http://www.annodex.org</a>"\
93     "<img src=\"images/index.jpg\"/>"\
94     "<desc>Annodex Foundation</desc>"\
95     "<meta name=\"test\" content=\"test content\"/>"\
96   "</clip>"
97
98 #define EMPTY_CLIP_TEMPLATE_ENCODED \
99   "<clip track=\"%s\"/>"
100
101 #define fail_unless_equals_flow_return(a, b)                            \
102 G_STMT_START {                                                          \
103   gchar *a_up = g_ascii_strup (gst_flow_get_name (a), -1);              \
104   gchar *b_up = g_ascii_strup (gst_flow_get_name (b), -1);              \
105   fail_unless (a == b,                                                  \
106       "'" #a "' (GST_FLOW_%s) is not equal to '" #b "' (GST_FLOW_%s)",  \
107       a_up, b_up);                                                      \
108   g_free (a_up);                                                        \
109   g_free (b_up);                                                        \
110 } G_STMT_END;
111
112 static GList *current_buf;
113 static guint64 granulerate;
114 static guint8 granuleshift;
115 static GstElement *cmmlenc;
116 static GstBus *bus;
117 static GstFlowReturn flow;
118 static GstPad *srcpad, *sinkpad;
119
120 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
121     GST_PAD_SINK,
122     GST_PAD_ALWAYS,
123     GST_STATIC_CAPS (SINK_CAPS)
124     );
125
126 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
127     GST_PAD_SRC,
128     GST_PAD_ALWAYS,
129     GST_STATIC_CAPS (SRC_CAPS)
130     );
131
132 static GstBuffer *
133 buffer_new (const gchar * buffer_data, guint size)
134 {
135   GstBuffer *buffer;
136   GstCaps *caps;
137
138   buffer = gst_buffer_new_and_alloc (size);
139   memcpy (GST_BUFFER_DATA (buffer), buffer_data, size);
140   caps = gst_caps_from_string (SRC_CAPS);
141   gst_buffer_set_caps (buffer, caps);
142   gst_caps_unref (caps);
143
144   return buffer;
145 }
146
147 static void
148 buffer_unref (void *buffer, void *user_data)
149 {
150   gst_buffer_unref (GST_BUFFER (buffer));
151 }
152
153 static void
154 setup_cmmlenc (void)
155 {
156   guint64 granulerate_n, granulerate_d;
157
158   GST_DEBUG ("setup_cmmlenc");
159
160   cmmlenc = gst_check_setup_element ("cmmlenc");
161   srcpad = gst_check_setup_src_pad (cmmlenc, &srctemplate, NULL);
162   sinkpad = gst_check_setup_sink_pad (cmmlenc, &sinktemplate, NULL);
163   gst_pad_set_active (srcpad, TRUE);
164   gst_pad_set_active (sinkpad, TRUE);
165
166   bus = gst_bus_new ();
167   gst_element_set_bus (cmmlenc, bus);
168
169   fail_unless (gst_element_set_state (cmmlenc,
170           GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE,
171       "could not set to playing");
172
173   g_object_get (cmmlenc, "granule-rate-numerator", &granulerate_n,
174       "granule-rate-denominator", &granulerate_d,
175       "granule-shift", &granuleshift, NULL);
176
177   granulerate = GST_SECOND * granulerate_d / granulerate_n;
178 }
179
180 static void
181 teardown_cmmlenc (void)
182 {
183   /* free encoded buffers */
184   g_list_foreach (buffers, buffer_unref, NULL);
185   g_list_free (buffers);
186   buffers = NULL;
187   current_buf = NULL;
188
189   gst_bus_set_flushing (bus, TRUE);
190   gst_object_unref (bus);
191
192   GST_DEBUG ("teardown_cmmlenc");
193   gst_pad_set_active (srcpad, FALSE);
194   gst_pad_set_active (sinkpad, FALSE);
195   gst_check_teardown_src_pad (cmmlenc);
196   gst_check_teardown_sink_pad (cmmlenc);
197   gst_check_teardown_element (cmmlenc);
198 }
199
200 static void
201 check_output_buffer_is_equal (const gchar * name,
202     const gchar * data, gint refcount)
203 {
204   GstBuffer *buffer;
205
206   if (current_buf == NULL)
207     current_buf = buffers;
208   else
209     current_buf = g_list_next (current_buf);
210
211   fail_unless (current_buf != NULL);
212   buffer = GST_BUFFER (current_buf->data);
213
214   ASSERT_OBJECT_REFCOUNT (buffer, name, refcount);
215   fail_unless (memcmp (GST_BUFFER_DATA (buffer), data,
216           GST_BUFFER_SIZE (buffer)) == 0,
217       "'%s' (%s) is not equal to (%s)", name, GST_BUFFER_DATA (buffer), data);
218 }
219
220 static GstFlowReturn
221 push_data (const gchar * name, const gchar * data, gint size)
222 {
223   GstBuffer *buffer;
224   GstFlowReturn res;
225
226   buffer = buffer_new (data, size);
227   res = gst_pad_push (srcpad, buffer);
228
229   return res;
230 }
231
232 static void
233 check_headers (void)
234 {
235   /* push the cmml start tag */
236   flow = push_data ("preamble", PREAMBLE, strlen (PREAMBLE));
237   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
238
239   /* push the stream tag */
240   flow = push_data ("stream", STREAM_TAG, strlen (STREAM_TAG));
241   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
242   /* push the head tag */
243   flow = push_data ("head", HEAD_TAG, strlen (HEAD_TAG));
244   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
245
246   /* should output 3 buffers: the ident, preamble and head headers */
247   fail_unless_equals_int (g_list_length (buffers), 3);
248
249   /* check the ident header */
250   check_output_buffer_is_equal ("cmml-ident-buffer", IDENT_HEADER, 1);
251
252   /* check the cmml processing instruction */
253   check_output_buffer_is_equal ("cmml-preamble-buffer", PREAMBLE_ENCODED, 1);
254
255   /* check the encoded head tag */
256   check_output_buffer_is_equal ("head-tag-buffer", HEAD_TAG_ENCODED, 1);
257 }
258
259 static GstFlowReturn
260 push_clip (const gchar * name, const gchar * track,
261     const gchar * start, const gchar * end)
262 {
263   gchar *clip;
264   GstFlowReturn res;
265
266   if (end != NULL)
267     clip = g_strdup_printf (ENDED_CLIP_TEMPLATE, name, track, start, end);
268   else
269     clip = g_strdup_printf (CLIP_TEMPLATE, name, track, start);
270   res = push_data (name, clip, strlen (clip));
271   g_free (clip);
272
273   return res;
274 }
275
276 static void
277 check_clip_times (GstBuffer * buffer, GstClockTime start, GstClockTime prev)
278 {
279   guint64 keyindex, keyoffset, granulepos;
280
281   granulepos = GST_BUFFER_OFFSET_END (buffer);
282   if (granuleshift == 0 || granuleshift == 64)
283     keyindex = 0;
284   else
285     keyindex = granulepos >> granuleshift;
286   keyoffset = granulepos - (keyindex << granuleshift);
287   fail_unless_equals_uint64 (keyindex * granulerate, prev);
288   fail_unless_equals_uint64 ((keyindex + keyoffset) * granulerate, start);
289 }
290
291 static void
292 check_clip (const gchar * name, const gchar * track,
293     GstClockTime start, GstClockTime prev)
294 {
295   gchar *encoded_clip;
296   GstBuffer *buffer;
297
298   encoded_clip = g_strdup_printf (CLIP_TEMPLATE_ENCODED, name, track);
299   check_output_buffer_is_equal (name, encoded_clip, 1);
300   g_free (encoded_clip);
301   buffer = GST_BUFFER (current_buf->data);
302   check_clip_times (buffer, start, prev);
303 }
304
305 static void
306 check_empty_clip (const gchar * name, const gchar * track,
307     GstClockTime start, GstClockTime prev)
308 {
309   gchar *encoded_clip;
310   GstBuffer *buffer;
311
312   encoded_clip = g_strdup_printf (EMPTY_CLIP_TEMPLATE_ENCODED, track);
313   check_output_buffer_is_equal (name, encoded_clip, 1);
314   g_free (encoded_clip);
315   buffer = GST_BUFFER (current_buf->data);
316   check_clip_times (buffer, start, prev);
317 }
318
319 GST_START_TEST (test_enc)
320 {
321   check_headers ();
322
323   flow = push_clip ("clip-1", "default", "1.234", NULL);
324   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
325   check_clip ("clip-1", "default", 1 * GST_SECOND + 234 * GST_MSECOND, 0);
326
327   flow = push_clip ("clip-2", "default", "5.678", NULL);
328   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
329   check_clip ("clip-2", "default",
330       5 * GST_SECOND + 678 * GST_MSECOND, 1 * GST_SECOND + 234 * GST_MSECOND);
331
332   flow = push_clip ("clip-3", "othertrack", "9.123", NULL);
333   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
334   check_clip ("clip-3", "othertrack", 9 * GST_SECOND + 123 * GST_MSECOND, 0);
335
336   flow = push_data ("end-tag", "</cmml>", strlen ("</cmml>"));
337   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
338   check_output_buffer_is_equal ("cmml-eos", NULL, 1);
339 }
340
341 GST_END_TEST;
342
343 GST_START_TEST (test_clip_end_time)
344 {
345   check_headers ();
346
347   /* push a clip that starts at 1.234 an ends at 2.234 */
348   flow = push_clip ("clip-1", "default", "1.234", "2.234");
349   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
350   check_clip ("clip-1", "default", 1 * GST_SECOND + 234 * GST_MSECOND, 0);
351
352   /* now check that the encoder created an empty clip starting at 2.234 to mark
353    * the end of clip-1 */
354   check_empty_clip ("clip-1-end", "default",
355       2 * GST_SECOND + 234 * GST_MSECOND, 1 * GST_SECOND + 234 * GST_MSECOND);
356
357   /* now push another clip on the same track and check that the keyindex part of
358    * the granulepos points to clip-1 and not to the empty clip */
359   flow = push_clip ("clip-2", "default", "5", NULL);
360   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
361   check_clip ("clip-2", "default",
362       5 * GST_SECOND, 1 * GST_SECOND + 234 * GST_MSECOND);
363 }
364
365 GST_END_TEST;
366
367 GST_START_TEST (test_time_order)
368 {
369   check_headers ();
370
371   /* clips belonging to the same track must have start times in non decreasing
372    * order */
373   flow = push_clip ("clip-1", "default", "1000:00:00.000", NULL);
374   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
375   check_clip ("clip-1", "default", 3600 * 1000 * GST_SECOND, 0);
376
377   /* this will make the encoder throw an error message */
378   flow = push_clip ("clip-2", "default", "5.678", NULL);
379   fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
380
381   flow = push_clip ("clip-3", "default", "1000:00:00.001", NULL);
382   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
383   check_clip ("clip-3", "default",
384       3600 * 1000 * GST_SECOND + 1 * GST_MSECOND, 3600 * 1000 * GST_SECOND);
385
386   /* tracks don't interfere with each other */
387   flow = push_clip ("clip-4", "othertrack", "9.123", NULL);
388   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
389   check_clip ("clip-4", "othertrack", 9 * GST_SECOND + 123 * GST_MSECOND, 0);
390 }
391
392 GST_END_TEST;
393
394 GST_START_TEST (test_time_parsing)
395 {
396   check_headers ();
397
398   flow = push_clip ("bad-msecs", "default", "0.1000", NULL);
399   fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
400
401   flow = push_clip ("bad-secs", "default", "00:00:60.123", NULL);
402   fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
403
404   flow = push_clip ("bad-minutes", "default", "00:60:12.345", NULL);
405   fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
406
407   /* this fails since we can't store 5124096 * 3600 * GST_SECOND in a
408    * GstClockTime */
409   flow = push_clip ("bad-hours", "default", "5124096:00:00.000", NULL);
410   fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
411 }
412
413 GST_END_TEST;
414
415 GST_START_TEST (test_time_limits)
416 {
417   check_headers ();
418
419   /* ugly hack to make sure that the following checks actually overflow parsing
420    * the times in gst_cmml_clock_time_from_npt rather than converting them to
421    * granulepos in gst_cmml_clock_time_to_granule */
422   granuleshift = 64;
423   g_object_set (cmmlenc, "granule-shift", granuleshift, NULL);
424
425   /* 5124095:34:33.709 is the max npt-hhmmss time representable with
426    * GstClockTime */
427   flow = push_clip ("max-npt-hhmmss", "foo", "5124095:34:33.709", NULL);
428   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
429   check_clip ("max-npt-hhmmss", "foo",
430       (GstClockTime) 5124095 * 3600 * GST_SECOND + 34 * 60 * GST_SECOND +
431       33 * GST_SECOND + 709 * GST_MSECOND, 0);
432
433   flow = push_clip ("overflow-max-npt-hhmmss", "overflows",
434       "5124095:34:33.710", NULL);
435   fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
436
437   /* 18446744073.709 is the max ntp-sec time */
438   flow = push_clip ("max-npt-secs", "bar", "18446744073.709", NULL);
439   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
440   check_clip ("max-npt-secs", "bar",
441       (GstClockTime) 5124095 * 3600 * GST_SECOND + 34 * 60 * GST_SECOND +
442       33 * GST_SECOND + 709 * GST_MSECOND, 0);
443
444   /* overflow doing 18446744074 * GST_SECOND */
445   flow = push_clip ("overflow-max-npt-secs", "overflows",
446       "18446744074.000", NULL);
447   fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
448
449   /* overflow doing seconds + milliseconds */
450   flow = push_clip ("overflow-max-npt-secs-msecs", "overflows",
451       "18446744073.710", NULL);
452   fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
453
454   /* reset granuleshift to 32 to check keyoffset overflows in
455    * gst_cmml_clock_time_to_granule */
456   granuleshift = 32;
457   g_object_set (cmmlenc, "granule-shift", granuleshift, NULL);
458
459   /* 1193:02:47.295 is the max time we can encode in the keyoffset part of a
460    * granulepos given a granuleshift of 32 */
461   flow = push_clip ("max-granule-keyoffset", "baz", "1193:02:47.295", NULL);
462   fail_unless_equals_flow_return (flow, GST_FLOW_OK);
463   check_clip ("max-granule-keyoffset", "baz",
464       1193 * 3600 * GST_SECOND + 2 * 60 * GST_SECOND +
465       47 * GST_SECOND + 295 * GST_MSECOND, 0);
466
467   flow = push_clip ("overflow-max-granule-keyoffset", "overflows",
468       "1193:02:47.296", NULL);
469   fail_unless_equals_flow_return (flow, GST_FLOW_ERROR);
470 }
471
472 GST_END_TEST;
473
474 static Suite *
475 cmmlenc_suite (void)
476 {
477   Suite *s = suite_create ("cmmlenc");
478   TCase *tc_general = tcase_create ("general");
479
480   suite_add_tcase (s, tc_general);
481   tcase_add_checked_fixture (tc_general, setup_cmmlenc, teardown_cmmlenc);
482   tcase_add_test (tc_general, test_enc);
483   tcase_add_test (tc_general, test_clip_end_time);
484   tcase_add_test (tc_general, test_time_order);
485   tcase_add_test (tc_general, test_time_parsing);
486   tcase_add_test (tc_general, test_time_limits);
487
488   return s;
489 }
490
491 GST_CHECK_MAIN (cmmlenc);