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