FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/drawutils.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 338 394 85.8%
Functions: 21 21 100.0%
Branches: 212 264 80.3%

Line Branch Exec Source
1 /*
2 * Copyright 2011 Stefano Sabatini <stefano.sabatini-lala poste it>
3 * Copyright 2012 Nicolas George <nicolas.george normalesup org>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <string.h>
23
24 #include "libavutil/avassert.h"
25 #include "libavutil/avutil.h"
26 #include "libavutil/csp.h"
27 #include "libavutil/intreadwrite.h"
28 #include "libavutil/pixdesc.h"
29 #include "colorspace.h"
30 #include "drawutils.h"
31 #include "formats.h"
32
33 enum { RED = 0, GREEN, BLUE, ALPHA };
34
35 845 static int fill_map(const AVPixFmtDescriptor *desc, uint8_t *map)
36 {
37
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 845 times.
845 if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL |
38 AV_PIX_FMT_FLAG_BAYER | AV_PIX_FMT_FLAG_XYZ | AV_PIX_FMT_FLAG_PAL))
39 return AVERROR(EINVAL);
40
3/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 815 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 845 times.
845 av_assert0(desc->nb_components == 3 + !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA));
41
2/2
✓ Branch 0 taken 614 times.
✓ Branch 1 taken 231 times.
845 if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) {
42 614 map[RED] = desc->comp[0].plane;
43 614 map[GREEN] = desc->comp[1].plane;
44 614 map[BLUE] = desc->comp[2].plane;
45
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 602 times.
614 map[ALPHA] = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? desc->comp[3].plane : 3;
46 } else {
47 231 int had0 = 0;
48 231 unsigned depthb = 0;
49 unsigned i;
50
2/2
✓ Branch 0 taken 706 times.
✓ Branch 1 taken 228 times.
934 for (i = 0; i < desc->nb_components; i++) {
51 /* all components must have same depth in bytes */
52 706 unsigned db = (desc->comp[i].depth + 7) / 8;
53 706 unsigned pos = desc->comp[i].offset / db;
54
3/4
✓ Branch 0 taken 475 times.
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 475 times.
706 if (depthb && (depthb != db))
55 return AVERROR(ENOSYS);
56
57
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 703 times.
706 if (desc->comp[i].offset % db)
58 3 return AVERROR(ENOSYS);
59
60 703 had0 |= pos == 0;
61 703 map[i] = pos;
62 703 depthb = db;
63 }
64
65
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 18 times.
228 if (desc->nb_components == 3)
66
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 map[ALPHA] = had0 ? 3 : 0;
67 }
68
69
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 842 times.
842 av_assert0(map[RED] != map[GREEN]);
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 842 times.
842 av_assert0(map[GREEN] != map[BLUE]);
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 842 times.
842 av_assert0(map[BLUE] != map[RED]);
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 842 times.
842 av_assert0(map[RED] != map[ALPHA]);
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 842 times.
842 av_assert0(map[GREEN] != map[ALPHA]);
74
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 842 times.
842 av_assert0(map[BLUE] != map[ALPHA]);
75
76 842 return 0;
77 }
78
79 589 int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
80 {
81 589 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
82
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 542 times.
589 if (!(desc->flags & AV_PIX_FMT_FLAG_RGB))
83 47 return AVERROR(EINVAL);
84 542 return fill_map(desc, rgba_map);
85 }
86
87 303 int ff_fill_ayuv_map(uint8_t *ayuv_map, enum AVPixelFormat pix_fmt)
88 {
89 303 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
90
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 303 times.
303 if (desc->flags & AV_PIX_FMT_FLAG_RGB)
91 return AVERROR(EINVAL);
92 303 return fill_map(desc, ayuv_map);
93 }
94
95 40318 int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSpace csp,
96 enum AVColorRange range, unsigned flags)
97 {
98 40318 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
99 40318 const AVLumaCoefficients *luma = NULL;
100 const AVComponentDescriptor *c;
101 40318 unsigned i, nb_planes = 0;
102 40318 int pixelstep[MAX_PLANES] = { 0 };
103 40318 int depthb = 0;
104
105
2/4
✓ Branch 0 taken 40318 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 40318 times.
40318 if (!desc || !desc->name)
106 return AVERROR(EINVAL);
107
2/2
✓ Branch 0 taken 14355 times.
✓ Branch 1 taken 25963 times.
40318 if (desc->flags & AV_PIX_FMT_FLAG_BE)
108 14355 return AVERROR(ENOSYS);
109
2/2
✓ Branch 0 taken 5775 times.
✓ Branch 1 taken 20188 times.
25963 if (desc->flags & ~(AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA))
110 5775 return AVERROR(ENOSYS);
111
2/2
✓ Branch 0 taken 20141 times.
✓ Branch 1 taken 47 times.
20188 if (csp == AVCOL_SPC_UNSPECIFIED)
112
2/2
✓ Branch 0 taken 6435 times.
✓ Branch 1 taken 13706 times.
20141 csp = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? AVCOL_SPC_RGB : AVCOL_SPC_SMPTE170M;
113
3/4
✓ Branch 0 taken 13706 times.
✓ Branch 1 taken 6482 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13706 times.
20188 if (!(desc->flags & AV_PIX_FMT_FLAG_RGB) && !(luma = av_csp_luma_coeffs_from_avcsp(csp)))
114 return AVERROR(EINVAL);
115
2/2
✓ Branch 0 taken 20013 times.
✓ Branch 1 taken 175 times.
20188 if (range == AVCOL_RANGE_UNSPECIFIED)
116
4/4
✓ Branch 0 taken 19683 times.
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 19518 times.
✓ Branch 3 taken 165 times.
39861 range = (format == AV_PIX_FMT_YUVJ420P || format == AV_PIX_FMT_YUVJ422P ||
117
4/4
✓ Branch 0 taken 19353 times.
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 19188 times.
✓ Branch 3 taken 165 times.
19518 format == AV_PIX_FMT_YUVJ444P || format == AV_PIX_FMT_YUVJ411P ||
118
2/2
✓ Branch 0 taken 6435 times.
✓ Branch 1 taken 12753 times.
19188 format == AV_PIX_FMT_YUVJ440P || csp == AVCOL_SPC_RGB)
119
2/2
✓ Branch 0 taken 19848 times.
✓ Branch 1 taken 165 times.
39861 ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
120
3/4
✓ Branch 0 taken 12860 times.
✓ Branch 1 taken 7328 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12860 times.
20188 if (range != AVCOL_RANGE_JPEG && range != AVCOL_RANGE_MPEG)
121 return AVERROR(EINVAL);
122
2/2
✓ Branch 0 taken 54664 times.
✓ Branch 1 taken 15568 times.
70232 for (i = 0; i < desc->nb_components; i++) {
123 int db;
124 54664 c = &desc->comp[i];
125 /* for now, only 8-16 bits formats */
126
4/4
✓ Branch 0 taken 53014 times.
✓ Branch 1 taken 1650 times.
✓ Branch 2 taken 330 times.
✓ Branch 3 taken 52684 times.
54664 if (c->depth < 8 || c->depth > 16)
127 1980 return AVERROR(ENOSYS);
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52684 times.
52684 if (c->plane >= MAX_PLANES)
129 return AVERROR(ENOSYS);
130 /* data must either be in the high or low bits, never middle */
131
4/4
✓ Branch 0 taken 4473 times.
✓ Branch 1 taken 48211 times.
✓ Branch 2 taken 660 times.
✓ Branch 3 taken 3813 times.
52684 if (c->shift && ((c->shift + c->depth) & 0x7))
132 660 return AVERROR(ENOSYS);
133 /* mixed >8 and <=8 depth */
134 52024 db = (c->depth + 7) / 8;
135
3/4
✓ Branch 0 taken 34311 times.
✓ Branch 1 taken 17713 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 34311 times.
52024 if (depthb && (depthb != db))
136 return AVERROR(ENOSYS);
137 52024 depthb = db;
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52024 times.
52024 if (db * (c->offset + 1) > 16)
139 return AVERROR(ENOSYS);
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52024 times.
52024 if (c->offset % db)
141 return AVERROR(ENOSYS);
142 /* strange interleaving */
143
2/2
✓ Branch 0 taken 10830 times.
✓ Branch 1 taken 41194 times.
52024 if (pixelstep[c->plane] != 0 &&
144
2/2
✓ Branch 0 taken 1155 times.
✓ Branch 1 taken 9675 times.
10830 pixelstep[c->plane] != c->step)
145 1155 return AVERROR(ENOSYS);
146 50869 pixelstep[c->plane] = c->step;
147
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 50044 times.
50869 if (pixelstep[c->plane] >= 8)
148 825 return AVERROR(ENOSYS);
149 50044 nb_planes = FFMAX(nb_planes, c->plane + 1);
150 }
151 15568 memset(draw, 0, sizeof(*draw));
152 15568 draw->desc = desc;
153 15568 draw->format = format;
154 15568 draw->nb_planes = nb_planes;
155 15568 draw->range = range;
156 15568 draw->csp = csp;
157 15568 draw->flags = flags;
158
2/2
✓ Branch 0 taken 11726 times.
✓ Branch 1 taken 3842 times.
15568 if (luma)
159 11726 ff_fill_rgb2yuv_table(luma, draw->rgb2yuv);
160 15568 memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep));
161 15568 draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w;
162 15568 draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h;
163 15568 return 0;
164 }
165
166 40095 int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
167 {
168 40095 return ff_draw_init2(draw, format, AVCOL_SPC_UNSPECIFIED, AVCOL_RANGE_UNSPECIFIED, flags);
169 }
170
171 209610 void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
172 {
173 unsigned i;
174 double yuvad[4];
175 double rgbad[4];
176 209610 const AVPixFmtDescriptor *desc = draw->desc;
177
178
1/2
✓ Branch 0 taken 209610 times.
✗ Branch 1 not taken.
209610 if (rgba != color->rgba)
179 209610 memcpy(color->rgba, rgba, sizeof(color->rgba));
180
181 209610 memset(color->comp, 0, sizeof(color->comp));
182
183
2/2
✓ Branch 0 taken 838440 times.
✓ Branch 1 taken 209610 times.
1048050 for (int i = 0; i < 4; i++)
184 838440 rgbad[i] = color->rgba[i] / 255.;
185
186
2/2
✓ Branch 0 taken 54599 times.
✓ Branch 1 taken 155011 times.
209610 if (draw->desc->flags & AV_PIX_FMT_FLAG_RGB)
187 54599 memcpy(yuvad, rgbad, sizeof(double) * 3);
188 else
189 155011 ff_matrix_mul_3x3_vec(yuvad, rgbad, draw->rgb2yuv);
190
191 209610 yuvad[3] = rgbad[3];
192
193
2/2
✓ Branch 0 taken 628830 times.
✓ Branch 1 taken 209610 times.
838440 for (int i = 0; i < 3; i++) {
194
4/4
✓ Branch 0 taken 465033 times.
✓ Branch 1 taken 163797 times.
✓ Branch 2 taken 310022 times.
✓ Branch 3 taken 155011 times.
628830 int chroma = (!(draw->desc->flags & AV_PIX_FMT_FLAG_RGB) && i > 0);
195
2/2
✓ Branch 0 taken 464970 times.
✓ Branch 1 taken 163860 times.
628830 if (draw->range == AVCOL_RANGE_MPEG) {
196
2/2
✓ Branch 0 taken 309980 times.
✓ Branch 1 taken 154990 times.
464970 yuvad[i] *= (chroma ? 224. : 219.) / 255.;
197
2/2
✓ Branch 0 taken 309980 times.
✓ Branch 1 taken 154990 times.
464970 yuvad[i] += (chroma ? 128. : 16.) / 255.;
198
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 163818 times.
163860 } else if (chroma) {
199 42 yuvad[i] += 0.5;
200 }
201 }
202
203 // Ensure we place the alpha appropriately for gray formats
204
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 209600 times.
209610 if (desc->nb_components <= 2)
205 10 yuvad[1] = yuvad[3];
206
207
2/2
✓ Branch 0 taken 654841 times.
✓ Branch 1 taken 209610 times.
864451 for (i = 0; i < desc->nb_components; i++) {
208 654841 unsigned val = yuvad[i] * ((1 << (draw->desc->comp[i].depth + draw->desc->comp[i].shift)) - 1) + 0.5;
209
2/2
✓ Branch 0 taken 59662 times.
✓ Branch 1 taken 595179 times.
654841 if (desc->comp[i].depth > 8)
210 59662 color->comp[desc->comp[i].plane].u16[desc->comp[i].offset / 2] = val;
211 else
212 595179 color->comp[desc->comp[i].plane].u8[desc->comp[i].offset] = val;
213 }
214 209610 }
215
216 607542 static uint8_t *pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[],
217 int plane, int x, int y)
218 {
219 607542 return data[plane] +
220 1215084 (y >> draw->vsub[plane]) * linesize[plane] +
221 607542 (x >> draw->hsub[plane]) * draw->pixelstep[plane];
222 }
223
224 37 void ff_copy_rectangle2(FFDrawContext *draw,
225 uint8_t *dst[], int dst_linesize[],
226 uint8_t *src[], int src_linesize[],
227 int dst_x, int dst_y, int src_x, int src_y,
228 int w, int h)
229 {
230 int plane, y, wp, hp;
231 uint8_t *p, *q;
232
233
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 37 times.
148 for (plane = 0; plane < draw->nb_planes; plane++) {
234 111 p = pointer_at(draw, src, src_linesize, plane, src_x, src_y);
235 111 q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
236 111 wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]) * draw->pixelstep[plane];
237 111 hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
238
2/2
✓ Branch 0 taken 21312 times.
✓ Branch 1 taken 111 times.
21423 for (y = 0; y < hp; y++) {
239 21312 memcpy(q, p, wp);
240 21312 p += src_linesize[plane];
241 21312 q += dst_linesize[plane];
242 }
243 }
244 37 }
245
246 211267 void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color,
247 uint8_t *dst[], int dst_linesize[],
248 int dst_x, int dst_y, int w, int h)
249 {
250 int plane, x, y, wp, hp;
251 uint8_t *p0, *p;
252 211267 FFDrawColor color_tmp = *color;
253
254
2/2
✓ Branch 0 taken 525400 times.
✓ Branch 1 taken 211267 times.
736667 for (plane = 0; plane < draw->nb_planes; plane++) {
255 525400 p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
256 525400 wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]);
257 525400 hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 525400 times.
525400 if (!hp)
259 return;
260 525400 p = p0;
261
262 if (HAVE_BIGENDIAN && draw->desc->comp[0].depth > 8) {
263 for (x = 0; 2*x < draw->pixelstep[plane]; x++)
264 color_tmp.comp[plane].u16[x] = av_bswap16(color_tmp.comp[plane].u16[x]);
265 }
266
267 /* copy first line from color */
268
2/2
✓ Branch 0 taken 2013673 times.
✓ Branch 1 taken 525400 times.
2539073 for (x = 0; x < wp; x++) {
269 2013673 memcpy(p, color_tmp.comp[plane].u8, draw->pixelstep[plane]);
270 2013673 p += draw->pixelstep[plane];
271 }
272 525400 wp *= draw->pixelstep[plane];
273 /* copy next lines from first line */
274 525400 p = p0 + dst_linesize[plane];
275
2/2
✓ Branch 0 taken 9008101 times.
✓ Branch 1 taken 525400 times.
9533501 for (y = 1; y < hp; y++) {
276 9008101 memcpy(p, p0, wp);
277 9008101 p += dst_linesize[plane];
278 }
279 }
280 }
281
282 /**
283 * Clip interval [x; x+w[ within [0; wmax[.
284 * The resulting w may be negative if the final interval is empty.
285 * dx, if not null, return the difference between in and out value of x.
286 */
287 61560 static void clip_interval(int wmax, int *x, int *w, int *dx)
288 {
289
2/2
✓ Branch 0 taken 59648 times.
✓ Branch 1 taken 1912 times.
61560 if (dx)
290 59648 *dx = 0;
291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61560 times.
61560 if (*x < 0) {
292 if (dx)
293 *dx = -*x;
294 *w += *x;
295 *x = 0;
296 }
297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61560 times.
61560 if (*x + *w > wmax)
298 *w = wmax - *x;
299 61560 }
300
301 /**
302 * Decompose w pixels starting at x
303 * into start + (w starting at x) + end
304 * with x and w aligned on multiples of 1<<sub.
305 */
306 163840 static void subsampling_bounds(int sub, int *x, int *w, int *start, int *end)
307 {
308 163840 int mask = (1 << sub) - 1;
309
310 163840 *start = (-*x) & mask;
311 163840 *x += *start;
312 163840 *start = FFMIN(*start, *w);
313 163840 *w -= *start;
314 163840 *end = *w & mask;
315 163840 *w >>= sub;
316 163840 }
317
318 /* If alpha is in the [ 0 ; 0x1010101 ] range,
319 then alpha * value is in the [ 0 ; 0xFFFFFFFF ] range,
320 and >> 24 gives a correct rounding. */
321 69660 static void blend_line(uint8_t *dst, unsigned src, unsigned alpha,
322 int dx, int w, unsigned hsub, int left, int right)
323 {
324 69660 unsigned asrc = alpha * src;
325 69660 unsigned tau = 0x1010101 - alpha;
326 int x;
327
328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69660 times.
69660 if (left) {
329 unsigned suba = (left * alpha) >> hsub;
330 *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
331 dst += dx;
332 }
333
2/2
✓ Branch 0 taken 5819400 times.
✓ Branch 1 taken 69660 times.
5889060 for (x = 0; x < w; x++) {
334 5819400 *dst = (*dst * tau + asrc) >> 24;
335 5819400 dst += dx;
336 }
337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69660 times.
69660 if (right) {
338 unsigned suba = (right * alpha) >> hsub;
339 *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
340 }
341 69660 }
342
343 11880 static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha,
344 int dx, int w, unsigned hsub, int left, int right)
345 {
346 11880 unsigned asrc = alpha * src;
347 11880 unsigned tau = 0x10001 - alpha;
348 int x;
349
350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11880 times.
11880 if (left) {
351 unsigned suba = (left * alpha) >> hsub;
352 uint16_t value = AV_RL16(dst);
353 AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
354 dst += dx;
355 }
356
2/2
✓ Branch 0 taken 792000 times.
✓ Branch 1 taken 11880 times.
803880 for (x = 0; x < w; x++) {
357 792000 uint16_t value = AV_RL16(dst);
358 792000 AV_WL16(dst, (value * tau + asrc) >> 16);
359 792000 dst += dx;
360 }
361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11880 times.
11880 if (right) {
362 unsigned suba = (right * alpha) >> hsub;
363 uint16_t value = AV_RL16(dst);
364 AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
365 }
366 11880 }
367
368 956 void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
369 uint8_t *dst[], int dst_linesize[],
370 int dst_w, int dst_h,
371 int x0, int y0, int w, int h)
372 {
373 unsigned alpha, nb_planes, nb_comp, plane, comp;
374 int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y;
375 uint8_t *p0, *p;
376
377 1912 nb_comp = draw->desc->nb_components -
378
3/4
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 885 times.
✓ Branch 2 taken 71 times.
✗ Branch 3 not taken.
956 !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
379
380 /* TODO optimize if alpha = 0xFF */
381 956 clip_interval(dst_w, &x0, &w, NULL);
382 956 clip_interval(dst_h, &y0, &h, NULL);
383
3/6
✓ Branch 0 taken 956 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 956 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 956 times.
956 if (w <= 0 || h <= 0 || !color->rgba[3])
384 return;
385
2/2
✓ Branch 0 taken 846 times.
✓ Branch 1 taken 110 times.
956 if (draw->desc->comp[0].depth <= 8) {
386 /* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */
387 846 alpha = 0x10203 * color->rgba[3] + 0x2;
388 } else {
389 /* 0x101 * alpha is in the [ 2 ; 0x1001] range */
390 110 alpha = 0x101 * color->rgba[3] + 0x2;
391 }
392
3/4
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 885 times.
✓ Branch 2 taken 71 times.
✗ Branch 3 not taken.
956 nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
393 956 nb_planes += !nb_planes;
394
2/2
✓ Branch 0 taken 2556 times.
✓ Branch 1 taken 956 times.
3512 for (plane = 0; plane < nb_planes; plane++) {
395 2556 p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
396 2556 w_sub = w;
397 2556 h_sub = h;
398 2556 x_sub = x0;
399 2556 y_sub = y0;
400 2556 subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
401 2556 subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
402
2/2
✓ Branch 0 taken 7668 times.
✓ Branch 1 taken 2556 times.
10224 for (comp = 0; comp < nb_comp; comp++) {
403 7668 const int depth = draw->desc->comp[comp].depth;
404 7668 const int offset = draw->desc->comp[comp].offset;
405 7668 const int index = offset / ((depth + 7) / 8);
406
407
2/2
✓ Branch 0 taken 4800 times.
✓ Branch 1 taken 2868 times.
7668 if (draw->desc->comp[comp].plane != plane)
408 4800 continue;
409 2868 p = p0 + offset;
410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2868 times.
2868 if (top) {
411 if (depth <= 8) {
412 blend_line(p, color->comp[plane].u8[index], alpha >> 1,
413 draw->pixelstep[plane], w_sub,
414 draw->hsub[plane], left, right);
415 } else {
416 blend_line16(p, color->comp[plane].u16[index], alpha >> 1,
417 draw->pixelstep[plane], w_sub,
418 draw->hsub[plane], left, right);
419 }
420 p += dst_linesize[plane];
421 }
422
2/2
✓ Branch 0 taken 2538 times.
✓ Branch 1 taken 330 times.
2868 if (depth <= 8) {
423
2/2
✓ Branch 0 taken 69660 times.
✓ Branch 1 taken 2538 times.
72198 for (y = 0; y < h_sub; y++) {
424 69660 blend_line(p, color->comp[plane].u8[index], alpha,
425 draw->pixelstep[plane], w_sub,
426 69660 draw->hsub[plane], left, right);
427 69660 p += dst_linesize[plane];
428 }
429 } else {
430
2/2
✓ Branch 0 taken 11880 times.
✓ Branch 1 taken 330 times.
12210 for (y = 0; y < h_sub; y++) {
431 11880 blend_line16(p, color->comp[plane].u16[index], alpha,
432 draw->pixelstep[plane], w_sub,
433 11880 draw->hsub[plane], left, right);
434 11880 p += dst_linesize[plane];
435 }
436 }
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2868 times.
2868 if (bottom) {
438 if (depth <= 8) {
439 blend_line(p, color->comp[plane].u8[index], alpha >> 1,
440 draw->pixelstep[plane], w_sub,
441 draw->hsub[plane], left, right);
442 } else {
443 blend_line16(p, color->comp[plane].u16[index], alpha >> 1,
444 draw->pixelstep[plane], w_sub,
445 draw->hsub[plane], left, right);
446 }
447 }
448 }
449 }
450 }
451
452 1070080 static void blend_pixel16(uint8_t *dst, unsigned src, unsigned alpha,
453 const uint8_t *mask, int mask_linesize, int l2depth,
454 unsigned w, unsigned h, unsigned shift, unsigned xm0)
455 {
456 1070080 unsigned xm, x, y, t = 0;
457 1070080 unsigned xmshf = 3 - l2depth;
458 1070080 unsigned xmmod = 7 >> l2depth;
459 1070080 unsigned mbits = (1 << (1 << l2depth)) - 1;
460 1070080 unsigned mmult = 255 / mbits;
461 1070080 uint16_t value = AV_RL16(dst);
462
463
2/2
✓ Branch 0 taken 1070080 times.
✓ Branch 1 taken 1070080 times.
2140160 for (y = 0; y < h; y++) {
464 1070080 xm = xm0;
465
2/2
✓ Branch 0 taken 1605120 times.
✓ Branch 1 taken 1070080 times.
2675200 for (x = 0; x < w; x++) {
466 1605120 t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
467 1605120 * mmult;
468 1605120 xm++;
469 }
470 1070080 mask += mask_linesize;
471 }
472 1070080 alpha = (t >> shift) * alpha;
473 1070080 AV_WL16(dst, ((0x10001 - alpha) * value + alpha * src) >> 16);
474 1070080 }
475
476 8018080 static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha,
477 const uint8_t *mask, int mask_linesize, int l2depth,
478 unsigned w, unsigned h, unsigned shift, unsigned xm0)
479 {
480 8018080 unsigned xm, x, y, t = 0;
481 8018080 unsigned xmshf = 3 - l2depth;
482 8018080 unsigned xmmod = 7 >> l2depth;
483 8018080 unsigned mbits = (1 << (1 << l2depth)) - 1;
484 8018080 unsigned mmult = 255 / mbits;
485
486
2/2
✓ Branch 0 taken 9481216 times.
✓ Branch 1 taken 8018080 times.
17499296 for (y = 0; y < h; y++) {
487 9481216 xm = xm0;
488
2/2
✓ Branch 0 taken 12489216 times.
✓ Branch 1 taken 9481216 times.
21970432 for (x = 0; x < w; x++) {
489 12489216 t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
490 12489216 * mmult;
491 12489216 xm++;
492 }
493 9481216 mask += mask_linesize;
494 }
495 8018080 alpha = (t >> shift) * alpha;
496 8018080 *dst = ((0x1010101 - alpha) * *dst + alpha * src) >> 24;
497 8018080 }
498
499 163680 static void blend_line_hv16(uint8_t *dst, int dst_delta,
500 unsigned src, unsigned alpha,
501 const uint8_t *mask, int mask_linesize, int l2depth, int w,
502 unsigned hsub, unsigned vsub,
503 int xm, int left, int right, int hband)
504 {
505 int x;
506
507
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 163680 times.
163680 if (left) {
508 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
509 left, hband, hsub + vsub, xm);
510 dst += dst_delta;
511 xm += left;
512 }
513
2/2
✓ Branch 0 taken 1070080 times.
✓ Branch 1 taken 163680 times.
1233760 for (x = 0; x < w; x++) {
514 1070080 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
515 1070080 1 << hsub, hband, hsub + vsub, xm);
516 1070080 dst += dst_delta;
517 1070080 xm += 1 << hsub;
518 }
519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 163680 times.
163680 if (right)
520 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
521 right, hband, hsub + vsub, xm);
522 163680 }
523
524 969204 static void blend_line_hv(uint8_t *dst, int dst_delta,
525 unsigned src, unsigned alpha,
526 const uint8_t *mask, int mask_linesize, int l2depth, int w,
527 unsigned hsub, unsigned vsub,
528 int xm, int left, int right, int hband)
529 {
530 int x;
531
532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 969204 times.
969204 if (left) {
533 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
534 left, hband, hsub + vsub, xm);
535 dst += dst_delta;
536 xm += left;
537 }
538
2/2
✓ Branch 0 taken 8018080 times.
✓ Branch 1 taken 969204 times.
8987284 for (x = 0; x < w; x++) {
539 8018080 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
540 8018080 1 << hsub, hband, hsub + vsub, xm);
541 8018080 dst += dst_delta;
542 8018080 xm += 1 << hsub;
543 }
544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 969204 times.
969204 if (right)
545 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
546 right, hband, hsub + vsub, xm);
547 969204 }
548
549 29824 void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color,
550 uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h,
551 const uint8_t *mask, int mask_linesize, int mask_w, int mask_h,
552 int l2depth, unsigned endianness, int x0, int y0)
553 {
554 unsigned alpha, nb_planes, nb_comp, plane, comp;
555 int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y;
556 uint8_t *p0, *p;
557 const uint8_t *m;
558
559 59648 nb_comp = draw->desc->nb_components -
560
3/4
✓ Branch 0 taken 2434 times.
✓ Branch 1 taken 27390 times.
✓ Branch 2 taken 2434 times.
✗ Branch 3 not taken.
29824 !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
561
562 29824 clip_interval(dst_w, &x0, &mask_w, &xm0);
563 29824 clip_interval(dst_h, &y0, &mask_h, &ym0);
564 29824 mask += ym0 * mask_linesize;
565
3/6
✓ Branch 0 taken 29824 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29824 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 29824 times.
29824 if (mask_w <= 0 || mask_h <= 0 || !color->rgba[3])
566 return;
567
2/2
✓ Branch 0 taken 26414 times.
✓ Branch 1 taken 3410 times.
29824 if (draw->desc->comp[0].depth <= 8) {
568 /* alpha is in the [ 0 ; 0x10203 ] range,
569 alpha * mask is in the [ 0 ; 0x1010101 - 4 ] range */
570 26414 alpha = (0x10307 * color->rgba[3] + 0x3) >> 8;
571 } else {
572 3410 alpha = (0x101 * color->rgba[3] + 0x2) >> 8;
573 }
574
3/4
✓ Branch 0 taken 2434 times.
✓ Branch 1 taken 27390 times.
✓ Branch 2 taken 2434 times.
✗ Branch 3 not taken.
29824 nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
575 29824 nb_planes += !nb_planes;
576
2/2
✓ Branch 0 taken 79364 times.
✓ Branch 1 taken 29824 times.
109188 for (plane = 0; plane < nb_planes; plane++) {
577 79364 p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
578 79364 w_sub = mask_w;
579 79364 h_sub = mask_h;
580 79364 x_sub = x0;
581 79364 y_sub = y0;
582 79364 subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
583 79364 subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
584
2/2
✓ Branch 0 taken 238092 times.
✓ Branch 1 taken 79364 times.
317456 for (comp = 0; comp < nb_comp; comp++) {
585 238092 const int depth = draw->desc->comp[comp].depth;
586 238092 const int offset = draw->desc->comp[comp].offset;
587 238092 const int index = offset / ((depth + 7) / 8);
588
589
2/2
✓ Branch 0 taken 148620 times.
✓ Branch 1 taken 89472 times.
238092 if (draw->desc->comp[comp].plane != plane)
590 148620 continue;
591 89472 p = p0 + offset;
592 89472 m = mask;
593
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 89292 times.
89472 if (top) {
594
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 if (depth <= 8) {
595 180 blend_line_hv(p, draw->pixelstep[plane],
596 180 color->comp[plane].u8[index], alpha,
597 m, mask_linesize, l2depth, w_sub,
598 180 draw->hsub[plane], draw->vsub[plane],
599 xm0, left, right, top);
600 } else {
601 blend_line_hv16(p, draw->pixelstep[plane],
602 color->comp[plane].u16[index], alpha,
603 m, mask_linesize, l2depth, w_sub,
604 draw->hsub[plane], draw->vsub[plane],
605 xm0, left, right, top);
606 }
607 180 p += dst_linesize[plane];
608 180 m += top * mask_linesize;
609 }
610
2/2
✓ Branch 0 taken 79242 times.
✓ Branch 1 taken 10230 times.
89472 if (depth <= 8) {
611
2/2
✓ Branch 0 taken 968844 times.
✓ Branch 1 taken 79242 times.
1048086 for (y = 0; y < h_sub; y++) {
612 968844 blend_line_hv(p, draw->pixelstep[plane],
613 968844 color->comp[plane].u8[index], alpha,
614 m, mask_linesize, l2depth, w_sub,
615 968844 draw->hsub[plane], draw->vsub[plane],
616 968844 xm0, left, right, 1 << draw->vsub[plane]);
617 968844 p += dst_linesize[plane];
618 968844 m += mask_linesize << draw->vsub[plane];
619 }
620 } else {
621
2/2
✓ Branch 0 taken 163680 times.
✓ Branch 1 taken 10230 times.
173910 for (y = 0; y < h_sub; y++) {
622 163680 blend_line_hv16(p, draw->pixelstep[plane],
623 163680 color->comp[plane].u16[index], alpha,
624 m, mask_linesize, l2depth, w_sub,
625 163680 draw->hsub[plane], draw->vsub[plane],
626 163680 xm0, left, right, 1 << draw->vsub[plane]);
627 163680 p += dst_linesize[plane];
628 163680 m += mask_linesize << draw->vsub[plane];
629 }
630 }
631
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 89292 times.
89472 if (bottom) {
632
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 if (depth <= 8) {
633 180 blend_line_hv(p, draw->pixelstep[plane],
634 180 color->comp[plane].u8[index], alpha,
635 m, mask_linesize, l2depth, w_sub,
636 180 draw->hsub[plane], draw->vsub[plane],
637 xm0, left, right, bottom);
638 } else {
639 blend_line_hv16(p, draw->pixelstep[plane],
640 color->comp[plane].u16[index], alpha,
641 m, mask_linesize, l2depth, w_sub,
642 draw->hsub[plane], draw->vsub[plane],
643 xm0, left, right, bottom);
644 }
645 }
646 }
647 }
648 }
649
650 230094 int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir,
651 int value)
652 {
653
2/2
✓ Branch 0 taken 206761 times.
✓ Branch 1 taken 23333 times.
230094 unsigned shift = sub_dir ? draw->vsub_max : draw->hsub_max;
654
655
2/2
✓ Branch 0 taken 105715 times.
✓ Branch 1 taken 124379 times.
230094 if (!shift)
656 105715 return value;
657
2/2
✓ Branch 0 taken 104106 times.
✓ Branch 1 taken 20273 times.
124379 if (round_dir >= 0)
658
2/2
✓ Branch 0 taken 3396 times.
✓ Branch 1 taken 100710 times.
104106 value += round_dir ? (1 << shift) - 1 : 1 << (shift - 1);
659 124379 return (value >> shift) << shift;
660 }
661
662 165 AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags)
663 {
664 enum AVPixelFormat i;
665 FFDrawContext draw;
666 165 AVFilterFormats *fmts = NULL;
667 int ret;
668
669
2/2
✓ Branch 1 taken 40095 times.
✓ Branch 2 taken 165 times.
40260 for (i = 0; av_pix_fmt_desc_get(i); i++)
670
3/4
✓ Branch 1 taken 15345 times.
✓ Branch 2 taken 24750 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15345 times.
55440 if (ff_draw_init(&draw, i, flags) >= 0 &&
671 15345 (ret = ff_add_format(&fmts, i)) < 0)
672 return NULL;
673 165 return fmts;
674 }
675