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