Mercurial > mplayer.hg
annotate ass_mp.c @ 32359:3f8dcfb95845
Fix switching audio track with the native MPEG-TS demuxer after an
additional subtitle stream was detected.
Patch by KS Ng, hk D dmbth A gmail
author | cehoyos |
---|---|
date | Wed, 06 Oct 2010 17:37:50 +0000 |
parents | f6ff1c427ff3 |
children | b4c3659d16b1 |
rev | line source |
---|---|
32209 | 1 /* |
2 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> | |
3 * | |
32210
f6ff1c427ff3
Adapt license header from libass to MPlayer boilerplate.
diego
parents:
32209
diff
changeset
|
4 * This file is part of MPlayer. |
32209 | 5 * |
32210
f6ff1c427ff3
Adapt license header from libass to MPlayer boilerplate.
diego
parents:
32209
diff
changeset
|
6 * MPlayer is free software; you can redistribute it and/or modify |
32209 | 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 * | |
32210
f6ff1c427ff3
Adapt license header from libass to MPlayer boilerplate.
diego
parents:
32209
diff
changeset
|
11 * MPlayer is distributed in the hope that it will be useful, |
32209 | 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 | |
32210
f6ff1c427ff3
Adapt license header from libass to MPlayer boilerplate.
diego
parents:
32209
diff
changeset
|
17 * with MPlayer; if not, write to the Free Software Foundation, Inc., |
32209 | 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 */ | |
20 | |
21 #include <inttypes.h> | |
22 #include <string.h> | |
23 #include <stdlib.h> | |
24 | |
25 #include "mp_msg.h" | |
26 #include "mpcommon.h" | |
27 #include "path.h" | |
28 #include "subreader.h" | |
29 | |
30 #include "ass_mp.h" | |
31 #include "help_mp.h" | |
32 #include "libvo/font_load.h" | |
33 #include "stream/stream.h" | |
34 | |
35 #ifdef CONFIG_FONTCONFIG | |
36 #include <fontconfig/fontconfig.h> | |
37 #endif | |
38 | |
39 // libass-related command line options | |
40 ASS_Library* ass_library; | |
41 int ass_enabled = 0; | |
42 float ass_font_scale = 1.; | |
43 float ass_line_spacing = 0.; | |
44 int ass_top_margin = 0; | |
45 int ass_bottom_margin = 0; | |
46 int extract_embedded_fonts = 1; | |
47 char **ass_force_style_list = NULL; | |
48 int ass_use_margins = 0; | |
49 char* ass_color = NULL; | |
50 char* ass_border_color = NULL; | |
51 char* ass_styles_file = NULL; | |
52 int ass_hinting = ASS_HINTING_NATIVE + 4; // native hinting for unscaled osd | |
53 | |
54 ASS_Track* ass_default_track(ASS_Library* library) { | |
55 ASS_Track* track = ass_new_track(library); | |
56 | |
57 track->track_type = TRACK_TYPE_ASS; | |
58 track->Timer = 100.; | |
59 track->PlayResY = 288; | |
60 track->WrapStyle = 0; | |
61 | |
62 if (ass_styles_file) | |
63 ass_read_styles(track, ass_styles_file, sub_cp); | |
64 | |
65 if (track->n_styles == 0) { | |
66 ASS_Style* style; | |
67 int sid; | |
68 double fs; | |
69 uint32_t c1, c2; | |
70 | |
71 sid = ass_alloc_style(track); | |
72 style = track->styles + sid; | |
73 style->Name = strdup("Default"); | |
74 style->FontName = (font_fontconfig >= 0 && sub_font_name) ? strdup(sub_font_name) : (font_fontconfig >= 0 && font_name) ? strdup(font_name) : strdup("Sans"); | |
75 style->treat_fontname_as_pattern = 1; | |
76 | |
77 fs = track->PlayResY * text_font_scale_factor / 100.; | |
78 // approximate autoscale coefficients | |
79 if (subtitle_autoscale == 2) | |
80 fs *= 1.3; | |
81 else if (subtitle_autoscale == 3) | |
82 fs *= 1.4; | |
83 style->FontSize = fs; | |
84 | |
85 if (ass_color) c1 = strtoll(ass_color, NULL, 16); | |
86 else c1 = 0xFFFF0000; | |
87 if (ass_border_color) c2 = strtoll(ass_border_color, NULL, 16); | |
88 else c2 = 0x00000000; | |
89 | |
90 style->PrimaryColour = c1; | |
91 style->SecondaryColour = c1; | |
92 style->OutlineColour = c2; | |
93 style->BackColour = 0x00000000; | |
94 style->BorderStyle = 1; | |
95 style->Alignment = 2; | |
96 style->Outline = 2; | |
97 style->MarginL = 10; | |
98 style->MarginR = 10; | |
99 style->MarginV = 5; | |
100 style->ScaleX = 1.; | |
101 style->ScaleY = 1.; | |
102 } | |
103 | |
104 ass_process_force_style(track); | |
105 return track; | |
106 } | |
107 | |
108 static int check_duplicate_plaintext_event(ASS_Track* track) | |
109 { | |
110 int i; | |
111 ASS_Event* evt = track->events + track->n_events - 1; | |
112 | |
113 for (i = 0; i<track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with | |
114 if (track->events[i].Start == evt->Start && | |
115 track->events[i].Duration == evt->Duration && | |
116 strcmp(track->events[i].Text, evt->Text) == 0) | |
117 return 1; | |
118 return 0; | |
119 } | |
120 | |
121 /** | |
122 * \brief Convert subtitle to ASS_Event for the given track | |
123 * \param track ASS_Track | |
124 * \param sub subtitle to convert | |
125 * \return event id | |
126 * note: assumes that subtitle is _not_ fps-based; caller must manually correct | |
127 * Start and Duration in other case. | |
128 **/ | |
129 int ass_process_subtitle(ASS_Track* track, subtitle* sub) | |
130 { | |
131 int eid; | |
132 ASS_Event* event; | |
133 int len = 0, j; | |
134 char* p; | |
135 char* end; | |
136 | |
137 eid = ass_alloc_event(track); | |
138 event = track->events + eid; | |
139 | |
140 event->Start = sub->start * 10; | |
141 event->Duration = (sub->end - sub->start) * 10; | |
142 event->Style = 0; | |
143 | |
144 for (j = 0; j < sub->lines; ++j) | |
145 len += sub->text[j] ? strlen(sub->text[j]) : 0; | |
146 | |
147 len += 2 * sub->lines; // '\N', including the one after the last line | |
148 len += 6; // {\anX} | |
149 len += 1; // '\0' | |
150 | |
151 event->Text = malloc(len); | |
152 end = event->Text + len; | |
153 p = event->Text; | |
154 | |
155 if (sub->alignment) | |
156 p += snprintf(p, end - p, "{\\an%d}", sub->alignment); | |
157 | |
158 for (j = 0; j < sub->lines; ++j) | |
159 p += snprintf(p, end - p, "%s\\N", sub->text[j]); | |
160 | |
161 if (sub->lines > 0) p-=2; // remove last "\N" | |
162 *p = 0; | |
163 | |
164 if (check_duplicate_plaintext_event(track)) { | |
165 ass_free_event(track, eid); | |
166 track->n_events--; | |
167 return -1; | |
168 } | |
169 | |
170 mp_msg(MSGT_ASS, MSGL_V, "plaintext event at %" PRId64 ", +%" PRId64 ": %s \n", | |
171 (int64_t)event->Start, (int64_t)event->Duration, event->Text); | |
172 | |
173 return eid; | |
174 } | |
175 | |
176 | |
177 /** | |
178 * \brief Convert subdata to ASS_Track | |
179 * \param subdata subtitles struct from subreader | |
180 * \param fps video framerate | |
181 * \return newly allocated ASS_Track, filled with subtitles from subdata | |
182 */ | |
183 ASS_Track* ass_read_subdata(ASS_Library* library, sub_data* subdata, double fps) { | |
184 ASS_Track* track; | |
185 int i; | |
186 | |
187 track = ass_default_track(library); | |
188 track->name = subdata->filename ? strdup(subdata->filename) : 0; | |
189 | |
190 for (i = 0; i < subdata->sub_num; ++i) { | |
191 int eid = ass_process_subtitle(track, subdata->subtitles + i); | |
192 if (eid < 0) | |
193 continue; | |
194 if (!subdata->sub_uses_time) { | |
195 track->events[eid].Start *= 100. / fps; | |
196 track->events[eid].Duration *= 100. / fps; | |
197 } | |
198 } | |
199 return track; | |
200 } | |
201 | |
202 ASS_Track* ass_read_stream(ASS_Library* library, const char *fname, char *charset) { | |
203 char *buf = NULL; | |
204 ASS_Track *track; | |
205 size_t sz = 0; | |
206 size_t buf_alloc = 0; | |
207 stream_t *fd; | |
208 | |
209 fd = open_stream(fname, NULL, NULL); | |
210 if (!fd) { | |
211 mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FopenFailed, fname); | |
212 return NULL; | |
213 } | |
214 if (fd->end_pos > STREAM_BUFFER_SIZE) | |
215 /* read entire file if size is known */ | |
216 buf_alloc = fd->end_pos; | |
217 for (;;) { | |
218 int i; | |
219 if (buf_alloc >= 100*1024*1024) { | |
220 mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_RefusingToLoadSubtitlesLargerThan100M, fname); | |
221 sz = 0; | |
222 break; | |
223 } | |
224 if (buf_alloc < sz + STREAM_BUFFER_SIZE) | |
225 buf_alloc += STREAM_BUFFER_SIZE; | |
226 buf = realloc(buf, buf_alloc + 1); | |
227 i = stream_read(fd, buf + sz, buf_alloc - sz); | |
228 if (i <= 0) break; | |
229 sz += i; | |
230 } | |
231 free_stream(fd); | |
232 if (!sz) { | |
233 free(buf); | |
234 return NULL; | |
235 } | |
236 buf[sz] = 0; | |
237 buf = realloc(buf, sz + 1); | |
238 track = ass_read_memory(library, buf, sz, charset); | |
239 if (track) { | |
240 free(track->name); | |
241 track->name = strdup(fname); | |
242 } | |
243 free(buf); | |
244 return track; | |
245 } | |
246 | |
247 void ass_configure(ASS_Renderer* priv, int w, int h, int unscaled) { | |
248 int hinting; | |
249 ass_set_frame_size(priv, w, h); | |
250 ass_set_margins(priv, ass_top_margin, ass_bottom_margin, 0, 0); | |
251 ass_set_use_margins(priv, ass_use_margins); | |
252 ass_set_font_scale(priv, ass_font_scale); | |
253 if (!unscaled && (ass_hinting & 4)) | |
254 hinting = 0; | |
255 else | |
256 hinting = ass_hinting & 3; | |
257 ass_set_hinting(priv, hinting); | |
258 ass_set_line_spacing(priv, ass_line_spacing); | |
259 } | |
260 | |
261 void ass_configure_fonts(ASS_Renderer* priv) { | |
262 char *dir, *path, *family; | |
263 dir = get_path("fonts"); | |
264 if (font_fontconfig < 0 && sub_font_name) path = strdup(sub_font_name); | |
265 else if (font_fontconfig < 0 && font_name) path = strdup(font_name); | |
266 else path = get_path("subfont.ttf"); | |
267 if (font_fontconfig >= 0 && sub_font_name) family = strdup(sub_font_name); | |
268 else if (font_fontconfig >= 0 && font_name) family = strdup(font_name); | |
269 else family = 0; | |
270 | |
271 ass_set_fonts(priv, path, family, font_fontconfig, NULL, 1); | |
272 | |
273 free(dir); | |
274 free(path); | |
275 free(family); | |
276 } | |
277 | |
278 static void message_callback(int level, const char *format, va_list va, void *ctx) | |
279 { | |
280 int n; | |
281 char *str; | |
282 va_list dst; | |
283 | |
284 va_copy(dst, va); | |
285 n = vsnprintf(NULL, 0, format, va); | |
286 if (n > 0 && (str = malloc(n + 1))) { | |
287 vsnprintf(str, n + 1, format, dst); | |
288 mp_msg(MSGT_ASS, level, "[ass] %s\n", str); | |
289 free(str); | |
290 } | |
291 } | |
292 | |
293 ASS_Library* ass_init(void) { | |
294 ASS_Library* priv; | |
295 char* path = get_path("fonts"); | |
296 priv = ass_library_init(); | |
297 ass_set_message_cb(priv, message_callback, NULL); | |
298 ass_set_fonts_dir(priv, path); | |
299 ass_set_extract_fonts(priv, extract_embedded_fonts); | |
300 ass_set_style_overrides(priv, ass_force_style_list); | |
301 free(path); | |
302 return priv; | |
303 } | |
304 | |
305 int ass_force_reload = 0; // flag set if global ass-related settings were changed | |
306 | |
307 ASS_Image* ass_mp_render_frame(ASS_Renderer *priv, ASS_Track* track, long long now, int* detect_change) { | |
308 if (ass_force_reload) { | |
309 ass_set_margins(priv, ass_top_margin, ass_bottom_margin, 0, 0); | |
310 ass_set_use_margins(priv, ass_use_margins); | |
311 ass_set_font_scale(priv, ass_font_scale); | |
312 ass_force_reload = 0; | |
313 } | |
314 return ass_render_frame(priv, track, now, detect_change); | |
315 } |