Mercurial > mplayer.hg
annotate libass/ass.c @ 31215:d0f70692a140
Make 3dnow and MMX code compile for 64 bit (just stupid search-and-replace).
They are not compiled/enabled on 64 bit though, since they are vastly slower
but would still be selected by default.
author | reimar |
---|---|
date | Sun, 30 May 2010 10:01:40 +0000 |
parents | 48d020c5ceca |
children | ee7beb1a3a6e |
rev | line source |
---|---|
20008
fa122b7c71c6
Add copyright notice and vim/emacs comments to libass and vf_ass.c.
eugeni
parents:
19905
diff
changeset
|
1 /* |
26723 | 2 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> |
3 * | |
26738
588ce97b44f2
Speak of libass instead of MPlayer in the libass license headers.
diego
parents:
26723
diff
changeset
|
4 * This file is part of libass. |
26723 | 5 * |
26738
588ce97b44f2
Speak of libass instead of MPlayer in the libass license headers.
diego
parents:
26723
diff
changeset
|
6 * libass is free software; you can redistribute it and/or modify |
26723 | 7 * it under the terms of the GNU General Public License as published by |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
26738
588ce97b44f2
Speak of libass instead of MPlayer in the libass license headers.
diego
parents:
26723
diff
changeset
|
11 * libass is distributed in the hope that it will be useful, |
26723 | 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License along | |
26738
588ce97b44f2
Speak of libass instead of MPlayer in the libass license headers.
diego
parents:
26723
diff
changeset
|
17 * with libass; if not, write to the Free Software Foundation, Inc., |
26723 | 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 */ | |
20008
fa122b7c71c6
Add copyright notice and vim/emacs comments to libass and vf_ass.c.
eugeni
parents:
19905
diff
changeset
|
20 |
18937 | 21 #include "config.h" |
22 | |
23 #include <stdio.h> | |
24 #include <stdlib.h> | |
25 #include <string.h> | |
26 #include <assert.h> | |
27 #include <errno.h> | |
28 #include <sys/types.h> | |
29 #include <sys/stat.h> | |
30 #include <unistd.h> | |
19374 | 31 #include <inttypes.h> |
18937 | 32 |
27393 | 33 #ifdef CONFIG_ICONV |
18937 | 34 #include <iconv.h> |
35 #endif | |
36 | |
37 #include "ass.h" | |
38 #include "ass_utils.h" | |
20477 | 39 #include "ass_library.h" |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
40 |
30200 | 41 typedef enum { |
42 PST_UNKNOWN = 0, | |
43 PST_INFO, | |
44 PST_STYLES, | |
45 PST_EVENTS, | |
46 PST_FONTS | |
47 } ParserState; | |
48 | |
49 struct parser_priv { | |
50 ParserState state; | |
51 char *fontname; | |
52 char *fontdata; | |
53 int fontdata_size; | |
54 int fontdata_used; | |
19492 | 55 }; |
56 | |
18937 | 57 #define ASS_STYLES_ALLOC 20 |
58 #define ASS_EVENTS_ALLOC 200 | |
59 | |
30200 | 60 void ass_free_track(ASS_Track *track) |
61 { | |
62 int i; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
63 |
30200 | 64 if (track->parser_priv) { |
65 if (track->parser_priv->fontname) | |
66 free(track->parser_priv->fontname); | |
67 if (track->parser_priv->fontdata) | |
68 free(track->parser_priv->fontdata); | |
69 free(track->parser_priv); | |
70 } | |
71 if (track->style_format) | |
72 free(track->style_format); | |
73 if (track->event_format) | |
74 free(track->event_format); | |
75 if (track->styles) { | |
76 for (i = 0; i < track->n_styles; ++i) | |
77 ass_free_style(track, i); | |
78 free(track->styles); | |
79 } | |
80 if (track->events) { | |
81 for (i = 0; i < track->n_events; ++i) | |
82 ass_free_event(track, i); | |
83 free(track->events); | |
84 } | |
85 free(track->name); | |
86 free(track); | |
18937 | 87 } |
88 | |
89 /// \brief Allocate a new style struct | |
90 /// \param track track | |
91 /// \return style id | |
30200 | 92 int ass_alloc_style(ASS_Track *track) |
93 { | |
94 int sid; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
95 |
30200 | 96 assert(track->n_styles <= track->max_styles); |
18937 | 97 |
30200 | 98 if (track->n_styles == track->max_styles) { |
99 track->max_styles += ASS_STYLES_ALLOC; | |
100 track->styles = | |
101 (ASS_Style *) realloc(track->styles, | |
102 sizeof(ASS_Style) * | |
103 track->max_styles); | |
104 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
105 |
30200 | 106 sid = track->n_styles++; |
107 memset(track->styles + sid, 0, sizeof(ASS_Style)); | |
108 return sid; | |
18937 | 109 } |
110 | |
111 /// \brief Allocate a new event struct | |
112 /// \param track track | |
113 /// \return event id | |
30200 | 114 int ass_alloc_event(ASS_Track *track) |
115 { | |
116 int eid; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
117 |
30200 | 118 assert(track->n_events <= track->max_events); |
18937 | 119 |
30200 | 120 if (track->n_events == track->max_events) { |
121 track->max_events += ASS_EVENTS_ALLOC; | |
122 track->events = | |
123 (ASS_Event *) realloc(track->events, | |
124 sizeof(ASS_Event) * | |
125 track->max_events); | |
126 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
127 |
30200 | 128 eid = track->n_events++; |
129 memset(track->events + eid, 0, sizeof(ASS_Event)); | |
130 return eid; | |
18937 | 131 } |
132 | |
30200 | 133 void ass_free_event(ASS_Track *track, int eid) |
134 { | |
135 ASS_Event *event = track->events + eid; | |
136 if (event->Name) | |
137 free(event->Name); | |
138 if (event->Effect) | |
139 free(event->Effect); | |
140 if (event->Text) | |
141 free(event->Text); | |
142 if (event->render_priv) | |
143 free(event->render_priv); | |
19474
07209f48e527
Add public functions for removal of styles and events.
eugeni
parents:
19405
diff
changeset
|
144 } |
07209f48e527
Add public functions for removal of styles and events.
eugeni
parents:
19405
diff
changeset
|
145 |
30200 | 146 void ass_free_style(ASS_Track *track, int sid) |
147 { | |
148 ASS_Style *style = track->styles + sid; | |
149 if (style->Name) | |
150 free(style->Name); | |
151 if (style->FontName) | |
152 free(style->FontName); | |
18937 | 153 } |
154 | |
155 // ============================================================================================== | |
156 | |
30200 | 157 static void skip_spaces(char **str) |
158 { | |
159 char *p = *str; | |
160 while ((*p == ' ') || (*p == '\t')) | |
161 ++p; | |
162 *str = p; | |
18937 | 163 } |
164 | |
30200 | 165 static void rskip_spaces(char **str, char *limit) |
166 { | |
167 char *p = *str; | |
168 while ((p >= limit) && ((*p == ' ') || (*p == '\t'))) | |
169 --p; | |
170 *str = p; | |
18937 | 171 } |
172 | |
173 /** | |
174 * \brief find style by name | |
175 * \param track track | |
176 * \param name style name | |
177 * \return index in track->styles | |
178 * Returnes 0 if no styles found => expects at least 1 style. | |
179 * Parsing code always adds "Default" style in the end. | |
180 */ | |
30200 | 181 static int lookup_style(ASS_Track *track, char *name) |
182 { | |
183 int i; | |
184 if (*name == '*') | |
185 ++name; // FIXME: what does '*' really mean ? | |
186 for (i = track->n_styles - 1; i >= 0; --i) { | |
187 // FIXME: mb strcasecmp ? | |
188 if (strcmp(track->styles[i].Name, name) == 0) | |
189 return i; | |
190 } | |
191 i = track->default_style; | |
192 ass_msg(track->library, MSGL_WARN, | |
193 "[%p]: Warning: no style named '%s' found, using '%s'", | |
194 track, name, track->styles[i].Name); | |
195 return i; // use the first style | |
18937 | 196 } |
197 | |
30200 | 198 static uint32_t string2color(ASS_Library *library, char *p) |
199 { | |
200 uint32_t tmp; | |
201 (void) strtocolor(library, &p, &tmp, 0); | |
202 return tmp; | |
18937 | 203 } |
204 | |
30200 | 205 static long long string2timecode(ASS_Library *library, char *p) |
206 { | |
207 unsigned h, m, s, ms; | |
208 long long tm; | |
209 int res = sscanf(p, "%1d:%2d:%2d.%2d", &h, &m, &s, &ms); | |
210 if (res < 4) { | |
211 ass_msg(library, MSGL_WARN, "Bad timestamp"); | |
212 return 0; | |
213 } | |
214 tm = ((h * 60 + m) * 60 + s) * 1000 + ms * 10; | |
215 return tm; | |
18937 | 216 } |
217 | |
218 /** | |
219 * \brief converts numpad-style align to align. | |
220 */ | |
30200 | 221 static int numpad2align(int val) |
222 { | |
223 int res, v; | |
224 v = (val - 1) / 3; // 0, 1 or 2 for vertical alignment | |
225 if (v != 0) | |
226 v = 3 - v; | |
227 res = ((val - 1) % 3) + 1; // horizontal alignment | |
228 res += v * 4; | |
229 return res; | |
18937 | 230 } |
231 | |
232 #define NEXT(str,token) \ | |
233 token = next_token(&str); \ | |
234 if (!token) break; | |
235 | |
236 #define ANYVAL(name,func) \ | |
237 } else if (strcasecmp(tname, #name) == 0) { \ | |
238 target->name = func(token); \ | |
30200 | 239 ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); |
19495 | 240 |
241 #define STRVAL(name) \ | |
242 } else if (strcasecmp(tname, #name) == 0) { \ | |
243 if (target->name != NULL) free(target->name); \ | |
244 target->name = strdup(token); \ | |
30200 | 245 ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
246 |
30200 | 247 #define COLORVAL(name) \ |
248 } else if (strcasecmp(tname, #name) == 0) { \ | |
249 target->name = string2color(track->library, token); \ | |
250 ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); | |
251 | |
18937 | 252 #define INTVAL(name) ANYVAL(name,atoi) |
253 #define FPVAL(name) ANYVAL(name,atof) | |
30200 | 254 #define TIMEVAL(name) \ |
255 } else if (strcasecmp(tname, #name) == 0) { \ | |
256 target->name = string2timecode(track->library, token); \ | |
257 ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); | |
258 | |
18937 | 259 #define STYLEVAL(name) \ |
260 } else if (strcasecmp(tname, #name) == 0) { \ | |
261 target->name = lookup_style(track, token); \ | |
30200 | 262 ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); |
18937 | 263 |
264 #define ALIAS(alias,name) \ | |
265 if (strcasecmp(tname, #alias) == 0) {tname = #name;} | |
266 | |
30200 | 267 static char *next_token(char **str) |
268 { | |
269 char *p = *str; | |
270 char *start; | |
271 skip_spaces(&p); | |
272 if (*p == '\0') { | |
273 *str = p; | |
274 return 0; | |
275 } | |
276 start = p; // start of the token | |
277 for (; (*p != '\0') && (*p != ','); ++p) { | |
278 } | |
279 if (*p == '\0') { | |
280 *str = p; // eos found, str will point to '\0' at exit | |
281 } else { | |
282 *p = '\0'; | |
283 *str = p + 1; // ',' found, str will point to the next char (beginning of the next token) | |
284 } | |
285 --p; // end of current token | |
286 rskip_spaces(&p, start); | |
287 if (p < start) | |
288 p = start; // empty token | |
289 else | |
290 ++p; // the first space character, or '\0' | |
291 *p = '\0'; | |
292 return start; | |
18937 | 293 } |
30200 | 294 |
18937 | 295 /** |
296 * \brief Parse the tail of Dialogue line | |
297 * \param track track | |
298 * \param event parsed data goes here | |
299 * \param str string to parse, zero-terminated | |
300 * \param n_ignored number of format options to skip at the beginning | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
301 */ |
30200 | 302 static int process_event_tail(ASS_Track *track, ASS_Event *event, |
303 char *str, int n_ignored) | |
18937 | 304 { |
30200 | 305 char *token; |
306 char *tname; | |
307 char *p = str; | |
308 int i; | |
309 ASS_Event *target = event; | |
18937 | 310 |
30200 | 311 char *format = strdup(track->event_format); |
312 char *q = format; // format scanning pointer | |
29472 | 313 |
30200 | 314 if (track->n_styles == 0) { |
315 // add "Default" style to the end | |
316 // will be used if track does not contain a default style (or even does not contain styles at all) | |
317 int sid = ass_alloc_style(track); | |
318 track->styles[sid].Name = strdup("Default"); | |
319 track->styles[sid].FontName = strdup("Arial"); | |
320 } | |
18937 | 321 |
30200 | 322 for (i = 0; i < n_ignored; ++i) { |
323 NEXT(q, tname); | |
324 } | |
18937 | 325 |
30200 | 326 while (1) { |
327 NEXT(q, tname); | |
328 if (strcasecmp(tname, "Text") == 0) { | |
329 char *last; | |
330 event->Text = strdup(p); | |
331 if (*event->Text != 0) { | |
332 last = event->Text + strlen(event->Text) - 1; | |
333 if (last >= event->Text && *last == '\r') | |
334 *last = 0; | |
335 } | |
336 ass_msg(track->library, MSGL_DBG2, "Text = %s", event->Text); | |
337 event->Duration -= event->Start; | |
338 free(format); | |
339 return 0; // "Text" is always the last | |
340 } | |
341 NEXT(p, token); | |
18937 | 342 |
30200 | 343 ALIAS(End, Duration) // temporarily store end timecode in event->Duration |
344 if (0) { // cool ;) | |
345 INTVAL(Layer) | |
346 STYLEVAL(Style) | |
347 STRVAL(Name) | |
348 STRVAL(Effect) | |
349 INTVAL(MarginL) | |
350 INTVAL(MarginR) | |
351 INTVAL(MarginV) | |
352 TIMEVAL(Start) | |
353 TIMEVAL(Duration) | |
354 } | |
355 } | |
356 free(format); | |
357 return 1; | |
18937 | 358 } |
359 | |
360 /** | |
19495 | 361 * \brief Parse command line style overrides (--ass-force-style option) |
362 * \param track track to apply overrides to | |
363 * The format for overrides is [StyleName.]Field=Value | |
364 */ | |
30200 | 365 void ass_process_force_style(ASS_Track *track) |
366 { | |
367 char **fs, *eq, *dt, *style, *tname, *token; | |
368 ASS_Style *target; | |
369 int sid; | |
370 char **list = track->library->style_overrides; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
371 |
30200 | 372 if (!list) |
373 return; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
374 |
30200 | 375 for (fs = list; *fs; ++fs) { |
376 eq = strrchr(*fs, '='); | |
377 if (!eq) | |
378 continue; | |
379 *eq = '\0'; | |
380 token = eq + 1; | |
19495 | 381 |
30200 | 382 if (!strcasecmp(*fs, "PlayResX")) |
383 track->PlayResX = atoi(token); | |
384 else if (!strcasecmp(*fs, "PlayResY")) | |
385 track->PlayResY = atoi(token); | |
386 else if (!strcasecmp(*fs, "Timer")) | |
387 track->Timer = atof(token); | |
388 else if (!strcasecmp(*fs, "WrapStyle")) | |
389 track->WrapStyle = atoi(token); | |
390 else if (!strcasecmp(*fs, "ScaledBorderAndShadow")) | |
391 track->ScaledBorderAndShadow = parse_bool(token); | |
392 else if (!strcasecmp(*fs, "Kerning")) | |
393 track->Kerning = parse_bool(token); | |
25582
6b1d7568ae3d
Allow overriding [Script Info] parameters with -ass-force-style option.
eugeni
parents:
25515
diff
changeset
|
394 |
30200 | 395 dt = strrchr(*fs, '.'); |
396 if (dt) { | |
397 *dt = '\0'; | |
398 style = *fs; | |
399 tname = dt + 1; | |
400 } else { | |
401 style = NULL; | |
402 tname = *fs; | |
403 } | |
404 for (sid = 0; sid < track->n_styles; ++sid) { | |
405 if (style == NULL | |
406 || strcasecmp(track->styles[sid].Name, style) == 0) { | |
407 target = track->styles + sid; | |
408 if (0) { | |
409 STRVAL(FontName) | |
410 COLORVAL(PrimaryColour) | |
411 COLORVAL(SecondaryColour) | |
412 COLORVAL(OutlineColour) | |
413 COLORVAL(BackColour) | |
414 FPVAL(FontSize) | |
415 INTVAL(Bold) | |
416 INTVAL(Italic) | |
417 INTVAL(Underline) | |
418 INTVAL(StrikeOut) | |
419 FPVAL(Spacing) | |
420 INTVAL(Angle) | |
421 INTVAL(BorderStyle) | |
422 INTVAL(Alignment) | |
423 INTVAL(MarginL) | |
424 INTVAL(MarginR) | |
425 INTVAL(MarginV) | |
426 INTVAL(Encoding) | |
427 FPVAL(ScaleX) | |
428 FPVAL(ScaleY) | |
429 FPVAL(Outline) | |
430 FPVAL(Shadow) | |
431 } | |
432 } | |
433 } | |
434 *eq = '='; | |
435 if (dt) | |
436 *dt = '.'; | |
437 } | |
19495 | 438 } |
439 | |
440 /** | |
18937 | 441 * \brief Parse the Style line |
442 * \param track track | |
443 * \param str string to parse, zero-terminated | |
444 * Allocates a new style struct. | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
445 */ |
30200 | 446 static int process_style(ASS_Track *track, char *str) |
18937 | 447 { |
448 | |
30200 | 449 char *token; |
450 char *tname; | |
451 char *p = str; | |
452 char *format; | |
453 char *q; // format scanning pointer | |
454 int sid; | |
455 ASS_Style *style; | |
456 ASS_Style *target; | |
18937 | 457 |
30200 | 458 if (!track->style_format) { |
459 // no style format header | |
460 // probably an ancient script version | |
461 if (track->track_type == TRACK_TYPE_SSA) | |
462 track->style_format = | |
463 strdup | |
464 ("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour," | |
465 "TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline," | |
466 "Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding"); | |
467 else | |
468 track->style_format = | |
469 strdup | |
470 ("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour," | |
471 "OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut," | |
472 "ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow," | |
473 "Alignment, MarginL, MarginR, MarginV, Encoding"); | |
474 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
475 |
30200 | 476 q = format = strdup(track->style_format); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
477 |
30200 | 478 ass_msg(track->library, MSGL_V, "[%p] Style: %s", track, str); |
479 | |
480 sid = ass_alloc_style(track); | |
18937 | 481 |
30200 | 482 style = track->styles + sid; |
483 target = style; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
484 |
30200 | 485 // fill style with some default values |
486 style->ScaleX = 100.; | |
487 style->ScaleY = 100.; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
488 |
30200 | 489 while (1) { |
490 NEXT(q, tname); | |
491 NEXT(p, token); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
492 |
30200 | 493 if (0) { // cool ;) |
494 STRVAL(Name) | |
495 if ((strcmp(target->Name, "Default") == 0) | |
496 || (strcmp(target->Name, "*Default") == 0)) | |
497 track->default_style = sid; | |
498 STRVAL(FontName) | |
499 COLORVAL(PrimaryColour) | |
500 COLORVAL(SecondaryColour) | |
501 COLORVAL(OutlineColour) // TertiaryColor | |
502 COLORVAL(BackColour) | |
503 // SSA uses BackColour for both outline and shadow | |
504 // this will destroy SSA's TertiaryColour, but i'm not going to use it anyway | |
505 if (track->track_type == TRACK_TYPE_SSA) | |
506 target->OutlineColour = target->BackColour; | |
507 FPVAL(FontSize) | |
508 INTVAL(Bold) | |
509 INTVAL(Italic) | |
510 INTVAL(Underline) | |
511 INTVAL(StrikeOut) | |
512 FPVAL(Spacing) | |
513 INTVAL(Angle) | |
514 INTVAL(BorderStyle) | |
515 INTVAL(Alignment) | |
516 if (track->track_type == TRACK_TYPE_ASS) | |
517 target->Alignment = numpad2align(target->Alignment); | |
518 INTVAL(MarginL) | |
519 INTVAL(MarginR) | |
520 INTVAL(MarginV) | |
521 INTVAL(Encoding) | |
522 FPVAL(ScaleX) | |
523 FPVAL(ScaleY) | |
524 FPVAL(Outline) | |
525 FPVAL(Shadow) | |
526 } | |
527 } | |
528 style->ScaleX /= 100.; | |
529 style->ScaleY /= 100.; | |
530 style->Bold = !!style->Bold; | |
531 style->Italic = !!style->Italic; | |
532 style->Underline = !!style->Underline; | |
533 if (!style->Name) | |
534 style->Name = strdup("Default"); | |
535 if (!style->FontName) | |
536 style->FontName = strdup("Arial"); | |
537 // skip '@' at the start of the font name | |
538 if (*style->FontName == '@') { | |
539 p = style->FontName; | |
540 style->FontName = strdup(p + 1); | |
541 free(p); | |
542 } | |
543 free(format); | |
544 return 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
545 |
18937 | 546 } |
547 | |
30200 | 548 static int process_styles_line(ASS_Track *track, char *str) |
19492 | 549 { |
30200 | 550 if (!strncmp(str, "Format:", 7)) { |
551 char *p = str + 7; | |
552 skip_spaces(&p); | |
553 track->style_format = strdup(p); | |
554 ass_msg(track->library, MSGL_DBG2, "Style format: %s", | |
555 track->style_format); | |
556 } else if (!strncmp(str, "Style:", 6)) { | |
557 char *p = str + 6; | |
558 skip_spaces(&p); | |
559 process_style(track, p); | |
560 } | |
561 return 0; | |
562 } | |
563 | |
564 static int process_info_line(ASS_Track *track, char *str) | |
565 { | |
566 if (!strncmp(str, "PlayResX:", 9)) { | |
567 track->PlayResX = atoi(str + 9); | |
568 } else if (!strncmp(str, "PlayResY:", 9)) { | |
569 track->PlayResY = atoi(str + 9); | |
570 } else if (!strncmp(str, "Timer:", 6)) { | |
571 track->Timer = atof(str + 6); | |
572 } else if (!strncmp(str, "WrapStyle:", 10)) { | |
573 track->WrapStyle = atoi(str + 10); | |
574 } else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) { | |
575 track->ScaledBorderAndShadow = parse_bool(str + 22); | |
576 } else if (!strncmp(str, "Kerning:", 8)) { | |
577 track->Kerning = parse_bool(str + 8); | |
578 } | |
579 return 0; | |
19492 | 580 } |
581 | |
30200 | 582 static void event_format_fallback(ASS_Track *track) |
19492 | 583 { |
30200 | 584 track->parser_priv->state = PST_EVENTS; |
585 if (track->track_type == TRACK_TYPE_SSA) | |
586 track->event_format = strdup("Format: Marked, Start, End, Style, " | |
587 "Name, MarginL, MarginR, MarginV, Effect, Text"); | |
588 else | |
589 track->event_format = strdup("Format: Layer, Start, End, Style, " | |
590 "Actor, MarginL, MarginR, MarginV, Effect, Text"); | |
591 ass_msg(track->library, MSGL_V, | |
592 "No event format found, using fallback"); | |
19492 | 593 } |
594 | |
30200 | 595 static int process_events_line(ASS_Track *track, char *str) |
19492 | 596 { |
30200 | 597 if (!strncmp(str, "Format:", 7)) { |
598 char *p = str + 7; | |
599 skip_spaces(&p); | |
600 track->event_format = strdup(p); | |
601 ass_msg(track->library, MSGL_DBG2, "Event format: %s", track->event_format); | |
602 } else if (!strncmp(str, "Dialogue:", 9)) { | |
603 // This should never be reached for embedded subtitles. | |
604 // They have slightly different format and are parsed in ass_process_chunk, | |
605 // called directly from demuxer | |
606 int eid; | |
607 ASS_Event *event; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
608 |
30200 | 609 str += 9; |
610 skip_spaces(&str); | |
19492 | 611 |
30200 | 612 eid = ass_alloc_event(track); |
613 event = track->events + eid; | |
19492 | 614 |
30200 | 615 // We can't parse events with event_format |
616 if (!track->event_format) | |
617 event_format_fallback(track); | |
618 | |
619 process_event_tail(track, event, str, 0); | |
620 } else { | |
621 ass_msg(track->library, MSGL_V, "Not understood: '%s'", str); | |
622 } | |
623 return 0; | |
19492 | 624 } |
625 | |
626 // Copied from mkvtoolnix | |
30200 | 627 static unsigned char *decode_chars(unsigned char c1, unsigned char c2, |
628 unsigned char c3, unsigned char c4, | |
629 unsigned char *dst, int cnt) | |
19492 | 630 { |
30200 | 631 uint32_t value; |
632 unsigned char bytes[3]; | |
633 int i; | |
19492 | 634 |
30200 | 635 value = |
636 ((c1 - 33) << 18) + ((c2 - 33) << 12) + ((c3 - 33) << 6) + (c4 - | |
637 33); | |
638 bytes[2] = value & 0xff; | |
639 bytes[1] = (value & 0xff00) >> 8; | |
640 bytes[0] = (value & 0xff0000) >> 16; | |
19492 | 641 |
30200 | 642 for (i = 0; i < cnt; ++i) |
643 *dst++ = bytes[i]; | |
644 return dst; | |
19492 | 645 } |
646 | |
30200 | 647 static int decode_font(ASS_Track *track) |
19492 | 648 { |
30200 | 649 unsigned char *p; |
650 unsigned char *q; | |
651 int i; | |
652 int size; // original size | |
653 int dsize; // decoded size | |
654 unsigned char *buf = 0; | |
19492 | 655 |
30200 | 656 ass_msg(track->library, MSGL_V, "Font: %d bytes encoded data", |
657 track->parser_priv->fontdata_used); | |
658 size = track->parser_priv->fontdata_used; | |
659 if (size % 4 == 1) { | |
660 ass_msg(track->library, MSGL_ERR, "Bad encoded data size"); | |
661 goto error_decode_font; | |
662 } | |
663 buf = malloc(size / 4 * 3 + 2); | |
664 q = buf; | |
665 for (i = 0, p = (unsigned char *) track->parser_priv->fontdata; | |
666 i < size / 4; i++, p += 4) { | |
667 q = decode_chars(p[0], p[1], p[2], p[3], q, 3); | |
668 } | |
669 if (size % 4 == 2) { | |
670 q = decode_chars(p[0], p[1], 0, 0, q, 1); | |
671 } else if (size % 4 == 3) { | |
672 q = decode_chars(p[0], p[1], p[2], 0, q, 2); | |
673 } | |
674 dsize = q - buf; | |
675 assert(dsize <= size / 4 * 3 + 2); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
676 |
30200 | 677 if (track->library->extract_fonts) { |
678 ass_add_font(track->library, track->parser_priv->fontname, | |
679 (char *) buf, dsize); | |
680 buf = 0; | |
681 } | |
19492 | 682 |
30200 | 683 error_decode_font: |
684 if (buf) | |
685 free(buf); | |
686 free(track->parser_priv->fontname); | |
687 free(track->parser_priv->fontdata); | |
688 track->parser_priv->fontname = 0; | |
689 track->parser_priv->fontdata = 0; | |
690 track->parser_priv->fontdata_size = 0; | |
691 track->parser_priv->fontdata_used = 0; | |
692 return 0; | |
19492 | 693 } |
694 | |
30200 | 695 static int process_fonts_line(ASS_Track *track, char *str) |
19492 | 696 { |
30200 | 697 int len; |
19492 | 698 |
30200 | 699 if (!strncmp(str, "fontname:", 9)) { |
700 char *p = str + 9; | |
701 skip_spaces(&p); | |
702 if (track->parser_priv->fontname) { | |
703 decode_font(track); | |
704 } | |
705 track->parser_priv->fontname = strdup(p); | |
706 ass_msg(track->library, MSGL_V, "Fontname: %s", | |
707 track->parser_priv->fontname); | |
708 return 0; | |
709 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
710 |
30200 | 711 if (!track->parser_priv->fontname) { |
712 ass_msg(track->library, MSGL_V, "Not understood: '%s'", str); | |
713 return 0; | |
714 } | |
19492 | 715 |
30200 | 716 len = strlen(str); |
717 if (len > 80) { | |
718 ass_msg(track->library, MSGL_WARN, "Font line too long: %d, %s", | |
719 len, str); | |
720 return 0; | |
721 } | |
722 if (track->parser_priv->fontdata_used + len > | |
723 track->parser_priv->fontdata_size) { | |
724 track->parser_priv->fontdata_size += 100 * 1024; | |
725 track->parser_priv->fontdata = | |
726 realloc(track->parser_priv->fontdata, | |
727 track->parser_priv->fontdata_size); | |
728 } | |
729 memcpy(track->parser_priv->fontdata + track->parser_priv->fontdata_used, | |
730 str, len); | |
731 track->parser_priv->fontdata_used += len; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
732 |
30200 | 733 return 0; |
19492 | 734 } |
735 | |
18937 | 736 /** |
737 * \brief Parse a header line | |
738 * \param track track | |
739 * \param str string to parse, zero-terminated | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
740 */ |
30200 | 741 static int process_line(ASS_Track *track, char *str) |
18937 | 742 { |
30200 | 743 if (!strncasecmp(str, "[Script Info]", 13)) { |
744 track->parser_priv->state = PST_INFO; | |
745 } else if (!strncasecmp(str, "[V4 Styles]", 11)) { | |
746 track->parser_priv->state = PST_STYLES; | |
747 track->track_type = TRACK_TYPE_SSA; | |
748 } else if (!strncasecmp(str, "[V4+ Styles]", 12)) { | |
749 track->parser_priv->state = PST_STYLES; | |
750 track->track_type = TRACK_TYPE_ASS; | |
751 } else if (!strncasecmp(str, "[Events]", 8)) { | |
752 track->parser_priv->state = PST_EVENTS; | |
753 } else if (!strncasecmp(str, "[Fonts]", 7)) { | |
754 track->parser_priv->state = PST_FONTS; | |
755 } else { | |
756 switch (track->parser_priv->state) { | |
757 case PST_INFO: | |
758 process_info_line(track, str); | |
759 break; | |
760 case PST_STYLES: | |
761 process_styles_line(track, str); | |
762 break; | |
763 case PST_EVENTS: | |
764 process_events_line(track, str); | |
765 break; | |
766 case PST_FONTS: | |
767 process_fonts_line(track, str); | |
768 break; | |
769 default: | |
770 break; | |
771 } | |
772 } | |
19492 | 773 |
30200 | 774 // there is no explicit end-of-font marker in ssa/ass |
775 if ((track->parser_priv->state != PST_FONTS) | |
776 && (track->parser_priv->fontname)) | |
777 decode_font(track); | |
19492 | 778 |
30200 | 779 return 0; |
19492 | 780 } |
781 | |
30200 | 782 static int process_text(ASS_Track *track, char *str) |
19492 | 783 { |
30200 | 784 char *p = str; |
785 while (1) { | |
786 char *q; | |
787 while (1) { | |
788 if ((*p == '\r') || (*p == '\n')) | |
789 ++p; | |
790 else if (p[0] == '\xef' && p[1] == '\xbb' && p[2] == '\xbf') | |
791 p += 3; // U+FFFE (BOM) | |
792 else | |
793 break; | |
794 } | |
795 for (q = p; ((*q != '\0') && (*q != '\r') && (*q != '\n')); ++q) { | |
796 }; | |
797 if (q == p) | |
798 break; | |
799 if (*q != '\0') | |
800 *(q++) = '\0'; | |
801 process_line(track, p); | |
802 if (*q == '\0') | |
803 break; | |
804 p = q; | |
805 } | |
806 return 0; | |
18937 | 807 } |
808 | |
809 /** | |
27498
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
810 * \brief Process a chunk of subtitle stream data. |
18937 | 811 * \param track track |
812 * \param data string to parse | |
813 * \param size length of data | |
27498
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
814 */ |
30200 | 815 void ass_process_data(ASS_Track *track, char *data, int size) |
18937 | 816 { |
30200 | 817 char *str = malloc(size + 1); |
18937 | 818 |
30200 | 819 memcpy(str, data, size); |
820 str[size] = '\0'; | |
18937 | 821 |
30200 | 822 ass_msg(track->library, MSGL_V, "Event: %s", str); |
823 process_text(track, str); | |
824 free(str); | |
27498
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
825 } |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
826 |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
827 /** |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
828 * \brief Process CodecPrivate section of subtitle stream |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
829 * \param track track |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
830 * \param data string to parse |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
831 * \param size length of data |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
832 CodecPrivate section contains [Stream Info] and [V4+ Styles] ([V4 Styles] for SSA) sections |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
833 */ |
30200 | 834 void ass_process_codec_private(ASS_Track *track, char *data, int size) |
27498
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
835 { |
30200 | 836 ass_process_data(track, data, size); |
18937 | 837 |
30200 | 838 // probably an mkv produced by ancient mkvtoolnix |
839 // such files don't have [Events] and Format: headers | |
840 if (!track->event_format) | |
841 event_format_fallback(track); | |
19495 | 842 |
30200 | 843 ass_process_force_style(track); |
18937 | 844 } |
845 | |
30200 | 846 static int check_duplicate_event(ASS_Track *track, int ReadOrder) |
18937 | 847 { |
30200 | 848 int i; |
849 for (i = 0; i < track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with | |
850 if (track->events[i].ReadOrder == ReadOrder) | |
851 return 1; | |
852 return 0; | |
18937 | 853 } |
854 | |
855 /** | |
25515 | 856 * \brief Process a chunk of subtitle stream data. In Matroska, this contains exactly 1 event (or a commentary). |
18937 | 857 * \param track track |
858 * \param data string to parse | |
859 * \param size length of data | |
860 * \param timecode starting time of the event (milliseconds) | |
861 * \param duration duration of the event (milliseconds) | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
862 */ |
30200 | 863 void ass_process_chunk(ASS_Track *track, char *data, int size, |
864 long long timecode, long long duration) | |
18937 | 865 { |
30200 | 866 char *str; |
867 int eid; | |
868 char *p; | |
869 char *token; | |
870 ASS_Event *event; | |
18937 | 871 |
30200 | 872 if (!track->event_format) { |
873 ass_msg(track->library, MSGL_WARN, "Event format header missing"); | |
874 return; | |
875 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
876 |
30200 | 877 str = malloc(size + 1); |
878 memcpy(str, data, size); | |
879 str[size] = '\0'; | |
880 ass_msg(track->library, MSGL_V, "Event at %" PRId64 ", +%" PRId64 ": %s", | |
881 (int64_t) timecode, (int64_t) duration, str); | |
18937 | 882 |
30200 | 883 eid = ass_alloc_event(track); |
884 event = track->events + eid; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
885 |
30200 | 886 p = str; |
18937 | 887 |
30200 | 888 do { |
889 NEXT(p, token); | |
890 event->ReadOrder = atoi(token); | |
891 if (check_duplicate_event(track, event->ReadOrder)) | |
892 break; | |
18937 | 893 |
30200 | 894 NEXT(p, token); |
895 event->Layer = atoi(token); | |
18937 | 896 |
30200 | 897 process_event_tail(track, event, p, 3); |
898 | |
899 event->Start = timecode; | |
900 event->Duration = duration; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
901 |
30200 | 902 free(str); |
903 return; | |
904 // dump_events(tid); | |
905 } while (0); | |
906 // some error | |
907 ass_free_event(track, eid); | |
908 track->n_events--; | |
909 free(str); | |
18937 | 910 } |
911 | |
27393 | 912 #ifdef CONFIG_ICONV |
18937 | 913 /** \brief recode buffer to utf-8 |
20477 | 914 * constraint: codepage != 0 |
18937 | 915 * \param data pointer to text buffer |
916 * \param size buffer size | |
917 * \return a pointer to recoded buffer, caller is responsible for freeing it | |
918 **/ | |
30200 | 919 static char *sub_recode(ASS_Library *library, char *data, size_t size, |
920 char *codepage) | |
18937 | 921 { |
30200 | 922 iconv_t icdsc; |
923 char *tocp = "UTF-8"; | |
924 char *outbuf; | |
925 assert(codepage); | |
18937 | 926 |
30200 | 927 { |
928 const char *cp_tmp = codepage; | |
27393 | 929 #ifdef CONFIG_ENCA |
30200 | 930 char enca_lang[3], enca_fallback[100]; |
931 if (sscanf(codepage, "enca:%2s:%99s", enca_lang, enca_fallback) == 2 | |
932 || sscanf(codepage, "ENCA:%2s:%99s", enca_lang, | |
933 enca_fallback) == 2) { | |
934 cp_tmp = | |
935 ass_guess_buffer_cp(library, (unsigned char *) data, size, | |
936 enca_lang, enca_fallback); | |
937 } | |
18937 | 938 #endif |
30200 | 939 if ((icdsc = iconv_open(tocp, cp_tmp)) != (iconv_t) (-1)) { |
940 ass_msg(library, MSGL_V, "Opened iconv descriptor"); | |
941 } else | |
942 ass_msg(library, MSGL_ERR, "Error opening iconv descriptor"); | |
943 } | |
18937 | 944 |
30200 | 945 { |
946 size_t osize = size; | |
947 size_t ileft = size; | |
948 size_t oleft = size - 1; | |
949 char *ip; | |
950 char *op; | |
951 size_t rc; | |
952 int clear = 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
953 |
30200 | 954 outbuf = malloc(osize); |
955 ip = data; | |
956 op = outbuf; | |
18937 | 957 |
30200 | 958 while (1) { |
959 if (ileft) | |
960 rc = iconv(icdsc, &ip, &ileft, &op, &oleft); | |
961 else { // clear the conversion state and leave | |
962 clear = 1; | |
963 rc = iconv(icdsc, NULL, NULL, &op, &oleft); | |
964 } | |
965 if (rc == (size_t) (-1)) { | |
966 if (errno == E2BIG) { | |
967 size_t offset = op - outbuf; | |
968 outbuf = (char *) realloc(outbuf, osize + size); | |
969 op = outbuf + offset; | |
970 osize += size; | |
971 oleft += size; | |
972 } else { | |
973 ass_msg(library, MSGL_WARN, "Error recoding file"); | |
974 return NULL; | |
975 } | |
976 } else if (clear) | |
977 break; | |
978 } | |
979 outbuf[osize - oleft - 1] = 0; | |
980 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
981 |
30200 | 982 if (icdsc != (iconv_t) (-1)) { |
983 (void) iconv_close(icdsc); | |
984 icdsc = (iconv_t) (-1); | |
985 ass_msg(library, MSGL_V, "Closed iconv descriptor"); | |
986 } | |
987 | |
988 return outbuf; | |
18937 | 989 } |
30200 | 990 #endif // ICONV |
18937 | 991 |
992 /** | |
20603 | 993 * \brief read file contents into newly allocated buffer |
994 * \param fname file name | |
995 * \param bufsize out: file size | |
996 * \return pointer to file contents. Caller is responsible for its deallocation. | |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
997 */ |
30200 | 998 static char *read_file(ASS_Library *library, char *fname, size_t *bufsize) |
18937 | 999 { |
30200 | 1000 int res; |
1001 long sz; | |
1002 long bytes_read; | |
1003 char *buf; | |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1004 |
30200 | 1005 FILE *fp = fopen(fname, "rb"); |
1006 if (!fp) { | |
1007 ass_msg(library, MSGL_WARN, | |
1008 "ass_read_file(%s): fopen failed", fname); | |
1009 return 0; | |
1010 } | |
1011 res = fseek(fp, 0, SEEK_END); | |
1012 if (res == -1) { | |
1013 ass_msg(library, MSGL_WARN, | |
1014 "ass_read_file(%s): fseek failed", fname); | |
1015 fclose(fp); | |
1016 return 0; | |
1017 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1018 |
30200 | 1019 sz = ftell(fp); |
1020 rewind(fp); | |
18937 | 1021 |
30200 | 1022 if (sz > 10 * 1024 * 1024) { |
1023 ass_msg(library, MSGL_INFO, | |
1024 "ass_read_file(%s): Refusing to load subtitles " | |
1025 "larger than 10MiB", fname); | |
1026 fclose(fp); | |
1027 return 0; | |
1028 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1029 |
30200 | 1030 ass_msg(library, MSGL_V, "File size: %ld", sz); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1031 |
30200 | 1032 buf = malloc(sz + 1); |
1033 assert(buf); | |
1034 bytes_read = 0; | |
1035 do { | |
1036 res = fread(buf + bytes_read, 1, sz - bytes_read, fp); | |
1037 if (res <= 0) { | |
1038 ass_msg(library, MSGL_INFO, "Read failed, %d: %s", errno, | |
1039 strerror(errno)); | |
1040 fclose(fp); | |
1041 free(buf); | |
1042 return 0; | |
1043 } | |
1044 bytes_read += res; | |
1045 } while (sz - bytes_read > 0); | |
1046 buf[sz] = '\0'; | |
1047 fclose(fp); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1048 |
30200 | 1049 if (bufsize) |
1050 *bufsize = sz; | |
1051 return buf; | |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1052 } |
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1053 |
20603 | 1054 /* |
1055 * \param buf pointer to subtitle text in utf-8 | |
1056 */ | |
30200 | 1057 static ASS_Track *parse_memory(ASS_Library *library, char *buf) |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1058 { |
30200 | 1059 ASS_Track *track; |
1060 int i; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1061 |
30200 | 1062 track = ass_new_track(library); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1063 |
30200 | 1064 // process header |
1065 process_text(track, buf); | |
19492 | 1066 |
30200 | 1067 // external SSA/ASS subs does not have ReadOrder field |
1068 for (i = 0; i < track->n_events; ++i) | |
1069 track->events[i].ReadOrder = i; | |
19905 | 1070 |
30200 | 1071 // there is no explicit end-of-font marker in ssa/ass |
1072 if (track->parser_priv->fontname) | |
1073 decode_font(track); | |
19492 | 1074 |
30200 | 1075 if (track->track_type == TRACK_TYPE_UNKNOWN) { |
1076 ass_free_track(track); | |
1077 return 0; | |
1078 } | |
18937 | 1079 |
30200 | 1080 ass_process_force_style(track); |
19495 | 1081 |
30200 | 1082 return track; |
20603 | 1083 } |
1084 | |
1085 /** | |
1086 * \brief Read subtitles from memory. | |
1087 * \param library libass library object | |
1088 * \param buf pointer to subtitles text | |
1089 * \param bufsize size of buffer | |
1090 * \param codepage recode buffer contents from given codepage | |
1091 * \return newly allocated track | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1092 */ |
30200 | 1093 ASS_Track *ass_read_memory(ASS_Library *library, char *buf, |
1094 size_t bufsize, char *codepage) | |
20603 | 1095 { |
30200 | 1096 ASS_Track *track; |
1097 int need_free = 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1098 |
30200 | 1099 if (!buf) |
1100 return 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1101 |
27393 | 1102 #ifdef CONFIG_ICONV |
30200 | 1103 if (codepage) { |
1104 buf = sub_recode(library, buf, bufsize, codepage); | |
1105 if (!buf) | |
1106 return 0; | |
1107 else | |
1108 need_free = 1; | |
1109 } | |
20603 | 1110 #endif |
30200 | 1111 track = parse_memory(library, buf); |
1112 if (need_free) | |
1113 free(buf); | |
1114 if (!track) | |
1115 return 0; | |
20603 | 1116 |
30200 | 1117 ass_msg(library, MSGL_INFO, "Added subtitle file: " |
1118 "<memory> (%d styles, %d events)", | |
1119 track->n_styles, track->n_events); | |
1120 return track; | |
20603 | 1121 } |
1122 | |
30200 | 1123 static char *read_file_recode(ASS_Library *library, char *fname, |
1124 char *codepage, size_t *size) | |
20603 | 1125 { |
30200 | 1126 char *buf; |
1127 size_t bufsize; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1128 |
30200 | 1129 buf = read_file(library, fname, &bufsize); |
1130 if (!buf) | |
1131 return 0; | |
27393 | 1132 #ifdef CONFIG_ICONV |
30200 | 1133 if (codepage) { |
1134 char *tmpbuf = sub_recode(library, buf, bufsize, codepage); | |
1135 free(buf); | |
1136 buf = tmpbuf; | |
1137 } | |
1138 if (!buf) | |
1139 return 0; | |
20603 | 1140 #endif |
30200 | 1141 *size = bufsize; |
1142 return buf; | |
23424
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1143 } |
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1144 |
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1145 /** |
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1146 * \brief Read subtitles from file. |
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1147 * \param library libass library object |
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1148 * \param fname file name |
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1149 * \param codepage recode buffer contents from given codepage |
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1150 * \return newly allocated track |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1151 */ |
30200 | 1152 ASS_Track *ass_read_file(ASS_Library *library, char *fname, |
1153 char *codepage) | |
23424
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1154 { |
30200 | 1155 char *buf; |
1156 ASS_Track *track; | |
1157 size_t bufsize; | |
23424
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1158 |
30200 | 1159 buf = read_file_recode(library, fname, codepage, &bufsize); |
1160 if (!buf) | |
1161 return 0; | |
1162 track = parse_memory(library, buf); | |
1163 free(buf); | |
1164 if (!track) | |
1165 return 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1166 |
30200 | 1167 track->name = strdup(fname); |
20603 | 1168 |
30200 | 1169 ass_msg(library, MSGL_INFO, |
1170 "Added subtitle file: '%s' (%d styles, %d events)", | |
1171 fname, track->n_styles, track->n_events); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1172 |
30200 | 1173 return track; |
18937 | 1174 } |
1175 | |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1176 /** |
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1177 * \brief read styles from file into already initialized track |
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1178 */ |
30200 | 1179 int ass_read_styles(ASS_Track *track, char *fname, char *codepage) |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1180 { |
30200 | 1181 char *buf; |
1182 ParserState old_state; | |
1183 size_t sz; | |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1184 |
30200 | 1185 buf = read_file(track->library, fname, &sz); |
1186 if (!buf) | |
1187 return 1; | |
27393 | 1188 #ifdef CONFIG_ICONV |
30200 | 1189 if (codepage) { |
1190 char *tmpbuf; | |
1191 tmpbuf = sub_recode(track->library, buf, sz, codepage); | |
1192 free(buf); | |
1193 buf = tmpbuf; | |
1194 } | |
1195 if (!buf) | |
1196 return 0; | |
20603 | 1197 #endif |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1198 |
30200 | 1199 old_state = track->parser_priv->state; |
1200 track->parser_priv->state = PST_STYLES; | |
1201 process_text(track, buf); | |
1202 track->parser_priv->state = old_state; | |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1203 |
30200 | 1204 return 0; |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1205 } |
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1206 |
30200 | 1207 long long ass_step_sub(ASS_Track *track, long long now, int movement) |
1208 { | |
1209 int i; | |
18937 | 1210 |
30200 | 1211 if (movement == 0) |
1212 return 0; | |
1213 if (track->n_events == 0) | |
1214 return 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1215 |
30200 | 1216 if (movement < 0) |
1217 for (i = 0; | |
1218 (i < track->n_events) | |
1219 && | |
1220 ((long long) (track->events[i].Start + | |
1221 track->events[i].Duration) <= now); ++i) { | |
1222 } else | |
1223 for (i = track->n_events - 1; | |
1224 (i >= 0) && ((long long) (track->events[i].Start) > now); | |
1225 --i) { | |
1226 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1227 |
30200 | 1228 // -1 and n_events are ok |
1229 assert(i >= -1); | |
1230 assert(i <= track->n_events); | |
1231 i += movement; | |
1232 if (i < 0) | |
1233 i = 0; | |
1234 if (i >= track->n_events) | |
1235 i = track->n_events - 1; | |
1236 return ((long long) track->events[i].Start) - now; | |
18937 | 1237 } |
1238 | |
30200 | 1239 ASS_Track *ass_new_track(ASS_Library *library) |
1240 { | |
1241 ASS_Track *track = calloc(1, sizeof(ASS_Track)); | |
1242 track->library = library; | |
1243 track->ScaledBorderAndShadow = 1; | |
1244 track->parser_priv = calloc(1, sizeof(ASS_ParserPriv)); | |
1245 return track; | |
18937 | 1246 } |