/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 | } |