Coverage Report

Created: 2026-09-28 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mpv/sub/ass_mp.c
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
}