mp_msg: print messages to stdout, statusline to stderr
[mplayer.git] / sub / ass_mp.c
bloba9551914a85735969f208156d7a0e0a051264c16
1 /*
2 * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
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.
11 * MPlayer is distributed in the hope that it will be useful,
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.
16 * You should have received a copy of the GNU General Public License along
17 * with libass; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <inttypes.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdbool.h>
27 #include <ass/ass.h>
28 #include <ass/ass_types.h>
30 #include <libavutil/common.h>
32 #include "config.h"
33 #include "mp_msg.h"
34 #include "path.h"
35 #include "ass_mp.h"
36 #include "subreader.h"
37 #include "sub/sub.h"
38 #include "stream/stream.h"
39 #include "options.h"
41 #ifndef CONFIG_ICONV
42 static char *sub_cp = 0;
43 #endif
45 ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts)
47 ASS_Track *track = ass_new_track(library);
49 track->track_type = TRACK_TYPE_ASS;
50 track->Timer = 100.;
51 track->PlayResY = 288;
52 track->WrapStyle = 0;
54 if (opts->ass_styles_file)
55 ass_read_styles(track, opts->ass_styles_file, sub_cp);
57 if (track->n_styles == 0) {
58 track->Kerning = true;
59 int sid = ass_alloc_style(track);
60 track->default_style = sid;
61 ASS_Style *style = track->styles + sid;
62 style->Name = strdup("Default");
63 style->FontName = sub_font_name ? strdup(sub_font_name)
64 : font_name ? strdup(font_name) : strdup("Sans");
65 style->treat_fontname_as_pattern = 1;
67 double fs = track->PlayResY * text_font_scale_factor / 100.;
68 /* The font size is always proportional to video height only;
69 * real -subfont-autoscale behavior is not implemented.
70 * Apply a correction that corresponds to about 4:3 aspect ratio
71 * video to get a size somewhat closer to what non-libass rendering
72 * would produce with the same text_font_scale_factor
73 * and subtitle_autoscale.
75 if (subtitle_autoscale == 2)
76 fs *= 1.3;
77 else if (subtitle_autoscale == 3)
78 fs *= 1.7;
80 uint32_t c1 = 0xFFFFFF00;
81 uint32_t c2 = 0x00000000;
82 if (opts->ass_color)
83 c1 = strtoll(opts->ass_color, NULL, 16);
84 if (opts->ass_border_color)
85 c2 = strtoll(opts->ass_border_color, NULL, 16);
87 style->FontSize = fs;
88 style->PrimaryColour = c1;
89 style->SecondaryColour = c1;
90 style->OutlineColour = c2;
91 style->BackColour = 0x00000000;
92 style->BorderStyle = 1;
93 style->Alignment = 2;
94 style->Outline = fs / 16;
95 style->MarginL = 10;
96 style->MarginR = 10;
97 style->MarginV = 5;
98 style->ScaleX = 1.;
99 style->ScaleY = 1.;
102 ass_process_force_style(track);
103 return track;
106 static int check_duplicate_plaintext_event(ASS_Track *track)
108 int i;
109 ASS_Event *evt = track->events + track->n_events - 1;
111 for (i = 0; i < track->n_events - 1; ++i) // ignoring last event, it is the one we are comparing with
112 if (track->events[i].Start == evt->Start &&
113 track->events[i].Duration == evt->Duration &&
114 strcmp(track->events[i].Text, evt->Text) == 0)
115 return 1;
116 return 0;
120 * \brief Convert subtitle to ASS_Events for the given track
121 * \param track track
122 * \param sub subtitle to convert
123 * \return event id
124 * note: assumes that subtitle is _not_ fps-based; caller must manually correct
125 * Start and Duration in other case.
127 static int ass_process_subtitle(ASS_Track *track, subtitle *sub)
129 int eid;
130 ASS_Event *event;
131 int len = 0, j;
132 char *p;
133 char *end;
135 eid = ass_alloc_event(track);
136 event = track->events + eid;
138 event->Start = sub->start * 10;
139 event->Duration = (sub->end - sub->start) * 10;
140 event->Style = track->default_style;
142 for (j = 0; j < sub->lines; ++j)
143 len += sub->text[j] ? strlen(sub->text[j]) : 0;
145 len += 2 * sub->lines; // '\N', including the one after the last line
146 len += 6; // {\anX}
147 len += 1; // '\0'
149 event->Text = malloc(len);
150 end = event->Text + len;
151 p = event->Text;
153 if (sub->alignment)
154 p += snprintf(p, end - p, "{\\an%d}", sub->alignment);
156 for (j = 0; j < sub->lines; ++j)
157 p += snprintf(p, end - p, "%s\\N", sub->text[j]);
159 if (sub->lines > 0)
160 p -= 2; // remove last "\N"
161 *p = 0;
163 if (check_duplicate_plaintext_event(track)) {
164 ass_free_event(track, eid);
165 track->n_events--;
166 return -1;
169 mp_msg(MSGT_ASS, MSGL_V,
170 "plaintext event at %" PRId64 ", +%" PRId64 ": %s \n",
171 (int64_t) event->Start, (int64_t) event->Duration, event->Text);
173 return eid;
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
183 ASS_Track *mp_ass_read_subdata(ASS_Library *library, struct MPOpts *opts,
184 sub_data *subdata, double fps)
186 ASS_Track *track;
187 int i;
189 track = mp_ass_default_track(library, opts);
190 track->name = subdata->filename ? strdup(subdata->filename) : 0;
192 for (i = 0; i < subdata->sub_num; ++i) {
193 int eid = ass_process_subtitle(track, subdata->subtitles + i);
194 if (eid < 0)
195 continue;
196 if (!subdata->sub_uses_time) {
197 track->events[eid].Start *= 100. / fps;
198 track->events[eid].Duration *= 100. / fps;
201 return track;
204 ASS_Track *mp_ass_read_stream(ASS_Library *library, struct MPOpts *opts,
205 const char *fname, char *charset)
207 ASS_Track *track;
209 struct stream *s = open_stream(fname, opts, NULL);
210 if (!s)
211 // Stream code should have printed an error already
212 return NULL;
213 struct bstr content = stream_read_complete(s, NULL, 100000000, 1);
214 if (content.start == NULL)
215 mp_tmsg(MSGT_ASS, MSGL_ERR, "Refusing to load subtitle file "
216 "larger than 100 MB: %s\n", fname);
217 free_stream(s);
218 if (content.len == 0) {
219 talloc_free(content.start);
220 return NULL;
222 content.start[content.len] = 0;
223 track = ass_read_memory(library, content.start, content.len, charset);
224 if (track) {
225 free(track->name);
226 track->name = strdup(fname);
228 talloc_free(content.start);
229 return track;
232 void mp_ass_configure(ASS_Renderer *priv, struct MPOpts *opts,
233 struct mp_eosd_res *dim, bool unscaled)
235 int hinting;
236 ass_set_frame_size(priv, dim->w, dim->h);
237 ass_set_margins(priv, dim->mt, dim->mb, dim->ml, dim->mr);
238 ass_set_use_margins(priv, opts->ass_use_margins);
239 ass_set_font_scale(priv, opts->ass_font_scale);
240 if (!unscaled && (opts->ass_hinting & 4))
241 hinting = 0;
242 else
243 hinting = opts->ass_hinting & 3;
244 ass_set_hinting(priv, hinting);
245 ass_set_line_spacing(priv, opts->ass_line_spacing);
248 void mp_ass_configure_fonts(ASS_Renderer *priv)
250 char *dir, *path, *family;
251 dir = get_path("fonts");
252 path = get_path("subfont.ttf");
253 if (!mp_path_exists(path)) {
254 free(path);
255 path = NULL;
257 if (sub_font_name)
258 family = strdup(sub_font_name);
259 else if (font_name)
260 family = strdup(font_name);
261 else
262 family = 0;
264 ass_set_fonts(priv, path, family, 1, NULL, 1);
266 free(dir);
267 free(path);
268 free(family);
271 static void message_callback(int level, const char *format, va_list va, void *ctx)
273 mp_msg(MSGT_ASS, level, "[ass] ");
274 mp_msg_va(MSGT_ASS, level, format, va);
275 // libass messages lack trailing \n
276 mp_msg(MSGT_ASS, level, "\n");
279 ASS_Library *mp_ass_init(struct MPOpts *opts)
281 ASS_Library *priv;
282 char *path = get_path("fonts");
283 priv = ass_library_init();
284 ass_set_message_cb(priv, message_callback, NULL);
285 ass_set_fonts_dir(priv, path);
286 ass_set_extract_fonts(priv, opts->use_embedded_fonts);
287 free(path);
288 return priv;