Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / tests / check / elements / subparse.c
1 /* GStreamer unit tests for subparse
2  * Copyright (C) 2006-2008 Tim-Philipp Müller <tim centricular net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <gst/check/gstcheck.h>
25
26 #include <string.h>
27
28 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
29     GST_PAD_SINK,
30     GST_PAD_ALWAYS,
31     GST_STATIC_CAPS ("text/plain; text/x-pango-markup")
32     );
33 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
34     GST_PAD_SRC,
35     GST_PAD_ALWAYS,
36     GST_STATIC_CAPS ("ANY")
37     );
38
39 static GstElement *subparse;
40 static GstPad *mysrcpad, *mysinkpad;
41
42 static GstBuffer *
43 buffer_from_static_string (const gchar * s)
44 {
45   GstBuffer *buf;
46
47   buf = gst_buffer_new ();
48   GST_BUFFER_DATA (buf) = (guint8 *) s;
49   GST_BUFFER_SIZE (buf) = strlen (s);
50   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
51
52   return buf;
53 }
54
55 typedef struct
56 {
57   const gchar *in;
58   GstClockTime from_ts;
59   GstClockTime to_ts;
60   const gchar *out;
61 } SubParseInputChunk;
62
63 static SubParseInputChunk srt_input[] = {
64   {
65         "1\n00:00:01,000 --> 00:00:02,000\nOne\n\n",
66       1 * GST_SECOND, 2 * GST_SECOND, "One"}, {
67         "2\n00:00:02,000 --> 00:00:03,000\nTwo\n\n",
68       2 * GST_SECOND, 3 * GST_SECOND, "Two"}, {
69         "3\n00:00:03,000 --> 00:00:04,000\nThree\n\n",
70       3 * GST_SECOND, 4 * GST_SECOND, "Three"}, {
71         "4\n00:00:04,000 --> 00:00:05,000\nFour\n\n",
72       4 * GST_SECOND, 5 * GST_SECOND, "Four"}, {
73         "5\n00:00:05,000 --> 00:00:06,000\nFive\n\n",
74       5 * GST_SECOND, 6 * GST_SECOND, "Five"}, {
75         /* markup should be preserved */
76         "6\n00:00:06,000 --> 00:00:07,000\n<i>Six</i>\n\n",
77       6 * GST_SECOND, 7 * GST_SECOND, "<i>Six</i>"}, {
78         /* open markup tags should be closed */
79         "7\n00:00:07,000 --> 00:00:08,000\n<i>Seven\n\n",
80       7 * GST_SECOND, 8 * GST_SECOND, "<i>Seven</i>"}, {
81         /* open markup tags should be closed (II) */
82         "8\n00:00:08,000 --> 00:00:09,000\n<b><i>Eight\n\n",
83       8 * GST_SECOND, 9 * GST_SECOND, "<b><i>Eight</i></b>"}, {
84         /* broken markup should be fixed */
85         "9\n00:00:09,000 --> 00:00:10,000\n</b>\n\n",
86       9 * GST_SECOND, 10 * GST_SECOND, ""}, {
87         "10\n00:00:10,000 --> 00:00:11,000\n</b></i>\n\n",
88       10 * GST_SECOND, 11 * GST_SECOND, ""}, {
89         "11\n00:00:11,000 --> 00:00:12,000\n<i>xyz</b></i>\n\n",
90       11 * GST_SECOND, 12 * GST_SECOND, "<i>xyz</i>"}, {
91         "12\n00:00:12,000 --> 00:00:13,000\n<i>xyz</b>\n\n",
92       12 * GST_SECOND, 13 * GST_SECOND, "<i>xyz</i>"}, {
93         /* skip a few chunk numbers here, the numbers shouldn't matter */
94         "24\n00:01:00,000 --> 00:02:00,000\nYep, still here\n\n",
95       60 * GST_SECOND, 120 * GST_SECOND, "Yep, still here"}, {
96         /* make sure stuff is escaped properly, but allowed markup stays intact */
97         "25\n00:03:00,000 --> 00:04:00,000\ngave <i>Rock & Roll</i> to\n\n",
98       180 * GST_SECOND, 240 * GST_SECOND, "gave <i>Rock &amp; Roll</i> to"}, {
99         "26\n00:04:00,000 --> 00:05:00,000\n<i>Rock & Roll</i>\n\n",
100       240 * GST_SECOND, 300 * GST_SECOND, "<i>Rock &amp; Roll</i>"}, {
101         "27\n00:06:00,000 --> 00:08:00,000\nRock & Roll\n\n",
102       360 * GST_SECOND, 480 * GST_SECOND, "Rock &amp; Roll"}, {
103         "28\n00:10:00,000 --> 00:11:00,000\n"
104         "<font \"#0000FF\"><joj>This is </xxx>in blue but <5</font>\n\n",
105       600 * GST_SECOND, 660 * GST_SECOND, "This is in blue but &lt;5"}
106 };
107
108 /* starts with chunk number 0 (not exactly according to spec) */
109 static SubParseInputChunk srt_input0[] = {
110   {
111         "0\n00:00:01,000 --> 00:00:02,000\nOne\n\n",
112       1 * GST_SECOND, 2 * GST_SECOND, "One"}, {
113         "1\n00:00:02,000 --> 00:00:03,000\nTwo\n\n",
114       2 * GST_SECOND, 3 * GST_SECOND, "Two"}, {
115         "2\n00:00:03,000 --> 00:00:04,000\nThree\n\n",
116       3 * GST_SECOND, 4 * GST_SECOND, "Three"}
117 };
118
119 /* has spaces instead of doubled zeroes (not exactly according to spec) */
120 static SubParseInputChunk srt_input1[] = {
121   {
122         "1\n 0: 0:26, 26 --> 0: 0:28, 17\nI cant see.\n\n",
123         26 * GST_SECOND + 26 * GST_MSECOND,
124       28 * GST_SECOND + 17 * GST_MSECOND, "I cant see."},
125   {
126         "2\n 0: 0:30, 30 --> 0: 0:33, 22\nI really cant see.\n\n",
127         30 * GST_SECOND + 30 * GST_MSECOND,
128       33 * GST_SECOND + 22 * GST_MSECOND, "I really cant see."},
129   {
130         "3\n 0: 0:40, 40 --> 0: 0:44, 44\nI still cant see anything.\n\n",
131         40 * GST_SECOND + 40 * GST_MSECOND,
132       44 * GST_SECOND + 44 * GST_MSECOND, "I still cant see anything."}
133 };
134
135 /* has UTF-8 BOM at the start */
136 static SubParseInputChunk srt_input2[] = {
137   {
138         "\xef\xbb\xbf" "1\n00:00:00,000 --> 00:00:03,50\nJust testing.\n\n",
139       0, 3 * GST_SECOND + 50 * GST_MSECOND, "Just testing."}
140 };
141
142 /* starts with chunk number 0 and has less than three digits after the comma
143  * and a few extra spaces before the arrow or at the end of the line */
144 static SubParseInputChunk srt_input3[] = {
145   {
146         "0\n00:00:01,0 --> 00:00:02,0\nOne\n\n",
147       1000 * GST_MSECOND, 2000 * GST_MSECOND, "One"}, {
148         "1\n00:00:02,5   --> 00:00:03,  5 \nTwo\n\n",
149       2500 * GST_MSECOND, 3005 * GST_MSECOND, "Two"}, {
150         "2\n00:00:03, 9 --> 00:00:04,0   \nThree\n\n",
151       3090 * GST_MSECOND, 4000 * GST_MSECOND, "Three"}
152 };
153
154 static void
155 setup_subparse (void)
156 {
157   subparse = gst_check_setup_element ("subparse");
158
159   mysrcpad = gst_check_setup_src_pad (subparse, &srctemplate, NULL);
160   mysinkpad = gst_check_setup_sink_pad (subparse, &sinktemplate, NULL);
161
162   gst_pad_set_active (mysrcpad, TRUE);
163   gst_pad_set_active (mysinkpad, TRUE);
164
165   fail_unless_equals_int (gst_element_set_state (subparse, GST_STATE_PLAYING),
166       GST_STATE_CHANGE_SUCCESS);
167 }
168
169 static void
170 teardown_subparse (void)
171 {
172   GST_DEBUG ("cleaning up");
173
174   g_list_foreach (buffers, (GFunc) gst_mini_object_unref, NULL);
175   g_list_free (buffers);
176   buffers = NULL;
177
178   gst_pad_set_active (mysrcpad, FALSE);
179   gst_pad_set_active (mysinkpad, FALSE);
180   gst_check_teardown_sink_pad (subparse);
181   gst_check_teardown_src_pad (subparse);
182   gst_check_teardown_element (subparse);
183   subparse = NULL;
184   mysrcpad = NULL;
185   mysinkpad = NULL;
186 }
187
188 static void
189 test_srt_do_test (SubParseInputChunk * input, guint start_idx, guint num)
190 {
191   guint n;
192
193   GST_LOG ("srt test: start_idx = %u, num = %u", start_idx, num);
194
195   setup_subparse ();
196
197   for (n = start_idx; n < start_idx + num; ++n) {
198     GstBuffer *buf;
199
200     buf = buffer_from_static_string (input[n].in);
201     fail_unless_equals_int (gst_pad_push (mysrcpad, buf), GST_FLOW_OK);
202   }
203
204   gst_pad_push_event (mysrcpad, gst_event_new_eos ());
205
206   fail_unless_equals_int (g_list_length (buffers), num);
207
208   for (n = start_idx; n < start_idx + num; ++n) {
209     const GstStructure *buffer_caps_struct;
210     GstBuffer *buf;
211     gchar *out;
212     guint out_size;
213
214     buf = g_list_nth_data (buffers, n - start_idx);
215     fail_unless (buf != NULL);
216     fail_unless (GST_BUFFER_TIMESTAMP_IS_VALID (buf), NULL);
217     fail_unless (GST_BUFFER_DURATION_IS_VALID (buf), NULL);
218     fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buf), input[n].from_ts);
219     fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf),
220         input[n].to_ts - input[n].from_ts);
221     out = (gchar *) GST_BUFFER_DATA (buf);
222     out_size = GST_BUFFER_SIZE (buf);
223     /* shouldn't have trailing newline characters */
224     fail_if (out_size > 0 && out[out_size - 1] == '\n');
225     /* shouldn't include NUL-terminator in data size */
226     fail_if (out_size > 0 && out[out_size - 1] == '\0');
227     /* but should still have a  NUL-terminator behind the declared data */
228     fail_unless_equals_int (out[out_size], '\0');
229     /* make sure out string matches expected string */
230     fail_unless_equals_string (out, input[n].out);
231     /* check caps */
232     fail_unless (GST_BUFFER_CAPS (buf) != NULL);
233     buffer_caps_struct = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
234     fail_unless_equals_string (gst_structure_get_name (buffer_caps_struct),
235         "text/x-pango-markup");
236   }
237
238   teardown_subparse ();
239 }
240
241 GST_START_TEST (test_srt)
242 {
243   test_srt_do_test (srt_input, 0, G_N_ELEMENTS (srt_input));
244
245   /* make sure everything works fine if we don't start with chunk 1 */
246   test_srt_do_test (srt_input, 1, G_N_ELEMENTS (srt_input) - 1);
247   test_srt_do_test (srt_input, 2, G_N_ELEMENTS (srt_input) - 2);
248   test_srt_do_test (srt_input, 3, G_N_ELEMENTS (srt_input) - 3);
249   test_srt_do_test (srt_input, 4, G_N_ELEMENTS (srt_input) - 4);
250
251   /* try with empty input, immediate EOS */
252   test_srt_do_test (srt_input, 5, G_N_ELEMENTS (srt_input) - 5);
253
254   /* try with chunk number 0 (which is not exactly according to spec) */
255   test_srt_do_test (srt_input0, 0, G_N_ELEMENTS (srt_input0));
256
257   /* try with spaces instead of doubled zeroes (which is not exactly according to spec) */
258   test_srt_do_test (srt_input1, 0, G_N_ELEMENTS (srt_input1));
259
260   /* try with UTF-8 BOM at the start */
261   test_srt_do_test (srt_input1, 0, G_N_ELEMENTS (srt_input2));
262
263   /* try with fewer than three post-comma digits, and some extra spaces */
264   test_srt_do_test (srt_input3, 0, G_N_ELEMENTS (srt_input3));
265 }
266
267 GST_END_TEST;
268
269 static void
270 do_test (SubParseInputChunk * input, guint num, const gchar * media_type)
271 {
272   guint n;
273
274   setup_subparse ();
275
276   for (n = 0; n < num; ++n) {
277     GstBuffer *buf;
278
279     buf = buffer_from_static_string (input[n].in);
280     fail_unless_equals_int (gst_pad_push (mysrcpad, buf), GST_FLOW_OK);
281   }
282
283   gst_pad_push_event (mysrcpad, gst_event_new_eos ());
284
285   fail_unless_equals_int (g_list_length (buffers), num);
286
287   for (n = 0; n < num; ++n) {
288     const GstStructure *buffer_caps_struct;
289     GstBuffer *buf;
290     gchar *out;
291     guint out_size;
292
293     buf = g_list_nth_data (buffers, n);
294     fail_unless (buf != NULL);
295
296     /* check timestamp */
297     fail_unless (GST_BUFFER_TIMESTAMP_IS_VALID (buf), NULL);
298     fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buf), input[n].from_ts);
299
300     /* might not be able to put a duration on the last buffer */
301     if (input[n].to_ts != GST_CLOCK_TIME_NONE) {
302       /* check duration */
303       fail_unless (GST_BUFFER_DURATION_IS_VALID (buf), NULL);
304       fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf),
305           input[n].to_ts - input[n].from_ts);
306     }
307
308     out = (gchar *) GST_BUFFER_DATA (buf);
309     out_size = GST_BUFFER_SIZE (buf);
310     /* shouldn't have trailing newline characters */
311     fail_if (out_size > 0 && out[out_size - 1] == '\n');
312     /* shouldn't include NUL-terminator in data size */
313     fail_if (out_size > 0 && out[out_size - 1] == '\0');
314     /* but should still have a  NUL-terminator behind the declared data */
315     fail_unless_equals_int (out[out_size], '\0');
316     /* make sure out string matches expected string */
317     fail_unless_equals_string (out, input[n].out);
318     /* check caps */
319     fail_unless (GST_BUFFER_CAPS (buf) != NULL);
320     buffer_caps_struct = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
321     fail_unless_equals_string (gst_structure_get_name (buffer_caps_struct),
322         media_type);
323   }
324
325   teardown_subparse ();
326 }
327
328 static void
329 test_tmplayer_do_test (SubParseInputChunk * input, guint num)
330 {
331   do_test (input, num, "text/plain");
332 }
333
334 static void
335 test_microdvd_do_test (SubParseInputChunk * input, guint num)
336 {
337   do_test (input, num, "text/x-pango-markup");
338 }
339
340 GST_START_TEST (test_tmplayer_multiline)
341 {
342   static SubParseInputChunk tmplayer_multiline_input[] = {
343     {
344           "00:00:10,1=This is the Earth at a time\n"
345           "00:00:10,2=when the dinosaurs roamed...\n" "00:00:13,1=\n",
346           10 * GST_SECOND, 13 * GST_SECOND,
347         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
348           "00:00:14,1=a lush and fertile planet.\n" "00:00:16,1=\n",
349           14 * GST_SECOND, 16 * GST_SECOND,
350         "a lush and fertile planet."}
351   };
352
353   test_tmplayer_do_test (tmplayer_multiline_input,
354       G_N_ELEMENTS (tmplayer_multiline_input));
355 }
356
357 GST_END_TEST;
358
359 GST_START_TEST (test_tmplayer_multiline_with_bogus_lines)
360 {
361   static SubParseInputChunk tmplayer_multiline_b_input[] = {
362     {
363           "00:00:10,1=This is the Earth at a time\n"
364           "Yooboo wabahablablahuguug bogus line hello test 1-2-3-4\n"
365           "00:00:10,2=when the dinosaurs roamed...\n" "00:00:13,1=\n",
366           10 * GST_SECOND, 13 * GST_SECOND,
367         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
368           "00:00:14,1=a lush and fertile planet.\n" "00:00:16,1=\n",
369           14 * GST_SECOND, 16 * GST_SECOND,
370         "a lush and fertile planet."}
371   };
372
373   test_tmplayer_do_test (tmplayer_multiline_b_input,
374       G_N_ELEMENTS (tmplayer_multiline_b_input));
375 }
376
377 GST_END_TEST;
378
379 GST_START_TEST (test_tmplayer_style1)
380 {
381   static SubParseInputChunk tmplayer_style1_input[] = {
382     {
383           "00:00:10:This is the Earth at a time|when the dinosaurs roamed...\n"
384           "00:00:13:\n",
385           10 * GST_SECOND, 13 * GST_SECOND,
386         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
387           "00:00:14:a lush and fertile planet.\n" "00:00:16:\n",
388           14 * GST_SECOND, 16 * GST_SECOND,
389         "a lush and fertile planet."}
390   };
391
392   test_tmplayer_do_test (tmplayer_style1_input,
393       G_N_ELEMENTS (tmplayer_style1_input));
394 }
395
396 GST_END_TEST;
397
398 GST_START_TEST (test_tmplayer_style2)
399 {
400   static SubParseInputChunk tmplayer_style2_input[] = {
401     {
402           "00:00:10=This is the Earth at a time|when the dinosaurs roamed...\n"
403           "00:00:13=\n",
404           10 * GST_SECOND, 13 * GST_SECOND,
405         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
406           "00:00:14=a lush and fertile planet.\n" "00:00:16=\n",
407           14 * GST_SECOND, 16 * GST_SECOND,
408         "a lush and fertile planet."}
409   };
410
411   test_tmplayer_do_test (tmplayer_style2_input,
412       G_N_ELEMENTS (tmplayer_style2_input));
413 }
414
415 GST_END_TEST;
416
417 GST_START_TEST (test_tmplayer_style3)
418 {
419   static SubParseInputChunk tmplayer_style3_input[] = {
420     {
421           "0:00:10:This is the Earth at a time|when the dinosaurs roamed...\n"
422           "0:00:13:\n",
423           10 * GST_SECOND, 13 * GST_SECOND,
424         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
425           "0:00:14:a lush and fertile planet.\n" "0:00:16:\n",
426           14 * GST_SECOND, 16 * GST_SECOND,
427         "a lush and fertile planet."}
428   };
429
430   test_tmplayer_do_test (tmplayer_style3_input,
431       G_N_ELEMENTS (tmplayer_style3_input));
432 }
433
434 GST_END_TEST;
435
436 /* also tests the max_duration stuff (see second-last chunk which is supposed
437  * to be clipped to 5s duration) */
438 GST_START_TEST (test_tmplayer_style3b)
439 {
440   static SubParseInputChunk tmplayer_style3b_input[] = {
441     {
442           "0:00:10:This is the Earth at a time|when the dinosaurs roamed...\n",
443           10 * GST_SECOND, 14 * GST_SECOND,
444         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
445           "0:00:14:a lush and fertile planet.\n",
446           14 * GST_SECOND, 16 * GST_SECOND,
447         "a lush and fertile planet."}, {
448           "0:00:16:And they liked it a lot.\n",
449         16 * GST_SECOND, (16 + 5) * GST_SECOND, "And they liked it a lot."}, {
450           "0:00:30:Last line.",
451         30 * GST_SECOND, GST_CLOCK_TIME_NONE, "Last line."}
452   };
453
454   test_tmplayer_do_test (tmplayer_style3b_input,
455       G_N_ELEMENTS (tmplayer_style3b_input));
456 }
457
458 GST_END_TEST;
459
460 GST_START_TEST (test_tmplayer_style4)
461 {
462   static SubParseInputChunk tmplayer_style4_input[] = {
463     {
464           "0:00:10=This is the Earth at a time|when the dinosaurs roamed...\n"
465           "0:00:13=\n",
466           10 * GST_SECOND, 13 * GST_SECOND,
467         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
468           "0:00:14=a lush and fertile planet.\n" "0:00:16=\n",
469           14 * GST_SECOND, 16 * GST_SECOND,
470         "a lush and fertile planet."}
471   };
472
473   test_tmplayer_do_test (tmplayer_style4_input,
474       G_N_ELEMENTS (tmplayer_style4_input));
475 }
476
477 GST_END_TEST;
478
479 GST_START_TEST (test_tmplayer_style4_with_bogus_lines)
480 {
481   static SubParseInputChunk tmplayer_style4b_input[] = {
482     {
483           "0:00:10=This is the Earth at a time|when the dinosaurs roamed...\n"
484           "# This is a bogus line with a comment and should just be skipped\n"
485           "0:00:13=\n",
486           10 * GST_SECOND, 13 * GST_SECOND,
487         "This is the Earth at a time\nwhen the dinosaurs roamed..."}, {
488           "0:00:14=a lush and fertile planet.\n"
489           "                                                            \n"
490           "0:00:16=\n",
491           14 * GST_SECOND, 16 * GST_SECOND,
492         "a lush and fertile planet."}
493   };
494
495   test_tmplayer_do_test (tmplayer_style4b_input,
496       G_N_ELEMENTS (tmplayer_style4b_input));
497 }
498
499 GST_END_TEST;
500
501 GST_START_TEST (test_microdvd_with_italics)
502 {
503   static SubParseInputChunk microdvd_italics[] = {
504     {
505           "{1}{1}25.000 movie info: XVID  608x256 25.0fps 699.0 MB|"
506           "/SubEdit b.4060(http://subedit.com.pl)/\n"
507           "{100}{200}/italics/|not italics\n",
508           4 * GST_SECOND, 8 * GST_SECOND,
509         "<span style=\"italic\">italics</span>\n" "<span>not italics</span>"}
510   };
511
512   test_microdvd_do_test (microdvd_italics, G_N_ELEMENTS (microdvd_italics));
513 }
514
515 GST_END_TEST;
516
517 GST_START_TEST (test_microdvd_with_fps)
518 {
519   static SubParseInputChunk microdvd_input[] = {
520     {
521           "{1}{1}12.500\n{100}{200}- Hi, Eddie.|- Hiya, Scotty.\n",
522           8 * GST_SECOND, 16 * GST_SECOND,
523         "<span>- Hi, Eddie.</span>\n<span>- Hiya, Scotty.</span>"}, {
524           "{1250}{1350}- Cold enough for you?|- Well, I'm only faintly alive. "
525           "It's 25 below\n",
526           100 * GST_SECOND, 108 * GST_SECOND,
527         "<span>- Cold enough for you?</span>\n"
528           "<span>- Well, I&apos;m only faintly alive. It&apos;s 25 below</span>"}
529   };
530
531   test_microdvd_do_test (microdvd_input, G_N_ELEMENTS (microdvd_input));
532
533   /* and the same with ',' instead of '.' as floating point divider */
534   microdvd_input[0].in =
535       "{1}{1}12,500\n{100}{200}- Hi, Eddie.|- Hiya, Scotty.\n";
536   test_microdvd_do_test (microdvd_input, G_N_ELEMENTS (microdvd_input));
537 }
538
539 GST_END_TEST;
540
541 GST_START_TEST (test_mpl2)
542 {
543   SubParseInputChunk mpl2_input[] = {
544     {
545           "[123][456] This is the Earth at a time|when the dinosaurs roamed\n",
546           (123 * GST_SECOND) / 10, (456 * GST_SECOND) / 10,
547         "This is the Earth at a time\nwhen the dinosaurs roamed"}, {
548           "[1234][5678]a lush and fertile planet.\n",
549           (1234 * GST_SECOND) / 10, (5678 * GST_SECOND) / 10,
550         "a lush and fertile planet."}, {
551           "[12345][27890] /Italic|Normal\n",
552           (12345 * GST_SECOND) / 10, (27890 * GST_SECOND) / 10,
553         "<i>Italic</i>\nNormal"}, {
554           "[32345][37890]/Italic|/Italic\n",
555           (32345 * GST_SECOND) / 10, (37890 * GST_SECOND) / 10,
556         "<i>Italic</i>\n<i>Italic</i>"}, {
557           "[42345][47890] Normal|/Italic",
558           (42345 * GST_SECOND) / 10, (47890 * GST_SECOND) / 10,
559         "Normal\n<i>Italic</i>"}
560   };
561
562   do_test (mpl2_input, G_N_ELEMENTS (mpl2_input), "text/x-pango-markup");
563 }
564
565 GST_END_TEST;
566
567 GST_START_TEST (test_subviewer)
568 {
569   SubParseInputChunk subviewer_input[] = {
570     {
571           "[INFORMATION]\n"
572           "[TITLE]xxxxxxxxxx\n"
573           "[AUTHOR]xxxxxxxx\n"
574           "[SOURCE]xxxxxxxxxxxxxxxx\n"
575           "[FILEPATH]\n"
576           "[DELAY]0\n"
577           "[COMMENT]\n"
578           "[END INFORMATION]\n"
579           "[SUBTITLE]\n"
580           "[COLF]&HFFFFFF,[STYLE]bd,[SIZE]18,[FONT]Arial\n"
581           "00:00:41.00,00:00:44.40\n"
582           "The Age of Gods was closing.\n"
583           "Eternity had come to an end.\n"
584           "\n", 41 * GST_SECOND, 44 * GST_SECOND + 40 * GST_MSECOND,
585         "The Age of Gods was closing.\nEternity had come to an end."}, {
586           "00:00:55.00,00:00:58.40\n"
587           "The heavens shook as the armies\n"
588           "of Falis, God of Light...\n\n", 55 * GST_SECOND,
589           58 * GST_SECOND + 40 * GST_MSECOND,
590         "The heavens shook as the armies\nof Falis, God of Light..."}
591   };
592
593   do_test (subviewer_input, G_N_ELEMENTS (subviewer_input), "text/plain");
594 }
595
596 GST_END_TEST;
597
598 GST_START_TEST (test_subviewer2)
599 {
600   SubParseInputChunk subviewer2_input[] = {
601     {
602           "[INFORMATION]\n"
603           "[TITLE]xxxxxxxxxx\n"
604           "[AUTHOR]xxxxxxxxxx\n"
605           "[SOURCE]xxxxxxxxxx\n"
606           "[PRG]\n"
607           "[FILEPATH]\n"
608           "[DELAY]0\n"
609           "[CD TRACK]0\n"
610           "[COMMENT]\n"
611           "[END INFORMATION]\n"
612           "[SUBTITLE]\n"
613           "[COLF]&H00FFFF,[STYLE]no,[SIZE]12,[FONT]Courier New\n"
614           "00:00:07.00,00:00:11.91\n"
615           "THERE IS A PLACE ON EARTH WHERE IT[br]IS STILL THE MORNING OF LIFE...\n\n",
616           7 * GST_SECOND, 11 * GST_SECOND + 91 * GST_MSECOND,
617         "THERE IS A PLACE ON EARTH WHERE IT\nIS STILL THE MORNING OF LIFE..."}, {
618           "00:00:12.48,00:00:15.17\n"
619           "AND THE GREAT HERDS RUN FREE.[br]SO WHAT?!\n\n",
620           12 * GST_SECOND + 48 * GST_MSECOND,
621           15 * GST_SECOND + 17 * GST_MSECOND,
622         "AND THE GREAT HERDS RUN FREE.\nSO WHAT?!"}
623   };
624
625   do_test (subviewer2_input, G_N_ELEMENTS (subviewer2_input), "text/plain");
626 }
627
628 GST_END_TEST;
629
630 GST_START_TEST (test_dks)
631 {
632   SubParseInputChunk dks_input[] = {
633     {
634           "[00:00:07]THERE IS A PLACE ON EARTH WHERE IT[br]IS STILL THE MORNING OF LIFE...\n[00:00:12]\n",
635           7 * GST_SECOND, 12 * GST_SECOND,
636         "THERE IS A PLACE ON EARTH WHERE IT\nIS STILL THE MORNING OF LIFE..."}, {
637           "[00:00:13]AND THE GREAT HERDS RUN FREE.[br]SO WHAT?!\n[00:00:15]\n",
638           13 * GST_SECOND, 15 * GST_SECOND,
639         "AND THE GREAT HERDS RUN FREE.\nSO WHAT?!"}
640   };
641
642   do_test (dks_input, G_N_ELEMENTS (dks_input), "text/plain");
643 }
644
645 GST_END_TEST;
646
647 #ifndef GST_DISABLE_XML
648 GST_START_TEST (test_sami)
649 {
650   SubParseInputChunk sami_input[] = {
651     {"<SAMI>\n"
652           "<HEAD>\n"
653           "    <TITLE>Subtitle</TITLE>\n"
654           "    <STYLE TYPE=\"text/css\">\n"
655           "    <!--\n"
656           "        P {margin-left:8pt; margin-right:8pt; margin-bottom:2pt; margin-top:2pt; text-align:center; font-size:12pt; font-weight:normal; color:black;}\n"
657           "        .CC {Name:English; lang:en-AU; SAMIType:CC;}\n"
658           "        #STDPrn {Name:Standard Print;}\n"
659           "        #LargePrn {Name:Large Print; font-size:24pt;}\n"
660           "        #SmallPrn {Name:Small Print; font-size:16pt;}\n"
661           "    -->\n"
662           "    </Style>\n"
663           "</HEAD>\n"
664           "<BODY>\n"
665           "    <SYNC Start=1000>\n"
666           "        <P Class=CC>\n"
667           "            This is a comment.<br>\n"
668           "            This is a second comment.\n",
669           1000 * GST_MSECOND, 2000 * GST_MSECOND,
670         "This is a comment.\nThis is a second comment."},
671     {"    <SYNC Start=2000>\n"
672           "        <P Class=CC>\n"
673           "            This is a third comment.<br>\n"
674           "            This is a fourth comment.\n" "</BODY>\n" "</SAMI>\n",
675           2000 * GST_MSECOND, GST_CLOCK_TIME_NONE,
676         "This is a third comment.\nThis is a fourth comment."}
677   };
678
679   do_test (sami_input, G_N_ELEMENTS (sami_input), "text/x-pango-markup");
680 }
681
682 GST_END_TEST;
683 #endif
684
685 /* TODO:
686  *  - add/modify tests so that lines aren't dogfed to the parsers in complete
687  *    lines or sets of complete lines, but rather in random chunks
688  */
689
690 static Suite *
691 subparse_suite (void)
692 {
693   Suite *s = suite_create ("subparse");
694   TCase *tc_chain = tcase_create ("general");
695
696   suite_add_tcase (s, tc_chain);
697
698   tcase_add_test (tc_chain, test_srt);
699   tcase_add_test (tc_chain, test_tmplayer_multiline);
700   tcase_add_test (tc_chain, test_tmplayer_multiline_with_bogus_lines);
701   tcase_add_test (tc_chain, test_tmplayer_style1);
702   tcase_add_test (tc_chain, test_tmplayer_style2);
703   tcase_add_test (tc_chain, test_tmplayer_style3);
704   tcase_add_test (tc_chain, test_tmplayer_style3b);
705   tcase_add_test (tc_chain, test_tmplayer_style4);
706   tcase_add_test (tc_chain, test_tmplayer_style4_with_bogus_lines);
707   tcase_add_test (tc_chain, test_microdvd_with_fps);
708   tcase_add_test (tc_chain, test_microdvd_with_italics);
709   tcase_add_test (tc_chain, test_mpl2);
710   tcase_add_test (tc_chain, test_subviewer);
711   tcase_add_test (tc_chain, test_subviewer2);
712   tcase_add_test (tc_chain, test_dks);
713 #ifndef GST_DISABLE_XML
714   tcase_add_test (tc_chain, test_sami);
715 #endif
716   return s;
717 }
718
719 GST_CHECK_MAIN (subparse);