Mercurial > mplayer.hg
annotate libass/ass.c @ 33155:16e5b7f9ddb8
Send udp master updates also when paused and let slave use normal timing
when it gets no messages.
This allows the slave to continue playing normally if the master crashes
or network stops working instead of hanging forever.
Note that the slave might still hang for the 30 second network timeout
in some cases.
author | reimar |
---|---|
date | Sat, 09 Apr 2011 14:55:22 +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 } |