1 /* GStreamer tmplayer format subtitle parser |
1 /* GStreamer tmplayer format subtitle parser |
2 * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net> |
2 * Copyright (C) 2006-2008 Tim-Philipp Müller <tim centricular net> |
3 * |
3 * |
4 * This library is free software; you can redistribute it and/or |
4 * This library is free software; you can redistribute it and/or |
5 * modify it under the terms of the GNU Library General Public |
5 * modify it under the terms of the GNU Library General Public |
6 * License as published by the Free Software Foundation; either |
6 * License as published by the Free Software Foundation; either |
7 * version 2 of the License, or (at your option) any later version. |
7 * version 2 of the License, or (at your option) any later version. |
53 * 00:00:50,1=This is the Earth at a time |
53 * 00:00:50,1=This is the Earth at a time |
54 * 00:00:50,2=when the dinosaurs roamed... |
54 * 00:00:50,2=when the dinosaurs roamed... |
55 * 00:00:53,1= |
55 * 00:00:53,1= |
56 * 00:00:54,1=a lush and fertile planet. |
56 * 00:00:54,1=a lush and fertile planet. |
57 * 00:00:56,1= |
57 * 00:00:56,1= |
|
58 * |
|
59 * -------------------------------------------------------------------------- |
|
60 * |
|
61 * And another variety (which is 'time-base 0:00:00:' but without empty lines): |
|
62 * |
|
63 * 00:00:01:This is the Earth at a time|when the dinosaurs roamed... |
|
64 * 00:00:03:a lush and fertile planet. |
|
65 * 00:00:06:More text here |
|
66 * 00:00:12:Yet another line |
|
67 * |
58 */ |
68 */ |
|
69 |
|
70 static gchar * |
|
71 tmplayer_process_buffer (ParserState * state) |
|
72 { |
|
73 gchar *ret; |
|
74 |
|
75 ret = g_strndup (state->buf->str, state->buf->len); |
|
76 g_strdelimit (ret, "|", '\n'); |
|
77 g_string_truncate (state->buf, 0); |
|
78 return ret; |
|
79 } |
59 |
80 |
60 static gchar * |
81 static gchar * |
61 tmplayer_parse_line (ParserState * state, const gchar * line, guint line_num) |
82 tmplayer_parse_line (ParserState * state, const gchar * line, guint line_num) |
62 { |
83 { |
63 GstClockTime ts = GST_CLOCK_TIME_NONE; |
84 GstClockTime ts = GST_CLOCK_TIME_NONE; |
76 } else if (sscanf (line, "%u:%02u:%02u%c", &h, &m, &s, &divc) == 4 && |
97 } else if (sscanf (line, "%u:%02u:%02u%c", &h, &m, &s, &divc) == 4 && |
77 (divc == '=' || divc == ':')) { |
98 (divc == '=' || divc == ':')) { |
78 GST_LOG ("single line format %u %u %u %u %c", h, m, s, l, divc); |
99 GST_LOG ("single line format %u %u %u %u %c", h, m, s, l, divc); |
79 ts = GST_SECOND * ((((h * 60) + m) * 60) + s); |
100 ts = GST_SECOND * ((((h * 60) + m) * 60) + s); |
80 text_start = strchr (line + 6, divc); |
101 text_start = strchr (line + 6, divc); |
|
102 } else if (line[0] == '\0' && state->buf->len > 0 && |
|
103 GST_CLOCK_TIME_IS_VALID (state->start_time)) { |
|
104 /* if we get an empty line (could be the end of the file, but doesn't have |
|
105 * to be), just push whatever is still in the buffer without a duration */ |
|
106 GST_LOG ("empty line, and there's still text in the buffer"); |
|
107 ret = tmplayer_process_buffer (state); |
|
108 state->duration = GST_CLOCK_TIME_NONE; |
|
109 return ret; |
81 } else { |
110 } else { |
82 GST_WARNING ("failed to parse line: '%s'", line); |
111 GST_WARNING ("failed to parse line: '%s'", line); |
83 return NULL; |
112 return NULL; |
84 } |
113 } |
85 |
114 |
|
115 /* if this is a line without text, or the first line in a multiline file, |
|
116 * process and return the data in the buffer, which is the previous line(s) */ |
86 if (text_start == NULL || text_start[1] == '\0' || |
117 if (text_start == NULL || text_start[1] == '\0' || |
87 (l == 1 && state->buf->len > 0)) { |
118 (l == 1 && state->buf->len > 0)) { |
|
119 |
88 if (GST_CLOCK_TIME_IS_VALID (state->start_time) && |
120 if (GST_CLOCK_TIME_IS_VALID (state->start_time) && |
89 state->start_time < ts && line_num > 0) { |
121 state->start_time < ts && line_num > 0) { |
90 ret = g_strndup (state->buf->str, state->buf->len); |
122 ret = tmplayer_process_buffer (state); |
91 g_strdelimit (ret, "|", '\n'); |
|
92 g_string_truncate (state->buf, 0); |
|
93 state->duration = ts - state->start_time; |
123 state->duration = ts - state->start_time; |
|
124 /* ..and append current line's text (if there is any) for the next round. |
|
125 * We don't have to store ts as pending_start_time, since we deduce the |
|
126 * durations from the start times anyway, so as long as the parser just |
|
127 * forwards state->start_time by duration after it pushes the line we |
|
128 * are about to return it will all be good. */ |
|
129 g_string_append (state->buf, text_start + 1); |
94 } else if (line_num > 0) { |
130 } else if (line_num > 0) { |
95 GST_WARNING ("end of subtitle unit but no valid start time?!"); |
131 GST_WARNING ("end of subtitle unit but no valid start time?!"); |
96 } |
132 } |
97 } else { |
133 } else { |
98 if (l > 1) |
134 if (l > 1) |
99 g_string_append_c (state->buf, '\n'); |
135 g_string_append_c (state->buf, '\n'); |
100 g_string_append (state->buf, text_start + 1); |
136 g_string_append (state->buf, text_start + 1); |
101 state->start_time = ts; |
137 state->start_time = ts; |
102 } |
138 } |
103 |
139 |
|
140 GST_LOG ("returning: '%s'", GST_STR_NULL (ret)); |
104 return ret; |
141 return ret; |
105 } |
142 } |
106 #ifdef __SYMBIAN32__ |
143 #ifdef __SYMBIAN32__ |
107 EXPORT_C |
144 EXPORT_C |
108 #endif |
145 #endif |