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