Mercurial > mplayer.hg
annotate libass/ass.c @ 36594:8c5bec08a72d
vo_corevideo: Fix VFCAP flags, adding ACCEPT_STRIDE and NOSLICES.
author | reimar |
---|---|
date | Wed, 22 Jan 2014 08:11:24 +0000 |
parents | c3aaaf17c721 |
children |
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); | |
36363 | 390 else if (!strcasecmp(*fs, "YCbCr Matrix")) |
391 track->YCbCrMatrix = parse_ycbcr_matrix(token); | |
25582
6b1d7568ae3d
Allow overriding [Script Info] parameters with -ass-force-style option.
eugeni
parents:
25515
diff
changeset
|
392 |
30200 | 393 dt = strrchr(*fs, '.'); |
394 if (dt) { | |
395 *dt = '\0'; | |
396 style = *fs; | |
397 tname = dt + 1; | |
398 } else { | |
399 style = NULL; | |
400 tname = *fs; | |
401 } | |
402 for (sid = 0; sid < track->n_styles; ++sid) { | |
403 if (style == NULL | |
404 || strcasecmp(track->styles[sid].Name, style) == 0) { | |
405 target = track->styles + sid; | |
406 if (0) { | |
407 STRVAL(FontName) | |
408 COLORVAL(PrimaryColour) | |
409 COLORVAL(SecondaryColour) | |
410 COLORVAL(OutlineColour) | |
411 COLORVAL(BackColour) | |
412 FPVAL(FontSize) | |
413 INTVAL(Bold) | |
414 INTVAL(Italic) | |
415 INTVAL(Underline) | |
416 INTVAL(StrikeOut) | |
417 FPVAL(Spacing) | |
418 INTVAL(Angle) | |
419 INTVAL(BorderStyle) | |
420 INTVAL(Alignment) | |
421 INTVAL(MarginL) | |
422 INTVAL(MarginR) | |
423 INTVAL(MarginV) | |
424 INTVAL(Encoding) | |
425 FPVAL(ScaleX) | |
426 FPVAL(ScaleY) | |
427 FPVAL(Outline) | |
428 FPVAL(Shadow) | |
36363 | 429 FPVAL(Blur) |
30200 | 430 } |
431 } | |
432 } | |
433 *eq = '='; | |
434 if (dt) | |
435 *dt = '.'; | |
436 } | |
19495 | 437 } |
438 | |
439 /** | |
18937 | 440 * \brief Parse the Style line |
441 * \param track track | |
442 * \param str string to parse, zero-terminated | |
443 * Allocates a new style struct. | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
444 */ |
30200 | 445 static int process_style(ASS_Track *track, char *str) |
18937 | 446 { |
447 | |
30200 | 448 char *token; |
449 char *tname; | |
450 char *p = str; | |
451 char *format; | |
452 char *q; // format scanning pointer | |
453 int sid; | |
454 ASS_Style *style; | |
455 ASS_Style *target; | |
18937 | 456 |
30200 | 457 if (!track->style_format) { |
458 // no style format header | |
459 // probably an ancient script version | |
460 if (track->track_type == TRACK_TYPE_SSA) | |
461 track->style_format = | |
462 strdup | |
463 ("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour," | |
464 "TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline," | |
465 "Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding"); | |
466 else | |
467 track->style_format = | |
468 strdup | |
469 ("Name, Fontname, Fontsize, PrimaryColour, SecondaryColour," | |
470 "OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut," | |
471 "ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow," | |
472 "Alignment, MarginL, MarginR, MarginV, Encoding"); | |
473 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
474 |
30200 | 475 q = format = strdup(track->style_format); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
476 |
34011 | 477 // Add default style first |
478 if (track->n_styles == 0) { | |
479 // will be used if track does not contain a default style (or even does not contain styles at all) | |
480 int sid = ass_alloc_style(track); | |
481 set_default_style(&track->styles[sid]); | |
482 track->default_style = sid; | |
483 } | |
484 | |
30200 | 485 ass_msg(track->library, MSGL_V, "[%p] Style: %s", track, str); |
486 | |
487 sid = ass_alloc_style(track); | |
18937 | 488 |
30200 | 489 style = track->styles + sid; |
490 target = style; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
491 |
30200 | 492 // fill style with some default values |
493 style->ScaleX = 100.; | |
494 style->ScaleY = 100.; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
495 |
30200 | 496 while (1) { |
497 NEXT(q, tname); | |
498 NEXT(p, token); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
499 |
30200 | 500 if (0) { // cool ;) |
501 STRVAL(Name) | |
502 if ((strcmp(target->Name, "Default") == 0) | |
503 || (strcmp(target->Name, "*Default") == 0)) | |
504 track->default_style = sid; | |
505 STRVAL(FontName) | |
506 COLORVAL(PrimaryColour) | |
507 COLORVAL(SecondaryColour) | |
508 COLORVAL(OutlineColour) // TertiaryColor | |
509 COLORVAL(BackColour) | |
510 // SSA uses BackColour for both outline and shadow | |
511 // this will destroy SSA's TertiaryColour, but i'm not going to use it anyway | |
512 if (track->track_type == TRACK_TYPE_SSA) | |
513 target->OutlineColour = target->BackColour; | |
514 FPVAL(FontSize) | |
515 INTVAL(Bold) | |
516 INTVAL(Italic) | |
517 INTVAL(Underline) | |
518 INTVAL(StrikeOut) | |
519 FPVAL(Spacing) | |
36363 | 520 FPVAL(Angle) |
30200 | 521 INTVAL(BorderStyle) |
522 INTVAL(Alignment) | |
523 if (track->track_type == TRACK_TYPE_ASS) | |
524 target->Alignment = numpad2align(target->Alignment); | |
525 INTVAL(MarginL) | |
526 INTVAL(MarginR) | |
527 INTVAL(MarginV) | |
528 INTVAL(Encoding) | |
529 FPVAL(ScaleX) | |
530 FPVAL(ScaleY) | |
531 FPVAL(Outline) | |
532 FPVAL(Shadow) | |
533 } | |
534 } | |
535 style->ScaleX /= 100.; | |
536 style->ScaleY /= 100.; | |
537 style->Bold = !!style->Bold; | |
538 style->Italic = !!style->Italic; | |
539 style->Underline = !!style->Underline; | |
540 if (!style->Name) | |
541 style->Name = strdup("Default"); | |
542 if (!style->FontName) | |
543 style->FontName = strdup("Arial"); | |
544 free(format); | |
545 return 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
546 |
18937 | 547 } |
548 | |
30200 | 549 static int process_styles_line(ASS_Track *track, char *str) |
19492 | 550 { |
30200 | 551 if (!strncmp(str, "Format:", 7)) { |
552 char *p = str + 7; | |
553 skip_spaces(&p); | |
554 track->style_format = strdup(p); | |
555 ass_msg(track->library, MSGL_DBG2, "Style format: %s", | |
556 track->style_format); | |
557 } else if (!strncmp(str, "Style:", 6)) { | |
558 char *p = str + 6; | |
559 skip_spaces(&p); | |
560 process_style(track, p); | |
561 } | |
562 return 0; | |
563 } | |
564 | |
565 static int process_info_line(ASS_Track *track, char *str) | |
566 { | |
567 if (!strncmp(str, "PlayResX:", 9)) { | |
568 track->PlayResX = atoi(str + 9); | |
569 } else if (!strncmp(str, "PlayResY:", 9)) { | |
570 track->PlayResY = atoi(str + 9); | |
571 } else if (!strncmp(str, "Timer:", 6)) { | |
31853 | 572 track->Timer = ass_atof(str + 6); |
30200 | 573 } else if (!strncmp(str, "WrapStyle:", 10)) { |
574 track->WrapStyle = atoi(str + 10); | |
575 } else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) { | |
576 track->ScaledBorderAndShadow = parse_bool(str + 22); | |
577 } else if (!strncmp(str, "Kerning:", 8)) { | |
578 track->Kerning = parse_bool(str + 8); | |
36363 | 579 } else if (!strncmp(str, "YCbCr Matrix:", 13)) { |
580 track->YCbCrMatrix = parse_ycbcr_matrix(str + 13); | |
34295 | 581 } else if (!strncmp(str, "Language:", 9)) { |
582 char *p = str + 9; | |
583 while (*p && isspace(*p)) p++; | |
584 track->Language = malloc(3); | |
585 strncpy(track->Language, p, 2); | |
586 track->Language[2] = 0; | |
30200 | 587 } |
588 return 0; | |
19492 | 589 } |
590 | |
30200 | 591 static void event_format_fallback(ASS_Track *track) |
19492 | 592 { |
30200 | 593 track->parser_priv->state = PST_EVENTS; |
594 if (track->track_type == TRACK_TYPE_SSA) | |
36363 | 595 track->event_format = strdup("Marked, Start, End, Style, " |
30200 | 596 "Name, MarginL, MarginR, MarginV, Effect, Text"); |
597 else | |
36363 | 598 track->event_format = strdup("Layer, Start, End, Style, " |
30200 | 599 "Actor, MarginL, MarginR, MarginV, Effect, Text"); |
600 ass_msg(track->library, MSGL_V, | |
601 "No event format found, using fallback"); | |
19492 | 602 } |
603 | |
30200 | 604 static int process_events_line(ASS_Track *track, char *str) |
19492 | 605 { |
30200 | 606 if (!strncmp(str, "Format:", 7)) { |
607 char *p = str + 7; | |
608 skip_spaces(&p); | |
31875 | 609 free(track->event_format); |
30200 | 610 track->event_format = strdup(p); |
611 ass_msg(track->library, MSGL_DBG2, "Event format: %s", track->event_format); | |
612 } else if (!strncmp(str, "Dialogue:", 9)) { | |
613 // This should never be reached for embedded subtitles. | |
614 // They have slightly different format and are parsed in ass_process_chunk, | |
615 // called directly from demuxer | |
616 int eid; | |
617 ASS_Event *event; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
618 |
30200 | 619 str += 9; |
620 skip_spaces(&str); | |
19492 | 621 |
30200 | 622 eid = ass_alloc_event(track); |
623 event = track->events + eid; | |
19492 | 624 |
30200 | 625 // We can't parse events with event_format |
626 if (!track->event_format) | |
627 event_format_fallback(track); | |
628 | |
629 process_event_tail(track, event, str, 0); | |
630 } else { | |
31853 | 631 ass_msg(track->library, MSGL_V, "Not understood: '%.30s'", str); |
30200 | 632 } |
633 return 0; | |
19492 | 634 } |
635 | |
636 // Copied from mkvtoolnix | |
30200 | 637 static unsigned char *decode_chars(unsigned char c1, unsigned char c2, |
638 unsigned char c3, unsigned char c4, | |
639 unsigned char *dst, int cnt) | |
19492 | 640 { |
30200 | 641 uint32_t value; |
642 unsigned char bytes[3]; | |
643 int i; | |
19492 | 644 |
30200 | 645 value = |
646 ((c1 - 33) << 18) + ((c2 - 33) << 12) + ((c3 - 33) << 6) + (c4 - | |
647 33); | |
648 bytes[2] = value & 0xff; | |
649 bytes[1] = (value & 0xff00) >> 8; | |
650 bytes[0] = (value & 0xff0000) >> 16; | |
19492 | 651 |
30200 | 652 for (i = 0; i < cnt; ++i) |
653 *dst++ = bytes[i]; | |
654 return dst; | |
19492 | 655 } |
656 | |
30200 | 657 static int decode_font(ASS_Track *track) |
19492 | 658 { |
30200 | 659 unsigned char *p; |
660 unsigned char *q; | |
661 int i; | |
662 int size; // original size | |
663 int dsize; // decoded size | |
664 unsigned char *buf = 0; | |
19492 | 665 |
30200 | 666 ass_msg(track->library, MSGL_V, "Font: %d bytes encoded data", |
667 track->parser_priv->fontdata_used); | |
668 size = track->parser_priv->fontdata_used; | |
669 if (size % 4 == 1) { | |
670 ass_msg(track->library, MSGL_ERR, "Bad encoded data size"); | |
671 goto error_decode_font; | |
672 } | |
673 buf = malloc(size / 4 * 3 + 2); | |
674 q = buf; | |
675 for (i = 0, p = (unsigned char *) track->parser_priv->fontdata; | |
676 i < size / 4; i++, p += 4) { | |
677 q = decode_chars(p[0], p[1], p[2], p[3], q, 3); | |
678 } | |
679 if (size % 4 == 2) { | |
680 q = decode_chars(p[0], p[1], 0, 0, q, 1); | |
681 } else if (size % 4 == 3) { | |
682 q = decode_chars(p[0], p[1], p[2], 0, q, 2); | |
683 } | |
684 dsize = q - buf; | |
685 assert(dsize <= size / 4 * 3 + 2); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
686 |
30200 | 687 if (track->library->extract_fonts) { |
688 ass_add_font(track->library, track->parser_priv->fontname, | |
689 (char *) buf, dsize); | |
690 } | |
19492 | 691 |
31875 | 692 error_decode_font: |
693 free(buf); | |
30200 | 694 free(track->parser_priv->fontname); |
695 free(track->parser_priv->fontdata); | |
696 track->parser_priv->fontname = 0; | |
697 track->parser_priv->fontdata = 0; | |
698 track->parser_priv->fontdata_size = 0; | |
699 track->parser_priv->fontdata_used = 0; | |
700 return 0; | |
19492 | 701 } |
702 | |
30200 | 703 static int process_fonts_line(ASS_Track *track, char *str) |
19492 | 704 { |
30200 | 705 int len; |
19492 | 706 |
30200 | 707 if (!strncmp(str, "fontname:", 9)) { |
708 char *p = str + 9; | |
709 skip_spaces(&p); | |
710 if (track->parser_priv->fontname) { | |
711 decode_font(track); | |
712 } | |
713 track->parser_priv->fontname = strdup(p); | |
714 ass_msg(track->library, MSGL_V, "Fontname: %s", | |
715 track->parser_priv->fontname); | |
716 return 0; | |
717 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
718 |
30200 | 719 if (!track->parser_priv->fontname) { |
720 ass_msg(track->library, MSGL_V, "Not understood: '%s'", str); | |
721 return 0; | |
722 } | |
19492 | 723 |
30200 | 724 len = strlen(str); |
725 if (len > 80) { | |
726 ass_msg(track->library, MSGL_WARN, "Font line too long: %d, %s", | |
727 len, str); | |
728 return 0; | |
729 } | |
730 if (track->parser_priv->fontdata_used + len > | |
731 track->parser_priv->fontdata_size) { | |
732 track->parser_priv->fontdata_size += 100 * 1024; | |
733 track->parser_priv->fontdata = | |
734 realloc(track->parser_priv->fontdata, | |
735 track->parser_priv->fontdata_size); | |
736 } | |
737 memcpy(track->parser_priv->fontdata + track->parser_priv->fontdata_used, | |
738 str, len); | |
739 track->parser_priv->fontdata_used += len; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
740 |
30200 | 741 return 0; |
19492 | 742 } |
743 | |
18937 | 744 /** |
745 * \brief Parse a header line | |
746 * \param track track | |
747 * \param str string to parse, zero-terminated | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
748 */ |
30200 | 749 static int process_line(ASS_Track *track, char *str) |
18937 | 750 { |
30200 | 751 if (!strncasecmp(str, "[Script Info]", 13)) { |
752 track->parser_priv->state = PST_INFO; | |
753 } else if (!strncasecmp(str, "[V4 Styles]", 11)) { | |
754 track->parser_priv->state = PST_STYLES; | |
755 track->track_type = TRACK_TYPE_SSA; | |
756 } else if (!strncasecmp(str, "[V4+ Styles]", 12)) { | |
757 track->parser_priv->state = PST_STYLES; | |
758 track->track_type = TRACK_TYPE_ASS; | |
759 } else if (!strncasecmp(str, "[Events]", 8)) { | |
760 track->parser_priv->state = PST_EVENTS; | |
761 } else if (!strncasecmp(str, "[Fonts]", 7)) { | |
762 track->parser_priv->state = PST_FONTS; | |
763 } else { | |
764 switch (track->parser_priv->state) { | |
765 case PST_INFO: | |
766 process_info_line(track, str); | |
767 break; | |
768 case PST_STYLES: | |
769 process_styles_line(track, str); | |
770 break; | |
771 case PST_EVENTS: | |
772 process_events_line(track, str); | |
773 break; | |
774 case PST_FONTS: | |
775 process_fonts_line(track, str); | |
776 break; | |
777 default: | |
778 break; | |
779 } | |
780 } | |
19492 | 781 |
30200 | 782 // there is no explicit end-of-font marker in ssa/ass |
783 if ((track->parser_priv->state != PST_FONTS) | |
784 && (track->parser_priv->fontname)) | |
785 decode_font(track); | |
19492 | 786 |
30200 | 787 return 0; |
19492 | 788 } |
789 | |
30200 | 790 static int process_text(ASS_Track *track, char *str) |
19492 | 791 { |
30200 | 792 char *p = str; |
793 while (1) { | |
794 char *q; | |
795 while (1) { | |
796 if ((*p == '\r') || (*p == '\n')) | |
797 ++p; | |
798 else if (p[0] == '\xef' && p[1] == '\xbb' && p[2] == '\xbf') | |
799 p += 3; // U+FFFE (BOM) | |
800 else | |
801 break; | |
802 } | |
803 for (q = p; ((*q != '\0') && (*q != '\r') && (*q != '\n')); ++q) { | |
804 }; | |
805 if (q == p) | |
806 break; | |
807 if (*q != '\0') | |
808 *(q++) = '\0'; | |
809 process_line(track, p); | |
810 if (*q == '\0') | |
811 break; | |
812 p = q; | |
813 } | |
814 return 0; | |
18937 | 815 } |
816 | |
817 /** | |
27498
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
818 * \brief Process a chunk of subtitle stream data. |
18937 | 819 * \param track track |
820 * \param data string to parse | |
821 * \param size length of data | |
27498
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
822 */ |
30200 | 823 void ass_process_data(ASS_Track *track, char *data, int size) |
18937 | 824 { |
30200 | 825 char *str = malloc(size + 1); |
18937 | 826 |
30200 | 827 memcpy(str, data, size); |
828 str[size] = '\0'; | |
18937 | 829 |
30200 | 830 ass_msg(track->library, MSGL_V, "Event: %s", str); |
831 process_text(track, str); | |
832 free(str); | |
27498
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
833 } |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
834 |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
835 /** |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
836 * \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
|
837 * \param track track |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
838 * \param data string to parse |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
839 * \param size length of data |
d895515b366d
libass: add a new ass_process_data() to process demuxed subtitle packets
aurel
parents:
27393
diff
changeset
|
840 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
|
841 */ |
30200 | 842 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
|
843 { |
30200 | 844 ass_process_data(track, data, size); |
18937 | 845 |
30200 | 846 // probably an mkv produced by ancient mkvtoolnix |
847 // such files don't have [Events] and Format: headers | |
848 if (!track->event_format) | |
849 event_format_fallback(track); | |
19495 | 850 |
30200 | 851 ass_process_force_style(track); |
18937 | 852 } |
853 | |
30200 | 854 static int check_duplicate_event(ASS_Track *track, int ReadOrder) |
18937 | 855 { |
30200 | 856 int i; |
857 for (i = 0; i < track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with | |
858 if (track->events[i].ReadOrder == ReadOrder) | |
859 return 1; | |
860 return 0; | |
18937 | 861 } |
862 | |
863 /** | |
25515 | 864 * \brief Process a chunk of subtitle stream data. In Matroska, this contains exactly 1 event (or a commentary). |
18937 | 865 * \param track track |
866 * \param data string to parse | |
867 * \param size length of data | |
868 * \param timecode starting time of the event (milliseconds) | |
869 * \param duration duration of the event (milliseconds) | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
870 */ |
30200 | 871 void ass_process_chunk(ASS_Track *track, char *data, int size, |
872 long long timecode, long long duration) | |
18937 | 873 { |
30200 | 874 char *str; |
875 int eid; | |
876 char *p; | |
877 char *token; | |
878 ASS_Event *event; | |
18937 | 879 |
30200 | 880 if (!track->event_format) { |
881 ass_msg(track->library, MSGL_WARN, "Event format header missing"); | |
882 return; | |
883 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
884 |
30200 | 885 str = malloc(size + 1); |
886 memcpy(str, data, size); | |
887 str[size] = '\0'; | |
888 ass_msg(track->library, MSGL_V, "Event at %" PRId64 ", +%" PRId64 ": %s", | |
889 (int64_t) timecode, (int64_t) duration, str); | |
18937 | 890 |
30200 | 891 eid = ass_alloc_event(track); |
892 event = track->events + eid; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
893 |
30200 | 894 p = str; |
18937 | 895 |
30200 | 896 do { |
897 NEXT(p, token); | |
898 event->ReadOrder = atoi(token); | |
899 if (check_duplicate_event(track, event->ReadOrder)) | |
900 break; | |
18937 | 901 |
30200 | 902 NEXT(p, token); |
903 event->Layer = atoi(token); | |
18937 | 904 |
30200 | 905 process_event_tail(track, event, p, 3); |
906 | |
907 event->Start = timecode; | |
908 event->Duration = duration; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
909 |
30200 | 910 free(str); |
911 return; | |
912 // dump_events(tid); | |
913 } while (0); | |
914 // some error | |
915 ass_free_event(track, eid); | |
916 track->n_events--; | |
917 free(str); | |
18937 | 918 } |
919 | |
31227
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 * \brief Flush buffered events. |
ee7beb1a3a6e
backport ass_flush_events() from upstream libass and make use of it
aurel
parents:
30200
diff
changeset
|
922 * \param track track |
ee7beb1a3a6e
backport ass_flush_events() from upstream libass and make use of it
aurel
parents:
30200
diff
changeset
|
923 */ |
ee7beb1a3a6e
backport ass_flush_events() from upstream libass and make use of it
aurel
parents:
30200
diff
changeset
|
924 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
|
925 { |
ee7beb1a3a6e
backport ass_flush_events() from upstream libass and make use of it
aurel
parents:
30200
diff
changeset
|
926 if (track->events) { |
ee7beb1a3a6e
backport ass_flush_events() from upstream libass and make use of it
aurel
parents:
30200
diff
changeset
|
927 int eid; |
ee7beb1a3a6e
backport ass_flush_events() from upstream libass and make use of it
aurel
parents:
30200
diff
changeset
|
928 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
|
929 ass_free_event(track, eid); |
ee7beb1a3a6e
backport ass_flush_events() from upstream libass and make use of it
aurel
parents:
30200
diff
changeset
|
930 track->n_events = 0; |
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 } |
ee7beb1a3a6e
backport ass_flush_events() from upstream libass and make use of it
aurel
parents:
30200
diff
changeset
|
933 |
27393 | 934 #ifdef CONFIG_ICONV |
18937 | 935 /** \brief recode buffer to utf-8 |
20477 | 936 * constraint: codepage != 0 |
18937 | 937 * \param data pointer to text buffer |
938 * \param size buffer size | |
939 * \return a pointer to recoded buffer, caller is responsible for freeing it | |
940 **/ | |
30200 | 941 static char *sub_recode(ASS_Library *library, char *data, size_t size, |
942 char *codepage) | |
18937 | 943 { |
30200 | 944 iconv_t icdsc; |
945 char *tocp = "UTF-8"; | |
946 char *outbuf; | |
947 assert(codepage); | |
18937 | 948 |
30200 | 949 { |
950 const char *cp_tmp = codepage; | |
27393 | 951 #ifdef CONFIG_ENCA |
30200 | 952 char enca_lang[3], enca_fallback[100]; |
953 if (sscanf(codepage, "enca:%2s:%99s", enca_lang, enca_fallback) == 2 | |
954 || sscanf(codepage, "ENCA:%2s:%99s", enca_lang, | |
955 enca_fallback) == 2) { | |
956 cp_tmp = | |
957 ass_guess_buffer_cp(library, (unsigned char *) data, size, | |
958 enca_lang, enca_fallback); | |
959 } | |
18937 | 960 #endif |
30200 | 961 if ((icdsc = iconv_open(tocp, cp_tmp)) != (iconv_t) (-1)) { |
962 ass_msg(library, MSGL_V, "Opened iconv descriptor"); | |
963 } else | |
964 ass_msg(library, MSGL_ERR, "Error opening iconv descriptor"); | |
965 } | |
18937 | 966 |
30200 | 967 { |
968 size_t osize = size; | |
969 size_t ileft = size; | |
970 size_t oleft = size - 1; | |
971 char *ip; | |
972 char *op; | |
973 size_t rc; | |
974 int clear = 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
975 |
30200 | 976 outbuf = malloc(osize); |
977 ip = data; | |
978 op = outbuf; | |
18937 | 979 |
30200 | 980 while (1) { |
981 if (ileft) | |
982 rc = iconv(icdsc, &ip, &ileft, &op, &oleft); | |
983 else { // clear the conversion state and leave | |
984 clear = 1; | |
985 rc = iconv(icdsc, NULL, NULL, &op, &oleft); | |
986 } | |
987 if (rc == (size_t) (-1)) { | |
988 if (errno == E2BIG) { | |
989 size_t offset = op - outbuf; | |
990 outbuf = (char *) realloc(outbuf, osize + size); | |
991 op = outbuf + offset; | |
992 osize += size; | |
993 oleft += size; | |
994 } else { | |
995 ass_msg(library, MSGL_WARN, "Error recoding file"); | |
35701 | 996 free(outbuf); |
35716 | 997 outbuf = NULL; |
998 goto out; | |
30200 | 999 } |
1000 } else if (clear) | |
1001 break; | |
1002 } | |
1003 outbuf[osize - oleft - 1] = 0; | |
1004 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1005 |
35701 | 1006 out: |
30200 | 1007 if (icdsc != (iconv_t) (-1)) { |
1008 (void) iconv_close(icdsc); | |
1009 icdsc = (iconv_t) (-1); | |
1010 ass_msg(library, MSGL_V, "Closed iconv descriptor"); | |
1011 } | |
1012 | |
1013 return outbuf; | |
18937 | 1014 } |
30200 | 1015 #endif // ICONV |
18937 | 1016 |
1017 /** | |
20603 | 1018 * \brief read file contents into newly allocated buffer |
1019 * \param fname file name | |
1020 * \param bufsize out: file size | |
1021 * \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
|
1022 */ |
30200 | 1023 static char *read_file(ASS_Library *library, char *fname, size_t *bufsize) |
18937 | 1024 { |
30200 | 1025 int res; |
1026 long sz; | |
1027 long bytes_read; | |
1028 char *buf; | |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1029 |
30200 | 1030 FILE *fp = fopen(fname, "rb"); |
1031 if (!fp) { | |
1032 ass_msg(library, MSGL_WARN, | |
1033 "ass_read_file(%s): fopen failed", fname); | |
1034 return 0; | |
1035 } | |
1036 res = fseek(fp, 0, SEEK_END); | |
1037 if (res == -1) { | |
1038 ass_msg(library, MSGL_WARN, | |
1039 "ass_read_file(%s): fseek failed", fname); | |
1040 fclose(fp); | |
1041 return 0; | |
1042 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1043 |
30200 | 1044 sz = ftell(fp); |
1045 rewind(fp); | |
18937 | 1046 |
30200 | 1047 ass_msg(library, MSGL_V, "File size: %ld", sz); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1048 |
30200 | 1049 buf = malloc(sz + 1); |
1050 assert(buf); | |
1051 bytes_read = 0; | |
1052 do { | |
1053 res = fread(buf + bytes_read, 1, sz - bytes_read, fp); | |
1054 if (res <= 0) { | |
1055 ass_msg(library, MSGL_INFO, "Read failed, %d: %s", errno, | |
1056 strerror(errno)); | |
1057 fclose(fp); | |
1058 free(buf); | |
1059 return 0; | |
1060 } | |
1061 bytes_read += res; | |
1062 } while (sz - bytes_read > 0); | |
1063 buf[sz] = '\0'; | |
1064 fclose(fp); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1065 |
30200 | 1066 if (bufsize) |
1067 *bufsize = sz; | |
1068 return buf; | |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1069 } |
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1070 |
20603 | 1071 /* |
1072 * \param buf pointer to subtitle text in utf-8 | |
1073 */ | |
30200 | 1074 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
|
1075 { |
30200 | 1076 ASS_Track *track; |
1077 int i; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1078 |
30200 | 1079 track = ass_new_track(library); |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1080 |
30200 | 1081 // process header |
1082 process_text(track, buf); | |
19492 | 1083 |
30200 | 1084 // external SSA/ASS subs does not have ReadOrder field |
1085 for (i = 0; i < track->n_events; ++i) | |
1086 track->events[i].ReadOrder = i; | |
19905 | 1087 |
30200 | 1088 // there is no explicit end-of-font marker in ssa/ass |
1089 if (track->parser_priv->fontname) | |
1090 decode_font(track); | |
19492 | 1091 |
30200 | 1092 if (track->track_type == TRACK_TYPE_UNKNOWN) { |
1093 ass_free_track(track); | |
1094 return 0; | |
1095 } | |
18937 | 1096 |
30200 | 1097 ass_process_force_style(track); |
19495 | 1098 |
30200 | 1099 return track; |
20603 | 1100 } |
1101 | |
1102 /** | |
1103 * \brief Read subtitles from memory. | |
1104 * \param library libass library object | |
1105 * \param buf pointer to subtitles text | |
1106 * \param bufsize size of buffer | |
1107 * \param codepage recode buffer contents from given codepage | |
1108 * \return newly allocated track | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1109 */ |
30200 | 1110 ASS_Track *ass_read_memory(ASS_Library *library, char *buf, |
1111 size_t bufsize, char *codepage) | |
20603 | 1112 { |
30200 | 1113 ASS_Track *track; |
1114 int need_free = 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1115 |
30200 | 1116 if (!buf) |
1117 return 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1118 |
27393 | 1119 #ifdef CONFIG_ICONV |
30200 | 1120 if (codepage) { |
1121 buf = sub_recode(library, buf, bufsize, codepage); | |
1122 if (!buf) | |
1123 return 0; | |
1124 else | |
1125 need_free = 1; | |
1126 } | |
20603 | 1127 #endif |
30200 | 1128 track = parse_memory(library, buf); |
1129 if (need_free) | |
1130 free(buf); | |
1131 if (!track) | |
1132 return 0; | |
20603 | 1133 |
30200 | 1134 ass_msg(library, MSGL_INFO, "Added subtitle file: " |
1135 "<memory> (%d styles, %d events)", | |
1136 track->n_styles, track->n_events); | |
1137 return track; | |
20603 | 1138 } |
1139 | |
30200 | 1140 static char *read_file_recode(ASS_Library *library, char *fname, |
1141 char *codepage, size_t *size) | |
20603 | 1142 { |
30200 | 1143 char *buf; |
1144 size_t bufsize; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1145 |
30200 | 1146 buf = read_file(library, fname, &bufsize); |
1147 if (!buf) | |
1148 return 0; | |
27393 | 1149 #ifdef CONFIG_ICONV |
30200 | 1150 if (codepage) { |
1151 char *tmpbuf = sub_recode(library, buf, bufsize, codepage); | |
1152 free(buf); | |
1153 buf = tmpbuf; | |
1154 } | |
1155 if (!buf) | |
1156 return 0; | |
20603 | 1157 #endif |
30200 | 1158 *size = bufsize; |
1159 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
|
1160 } |
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1161 |
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1162 /** |
7286d245bf33
Move code for reading a file and recoding it to utf-8 to a separate function.
eugeni
parents:
23300
diff
changeset
|
1163 * \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
|
1164 * \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
|
1165 * \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
|
1166 * \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
|
1167 * \return newly allocated track |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1168 */ |
30200 | 1169 ASS_Track *ass_read_file(ASS_Library *library, char *fname, |
1170 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
|
1171 { |
30200 | 1172 char *buf; |
1173 ASS_Track *track; | |
1174 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
|
1175 |
30200 | 1176 buf = read_file_recode(library, fname, codepage, &bufsize); |
1177 if (!buf) | |
1178 return 0; | |
1179 track = parse_memory(library, buf); | |
1180 free(buf); | |
1181 if (!track) | |
1182 return 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1183 |
30200 | 1184 track->name = strdup(fname); |
20603 | 1185 |
30200 | 1186 ass_msg(library, MSGL_INFO, |
1187 "Added subtitle file: '%s' (%d styles, %d events)", | |
1188 fname, track->n_styles, track->n_events); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1189 |
30200 | 1190 return track; |
18937 | 1191 } |
1192 | |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1193 /** |
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1194 * \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
|
1195 */ |
30200 | 1196 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
|
1197 { |
30200 | 1198 char *buf; |
1199 ParserState old_state; | |
1200 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
|
1201 |
30200 | 1202 buf = read_file(track->library, fname, &sz); |
1203 if (!buf) | |
1204 return 1; | |
27393 | 1205 #ifdef CONFIG_ICONV |
30200 | 1206 if (codepage) { |
1207 char *tmpbuf; | |
1208 tmpbuf = sub_recode(track->library, buf, sz, codepage); | |
1209 free(buf); | |
1210 buf = tmpbuf; | |
1211 } | |
1212 if (!buf) | |
1213 return 0; | |
20603 | 1214 #endif |
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 old_state = track->parser_priv->state; |
1217 track->parser_priv->state = PST_STYLES; | |
1218 process_text(track, buf); | |
1219 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
|
1220 |
30200 | 1221 return 0; |
19652
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1222 } |
2c016957360a
Add -ass-styles option. It allows to load styles from a file and use them
eugeni
parents:
19639
diff
changeset
|
1223 |
30200 | 1224 long long ass_step_sub(ASS_Track *track, long long now, int movement) |
1225 { | |
1226 int i; | |
18937 | 1227 |
30200 | 1228 if (movement == 0) |
1229 return 0; | |
1230 if (track->n_events == 0) | |
1231 return 0; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1232 |
30200 | 1233 if (movement < 0) |
1234 for (i = 0; | |
1235 (i < track->n_events) | |
1236 && | |
1237 ((long long) (track->events[i].Start + | |
1238 track->events[i].Duration) <= now); ++i) { | |
1239 } else | |
1240 for (i = track->n_events - 1; | |
1241 (i >= 0) && ((long long) (track->events[i].Start) > now); | |
1242 --i) { | |
1243 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
28900
diff
changeset
|
1244 |
30200 | 1245 // -1 and n_events are ok |
1246 assert(i >= -1); | |
1247 assert(i <= track->n_events); | |
1248 i += movement; | |
1249 if (i < 0) | |
1250 i = 0; | |
1251 if (i >= track->n_events) | |
1252 i = track->n_events - 1; | |
1253 return ((long long) track->events[i].Start) - now; | |
18937 | 1254 } |
1255 | |
30200 | 1256 ASS_Track *ass_new_track(ASS_Library *library) |
1257 { | |
1258 ASS_Track *track = calloc(1, sizeof(ASS_Track)); | |
1259 track->library = library; | |
1260 track->ScaledBorderAndShadow = 1; | |
1261 track->parser_priv = calloc(1, sizeof(ASS_ParserPriv)); | |
1262 return track; | |
18937 | 1263 } |
34295 | 1264 |
1265 /** | |
1266 * \brief Prepare track for rendering | |
1267 */ | |
1268 void ass_lazy_track_init(ASS_Library *lib, ASS_Track *track) | |
1269 { | |
1270 if (track->PlayResX && track->PlayResY) | |
1271 return; | |
1272 if (!track->PlayResX && !track->PlayResY) { | |
1273 ass_msg(lib, MSGL_WARN, | |
1274 "Neither PlayResX nor PlayResY defined. Assuming 384x288"); | |
1275 track->PlayResX = 384; | |
1276 track->PlayResY = 288; | |
1277 } else { | |
1278 if (!track->PlayResY && track->PlayResX == 1280) { | |
1279 track->PlayResY = 1024; | |
1280 ass_msg(lib, MSGL_WARN, | |
1281 "PlayResY undefined, setting to %d", track->PlayResY); | |
1282 } else if (!track->PlayResY) { | |
1283 track->PlayResY = track->PlayResX * 3 / 4; | |
1284 ass_msg(lib, MSGL_WARN, | |
1285 "PlayResY undefined, setting to %d", track->PlayResY); | |
1286 } else if (!track->PlayResX && track->PlayResY == 1024) { | |
1287 track->PlayResX = 1280; | |
1288 ass_msg(lib, MSGL_WARN, | |
1289 "PlayResX undefined, setting to %d", track->PlayResX); | |
1290 } else if (!track->PlayResX) { | |
1291 track->PlayResX = track->PlayResY * 4 / 3; | |
1292 ass_msg(lib, MSGL_WARN, | |
1293 "PlayResX undefined, setting to %d", track->PlayResX); | |
1294 } | |
1295 } | |
1296 } |