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