Coverage Report

Created: 2025-08-28 07:26

/src/mpv/sub/img_convert.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * This file is part of mpv.
3
 *
4
 * mpv is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * mpv is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with mpv.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
#include <string.h>
19
#include <assert.h>
20
#include <limits.h>
21
22
#include "mpv_talloc.h"
23
24
#include "common/common.h"
25
#include "img_convert.h"
26
#include "osd.h"
27
#include "video/img_format.h"
28
#include "video/mp_image.h"
29
#include "video/sws_utils.h"
30
31
void mp_blur_rgba_sub_bitmap(struct sub_bitmap *d, double gblur)
32
0
{
33
0
    struct mp_image *tmp1 = mp_image_alloc(IMGFMT_BGRA, d->w, d->h);
34
0
    MP_HANDLE_OOM(tmp1);
35
0
    {
36
0
        struct mp_image s = {0};
37
0
        mp_image_setfmt(&s, IMGFMT_BGRA);
38
0
        mp_image_set_size(&s, d->w, d->h);
39
0
        s.stride[0] = d->stride;
40
0
        s.planes[0] = d->bitmap;
41
42
0
        mp_image_copy(tmp1, &s);
43
44
0
        mp_image_sw_blur_scale(&s, tmp1, gblur);
45
0
    }
46
0
    talloc_free(tmp1);
47
0
}
48
49
bool mp_sub_bitmaps_bb(struct sub_bitmaps *imgs, struct mp_rect *out_bb)
50
0
{
51
0
    struct mp_rect bb = {INT_MAX, INT_MAX, INT_MIN, INT_MIN};
52
0
    for (int n = 0; n < imgs->num_parts; n++) {
53
0
        struct sub_bitmap *p = &imgs->parts[n];
54
0
        bb.x0 = MPMIN(bb.x0, p->x);
55
0
        bb.y0 = MPMIN(bb.y0, p->y);
56
0
        bb.x1 = MPMAX(bb.x1, p->x + p->dw);
57
0
        bb.y1 = MPMAX(bb.y1, p->y + p->dh);
58
0
    }
59
60
    // avoid degenerate bounding box if empty
61
0
    bb.x0 = MPMIN(bb.x0, bb.x1);
62
0
    bb.y0 = MPMIN(bb.y0, bb.y1);
63
64
0
    *out_bb = bb;
65
66
0
    return bb.x0 < bb.x1 && bb.y0 < bb.y1;
67
0
}
68
69
// Merge bounding rectangles if they're closer than the given amount of pixels.
70
// Avoids having too many rectangles due to spacing between letter.
71
0
#define MERGE_RC_PIXELS 50
72
73
static void remove_intersecting_rcs(struct mp_rect *list, int *count)
74
0
{
75
0
    int M = MERGE_RC_PIXELS;
76
0
    bool changed = true;
77
0
    while (changed) {
78
0
        changed = false;
79
0
        for (int a = 0; a < *count; a++) {
80
0
            struct mp_rect *rc_a = &list[a];
81
0
            for (int b = *count - 1; b > a; b--) {
82
0
                struct mp_rect *rc_b = &list[b];
83
0
                if (rc_a->x0 - M <= rc_b->x1 && rc_a->x1 + M >= rc_b->x0 &&
84
0
                    rc_a->y0 - M <= rc_b->y1 && rc_a->y1 + M >= rc_b->y0)
85
0
                {
86
0
                    mp_rect_union(rc_a, rc_b);
87
0
                    MP_TARRAY_REMOVE_AT(list, *count, b);
88
0
                    changed = true;
89
0
                }
90
0
            }
91
0
        }
92
0
    }
93
0
}
94
95
// Cluster the given subrectangles into a small numbers of bounding rectangles,
96
// and store them into list. E.g. when subtitles and toptitles are visible at
97
// the same time, there should be two bounding boxes, so that the video between
98
// the text is left untouched (need to resample less pixels -> faster).
99
// Returns number of rectangles added to out_rc_list (<= rc_list_count)
100
// NOTE: some callers assume that sub bitmaps are never split or partially
101
//       covered by returned rectangles.
102
int mp_get_sub_bb_list(struct sub_bitmaps *sbs, struct mp_rect *out_rc_list,
103
                       int rc_list_count)
104
0
{
105
0
    int M = MERGE_RC_PIXELS;
106
0
    int num_rc = 0;
107
0
    for (int n = 0; n < sbs->num_parts; n++) {
108
0
        struct sub_bitmap *sb = &sbs->parts[n];
109
0
        struct mp_rect bb = {sb->x,
110
0
                             sb->y,
111
0
                             sb->x + sb->dw,
112
0
                             sb->y + sb->dh};
113
0
        bool intersects = false;
114
0
        for (int r = 0; r < num_rc; r++) {
115
0
            struct mp_rect *rc = &out_rc_list[r];
116
0
            if ((bb.x0 - M <= rc->x1 && bb.x1 + M >= rc->x0 &&
117
0
                 bb.y0 - M <= rc->y1 && bb.y1 + M >= rc->y0) ||
118
0
                num_rc == rc_list_count)
119
0
            {
120
0
                mp_rect_union(rc, &bb);
121
0
                intersects = true;
122
0
                break;
123
0
            }
124
0
        }
125
0
        if (!intersects) {
126
0
            out_rc_list[num_rc++] = bb;
127
0
            remove_intersecting_rcs(out_rc_list, &num_rc);
128
0
        }
129
0
    }
130
0
    remove_intersecting_rcs(out_rc_list, &num_rc);
131
0
    return num_rc;
132
0
}