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