1 /*
2 * SSA/ASS spliting functions
3 * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg 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 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
24
33
39
49
52 .offset = offsetof(
ASS, script_info),
58 {0},
59 }
60 },
61 { .section = "V4+ Styles",
62 .format_header = "Format",
63 .fields_header = "Style",
66 .offset_count = offsetof(
ASS, styles_count),
76 {0},
77 }
78 },
79 { .section = "V4 Styles",
80 .format_header = "Format",
81 .fields_header = "Style",
84 .offset_count = offsetof(
ASS, styles_count),
93 {0},
94 }
95 },
96 { .section = "Events",
97 .format_header = "Format",
98 .fields_header = "Dialogue",
101 .offset_count = offsetof(
ASS, dialogs_count),
107 {0},
108 }
109 },
110 };
111
112
114
116 {
118 if (str) {
119 memcpy(str, buf, len);
121 if (*(void **)dest)
123 *(char **)dest = str;
124 }
125 return !str;
126 }
128 {
129 return sscanf(buf, "%d", (int *)dest) == 1;
130 }
132 {
133 return sscanf(buf, "%f", (float *)dest) == 1;
134 }
136 {
137 return sscanf(buf, "&H%8x", (int *)dest) == 1 ||
138 sscanf(buf, "%d", (int *)dest) == 1;
139 }
141 {
143 if ((c = sscanf(buf, "%d:%02d:%02d.%02d", &h, &m, &s, &cs)) == 4)
144 *(int *)dest = 360000*h + 6000*m + 100*s + cs;
145 return c == 4;
146 }
148 {
150 if (sscanf(buf, "%d", &a) == 1) {
151 /* convert V4 Style alignment to V4+ Style */
152 *(int *)dest = a + ((a&4) >> 1) - 5*!!(a&8);
153 return 1;
154 }
155 return 0;
156 }
157
165 };
166
167
173 };
174
175
177 {
182 if (!tmp)
183 return NULL;
184 *section_ptr = tmp;
185 tmp += *count * section->
size;
186 memset(tmp, 0, section->
size);
187 (*count)++;
188 return tmp;
189 }
190
192 {
193 return buf == '\r' || buf == '\n' || buf == 0;
194 }
195
197 {
198 while (*buf == ' ')
199 buf++;
201 }
202
204 {
209
210 while (buf && *buf) {
211 if (buf[0] == '[') {
213 break;
214 }
215 if (buf[0] == ';' || (buf[0] == '!' && buf[1] == ':')) {
216 /* skip comments */
219 if (strncmp(buf, section->
format_header, len) || buf[len] !=
':')
220 return NULL;
221 buf += len + 1;
224 len = strcspn(buf, ", \r\n");
225 if (!(tmp =
av_realloc(order, (*number + 1) *
sizeof(*order))))
226 return NULL;
227 order = tmp;
228 order[*number] = -1;
230 if (!strncmp(buf, section->
fields[i].
name, len)) {
231 order[*number] = i;
232 break;
233 }
234 (*number)++;
235 buf =
skip_space(buf + len + (buf[len] ==
','));
236 }
240 if (!strncmp(buf, section->
fields_header, len) && buf[len] ==
':') {
242 if (!struct_ptr) return NULL;
243 buf += len + 1;
244 for (i=0; !
is_eol(*buf) && i < *number; i++) {
245 int last = i == *number - 1;
247 len = strcspn(buf, last ? "\r\n" : ",\r\n");
248 if (order[i] >= 0) {
252 }
254 if (!last && *buf) buf++;
256 }
257 }
258 } else {
259 len = strcspn(buf, ":\r\n");
260 if (buf[len] == ':') {
262 if (!strncmp(buf, section->
fields[i].
name, len)) {
268 break;
269 }
270 }
271 }
272 buf += strcspn(buf, "\n");
274 }
276 }
277
279 {
281 int i;
282
285
286 while (buf && *buf) {
287 if (sscanf(buf, "[%15[0-9A-Za-z+ ]]%c", section, &c) == 2) {
288 buf += strcspn(buf, "\n");
291 if (!strcmp(section, ass_sections[i].section)) {
294 }
295 } else {
296 buf += strcspn(buf, "\n");
298 }
299 }
301 }
302
304 {
309 return NULL;
310 }
311 return ctx;
312 }
313
315 {
318
320 ptr = *(void **)ptr;
322 } else
324
325 if (ptr)
326 for (i=0; i<*
count; i++, ptr += section->
size)
331 }
332 *count = 0;
333
336 }
337
339 int cache, int *number)
340 {
343 if (!cache)
345 if (!strcmp(ass_sections[i].
section,
"Events")) {
347 break;
348 }
352 if (number)
354 return dialog;
355 }
356
358 {
359 if (ctx) {
360 int i;
364 }
366 }
367 }
368
369
372 {
373 const char *text = NULL;
374 char new_line[2];
375 int text_len = 0;
376
377 while (buf && *buf) {
378 if (text && callbacks->
text &&
379 (sscanf(buf, "\\%1[nN]", new_line) == 1 ||
380 !strncmp(buf, "{\\", 2))) {
381 callbacks->
text(priv, text, text_len);
382 text = NULL;
383 }
384 if (sscanf(buf, "\\%1[nN]", new_line) == 1) {
386 callbacks->
new_line(priv, new_line[0] ==
'N');
387 buf += 2;
388 } else if (!strncmp(buf, "{\\", 2)) {
389 buf++;
390 while (*buf == '\\') {
391 char style[2],
c[2], sep[2], c_num[2] =
"0", tmp[128] = {0};
392 unsigned int color = 0xFFFFFFFF;
394 int x1, y1, x2, y2,
t1 = -1,
t2 = -1;
395 if (sscanf(buf, "\\%1[bisu]%1[01\\}]%n", style, c, &len) > 1) {
396 int close = c[0] ==
'0' ? 1 : c[0] ==
'1' ? 0 : -1;
397 len += close != -1;
398 if (callbacks->
style)
399 callbacks->
style(priv, style[0], close);
400 } else if (sscanf(buf, "\\c%1[\\}]%n", sep, &len) > 0 ||
401 sscanf(buf, "\\c&H%X&%1[\\}]%n", &color, sep, &len) > 1 ||
402 sscanf(buf, "\\%1[1234]c%1[\\}]%n", c_num, sep, &len) > 1 ||
403 sscanf(buf, "\\%1[1234]c&H%X&%1[\\}]%n", c_num, &color, sep, &len) > 2) {
404 if (callbacks->
color)
405 callbacks->
color(priv, color, c_num[0] -
'0');
406 } else if (sscanf(buf, "\\alpha%1[\\}]%n", sep, &len) > 0 ||
407 sscanf(buf,
"\\alpha&H%2X&%1[\\}]%n", &
alpha, sep, &len) > 1 ||
408 sscanf(buf, "\\%1[1234]a%1[\\}]%n", c_num, sep, &len) > 1 ||
409 sscanf(buf,
"\\%1[1234]a&H%2X&%1[\\}]%n", c_num, &
alpha, sep, &len) > 2) {
410 if (callbacks->
alpha)
411 callbacks->
alpha(priv,
alpha, c_num[0] -
'0');
412 } else if (sscanf(buf, "\\fn%1[\\}]%n", sep, &len) > 0 ||
413 sscanf(buf, "\\fn%127[^\\}]%1[\\}]%n", tmp, sep, &len) > 1) {
415 callbacks->
font_name(priv, tmp[0] ? tmp : NULL);
416 } else if (sscanf(buf, "\\fs%1[\\}]%n", sep, &len) > 0 ||
417 sscanf(buf, "\\fs%u%1[\\}]%n", &size, sep, &len) > 1) {
420 } else if (sscanf(buf, "\\a%1[\\}]%n", sep, &len) > 0 ||
421 sscanf(buf, "\\a%2u%1[\\}]%n", &an, sep, &len) > 1 ||
422 sscanf(buf, "\\an%1[\\}]%n", sep, &len) > 0 ||
423 sscanf(buf, "\\an%1u%1[\\}]%n", &an, sep, &len) > 1) {
424 if (an != -1 && buf[2] != 'n')
425 an = (an&3) + (an&4 ? 6 : an&8 ? 3 : 0);
428 } else if (sscanf(buf, "\\r%1[\\}]%n", sep, &len) > 0 ||
429 sscanf(buf, "\\r%127[^\\}]%1[\\}]%n", tmp, sep, &len) > 1) {
432 } else if (sscanf(buf, "\\move(%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, sep, &len) > 4 ||
433 sscanf(buf,
"\\move(%d,%d,%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, &t1, &
t2, sep, &len) > 6) {
435 callbacks->
move(priv, x1, y1, x2, y2, t1,
t2);
436 } else if (sscanf(buf, "\\pos(%d,%d)%1[\\}]%n", &x1, &y1, sep, &len) > 2) {
438 callbacks->
move(priv, x1, y1, x1, y1, -1, -1);
439 } else if (sscanf(buf, "\\org(%d,%d)%1[\\}]%n", &x1, &y1, sep, &len) > 2) {
441 callbacks->
origin(priv, x1, y1);
442 } else {
443 len = strcspn(buf+1, "\\}") + 2; /* skip unknown code */
444 }
445 buf += len - 1;
446 }
447 if (*buf++ != '}')
449 } else {
450 if (!text) {
452 text_len = 1;
453 } else
454 text_len++;
455 buf++;
456 }
457 }
458 if (text && callbacks->
text)
459 callbacks->
text(priv, text, text_len);
461 callbacks->
end(priv);
462 return 0;
463 }
464
466 {
468 int i;
469
470 if (!style || !*style)
471 style = "Default";
475 return NULL;
476 }