Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com> |
3 | | * |
4 | | * This file is part of mpv. |
5 | | * |
6 | | * mpv is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * mpv 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 Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with mpv. If not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include <string.h> |
21 | | #include <stdlib.h> |
22 | | #include <stdarg.h> |
23 | | #include <stdbool.h> |
24 | | #include <assert.h> |
25 | | #include <math.h> |
26 | | |
27 | | #include <ass/ass.h> |
28 | | #include <ass/ass_types.h> |
29 | | |
30 | | #include "common/common.h" |
31 | | #include "common/msg.h" |
32 | | #include "options/path.h" |
33 | | #include "ass_mp.h" |
34 | | #include "osd.h" |
35 | | #include "stream/stream.h" |
36 | | |
37 | | // res_y should be track->PlayResY |
38 | | // It determines scaling of font sizes and more. |
39 | | void mp_ass_set_style(ASS_Style *style, double res_y, |
40 | | const struct osd_style_opts *opts) |
41 | 374 | { |
42 | 374 | if (!style) |
43 | 0 | return; |
44 | | |
45 | 374 | if (opts->font) { |
46 | 374 | if (!style->FontName || strcmp(style->FontName, opts->font) != 0) { |
47 | 69 | free(style->FontName); |
48 | 69 | style->FontName = strdup(opts->font); |
49 | 69 | } |
50 | 374 | } |
51 | | |
52 | | // libass_font_size = FontSize * (window_height / res_y) |
53 | | // scale translates parameters from PlayResY=720 to res_y |
54 | 374 | double scale = res_y / 720.0; |
55 | | |
56 | 374 | style->FontSize = opts->font_size * scale; |
57 | 374 | style->PrimaryColour = MP_ASS_COLOR(opts->color); |
58 | 374 | style->SecondaryColour = style->PrimaryColour; |
59 | 374 | style->OutlineColour = MP_ASS_COLOR(opts->outline_color); |
60 | 374 | style->BackColour = MP_ASS_COLOR(opts->back_color); |
61 | 374 | style->BorderStyle = opts->border_style; |
62 | 374 | style->Outline = opts->outline_size * scale; |
63 | 374 | style->Shadow = opts->shadow_offset * scale; |
64 | 374 | style->Spacing = opts->spacing * scale; |
65 | 374 | style->MarginL = opts->margin_x * scale; |
66 | 374 | style->MarginR = style->MarginL; |
67 | 374 | style->MarginV = (opts->margin_y + opts->margin_y_offset) * scale; |
68 | 374 | style->ScaleX = 1.; |
69 | 374 | style->ScaleY = 1.; |
70 | 374 | style->Alignment = 1 + (opts->align_x + 1) + (opts->align_y + 2) % 3 * 4; |
71 | 374 | #ifdef ASS_JUSTIFY_LEFT |
72 | 374 | style->Justify = opts->justify; |
73 | 374 | #endif |
74 | 374 | style->Blur = opts->blur; |
75 | 374 | style->Bold = opts->bold; |
76 | 374 | style->Italic = opts->italic; |
77 | 374 | } |
78 | | |
79 | | void mp_ass_configure_fonts(ASS_Renderer *priv, struct osd_style_opts *opts, |
80 | | struct mpv_global *global, struct mp_log *log) |
81 | 1.70k | { |
82 | 1.70k | void *tmp = talloc_new(NULL); |
83 | 1.70k | char *default_font = mp_find_config_file(tmp, global, "subfont.ttf"); |
84 | 1.70k | char *config = mp_find_config_file(tmp, global, "fonts.conf"); |
85 | | |
86 | 1.70k | if (default_font && !mp_path_exists(default_font)) |
87 | 0 | default_font = NULL; |
88 | | |
89 | 1.70k | int font_provider = ASS_FONTPROVIDER_AUTODETECT; |
90 | 1.70k | if (opts->font_provider == 1) |
91 | 0 | font_provider = ASS_FONTPROVIDER_NONE; |
92 | 1.70k | if (opts->font_provider == 2) |
93 | 0 | font_provider = ASS_FONTPROVIDER_FONTCONFIG; |
94 | | |
95 | 1.70k | mp_verbose(log, "Setting up fonts...\n"); |
96 | 1.70k | ass_set_fonts(priv, default_font, opts->font, font_provider, config, 1); |
97 | 1.70k | mp_verbose(log, "Done.\n"); |
98 | | |
99 | 1.70k | talloc_free(tmp); |
100 | 1.70k | } |
101 | | |
102 | | static const int map_ass_level[] = { |
103 | | MSGL_ERR, // 0 "FATAL errors" |
104 | | MSGL_WARN, |
105 | | MSGL_INFO, |
106 | | MSGL_V, |
107 | | MSGL_V, |
108 | | MSGL_DEBUG, // 5 application recommended level |
109 | | MSGL_TRACE, |
110 | | MSGL_TRACE, // 7 "verbose DEBUG" |
111 | | }; |
112 | | |
113 | | MP_PRINTF_ATTRIBUTE(2, 0) |
114 | | static void message_callback(int level, const char *format, va_list va, void *ctx) |
115 | 24.2k | { |
116 | 24.2k | struct mp_log *log = ctx; |
117 | 24.2k | if (!log) |
118 | 0 | return; |
119 | 24.2k | level = map_ass_level[level]; |
120 | 24.2k | mp_msg_va(log, level, format, va); |
121 | | // libass messages lack trailing \n |
122 | 24.2k | mp_msg(log, level, "\n"); |
123 | 24.2k | } |
124 | | |
125 | | ASS_Library *mp_ass_init(struct mpv_global *global, |
126 | | struct osd_style_opts *opts, struct mp_log *log) |
127 | 1.70k | { |
128 | 1.70k | char *path = opts->fonts_dir && opts->fonts_dir[0] ? |
129 | 0 | mp_get_user_path(NULL, global, opts->fonts_dir) : |
130 | 1.70k | mp_find_config_file(NULL, global, "fonts"); |
131 | 1.70k | mp_dbg(log, "ASS library version: 0x%x (runtime 0x%x)\n", |
132 | 1.70k | (unsigned)LIBASS_VERSION, ass_library_version()); |
133 | 1.70k | ASS_Library *priv = ass_library_init(); |
134 | 1.70k | if (!priv) |
135 | 0 | abort(); |
136 | 1.70k | ass_set_message_cb(priv, message_callback, log); |
137 | 1.70k | if (path) |
138 | 0 | ass_set_fonts_dir(priv, path); |
139 | 1.70k | talloc_free(path); |
140 | 1.70k | return priv; |
141 | 1.70k | } |
142 | | |
143 | | void mp_ass_flush_old_events(ASS_Track *track, long long ts) |
144 | 0 | { |
145 | 0 | int n = 0; |
146 | 0 | for (; n < track->n_events; n++) { |
147 | 0 | if ((track->events[n].Start + track->events[n].Duration) >= ts) |
148 | 0 | break; |
149 | 0 | ass_free_event(track, n); |
150 | 0 | track->n_events--; |
151 | 0 | } |
152 | 0 | for (int i = 0; n > 0 && i < track->n_events; i++) { |
153 | 0 | track->events[i] = track->events[i+n]; |
154 | 0 | } |
155 | 0 | } |
156 | | |
157 | | // Set *out_rc to [x0, y0, x1, y1] of the graphical bounding box in script |
158 | | // coordinates. |
159 | | // Set it to [inf, inf, -inf, -inf] if empty. |
160 | | void mp_ass_get_bb(ASS_Image *image_list, ASS_Track *track, |
161 | | struct mp_osd_res *res, double *out_rc) |
162 | 0 | { |
163 | 0 | double rc[4] = {INFINITY, INFINITY, -INFINITY, -INFINITY}; |
164 | |
|
165 | 0 | for (ASS_Image *img = image_list; img; img = img->next) { |
166 | 0 | if (img->w == 0 || img->h == 0) |
167 | 0 | continue; |
168 | 0 | rc[0] = MPMIN(rc[0], img->dst_x); |
169 | 0 | rc[1] = MPMIN(rc[1], img->dst_y); |
170 | 0 | rc[2] = MPMAX(rc[2], img->dst_x + img->w); |
171 | 0 | rc[3] = MPMAX(rc[3], img->dst_y + img->h); |
172 | 0 | } |
173 | |
|
174 | 0 | double scale = track->PlayResY / (double)MPMAX(res->h, 1); |
175 | 0 | if (scale > 0) { |
176 | 0 | for (int i = 0; i < 4; i++) |
177 | 0 | out_rc[i] = rc[i] * scale; |
178 | 0 | } |
179 | 0 | } |