FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/drawutils.c
Date: 2025-04-25 22:50:00
Exec Total Coverage
Lines: 340 396 85.9%
Functions: 21 21 100.0%
Branches: 214 266 80.5%

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 1124 static int fill_map(const AVPixFmtDescriptor *desc, uint8_t *map)
36 {
37
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1124 times.
1124 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 34 times.
✓ Branch 1 taken 1090 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1124 times.
1124 av_assert0(desc->nb_components == 3 + !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA));
41
2/2
✓ Branch 0 taken 893 times.
✓ Branch 1 taken 231 times.
1124 if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) {
42
2/2
✓ Branch 2 taken 295 times.
✓ Branch 3 taken 598 times.
893 if (desc->nb_components != av_pix_fmt_count_planes(av_pix_fmt_desc_get_id(desc)))
43 295 return AVERROR(EINVAL);
44 598 map[RED] = desc->comp[0].plane;
45 598 map[GREEN] = desc->comp[1].plane;
46 598 map[BLUE] = desc->comp[2].plane;
47
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 582 times.
598 map[ALPHA] = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? desc->comp[3].plane : 3;
48 } else {
49 231 int had0 = 0;
50 231 unsigned depthb = 0;
51
2/2
✓ Branch 0 taken 706 times.
✓ Branch 1 taken 228 times.
934 for (unsigned i = 0; i < desc->nb_components; i++) {
52 /* all components must have same depth in bytes */
53 706 unsigned db = (desc->comp[i].depth + 7) / 8;
54 706 unsigned pos = desc->comp[i].offset / db;
55
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))
56 return AVERROR(ENOSYS);
57
58
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 703 times.
706 if (desc->comp[i].offset % db)
59 3 return AVERROR(ENOSYS);
60
61 703 had0 |= pos == 0;
62 703 map[i] = pos;
63 703 depthb = db;
64 }
65
66
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 18 times.
228 if (desc->nb_components == 3)
67
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 map[ALPHA] = had0 ? 3 : 0;
68 }
69
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 826 times.
826 av_assert0(map[RED] != map[GREEN]);
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 826 times.
826 av_assert0(map[GREEN] != map[BLUE]);
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 826 times.
826 av_assert0(map[BLUE] != map[RED]);
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 826 times.
826 av_assert0(map[RED] != map[ALPHA]);
74
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 826 times.
826 av_assert0(map[GREEN] != map[ALPHA]);
75
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 826 times.
826 av_assert0(map[BLUE] != map[ALPHA]);
76
77 826 return 0;
78 }
79
80 591 int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
81 {
82 591 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
83
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 544 times.
591 if (!(desc->flags & AV_PIX_FMT_FLAG_RGB))
84 47 return AVERROR(EINVAL);
85 544 return fill_map(desc, rgba_map);
86 }
87
88 580 int ff_fill_ayuv_map(uint8_t *ayuv_map, enum AVPixelFormat pix_fmt)
89 {
90 580 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 580 times.
580 if (desc->flags & AV_PIX_FMT_FLAG_RGB)
92 return AVERROR(EINVAL);
93 580 return fill_map(desc, ayuv_map);
94 }
95
96 43052 int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSpace csp,
97 enum AVColorRange range, unsigned flags)
98 {
99 43052 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
100 43052 const AVLumaCoefficients *luma = NULL;
101 const AVComponentDescriptor *c;
102 43052 unsigned nb_planes = 0;
103 43052 int pixelstep[MAX_PLANES] = { 0 };
104 43052 int depthb = 0;
105
106
2/4
✓ Branch 0 taken 43052 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 43052 times.
43052 if (!desc || !desc->name)
107 return AVERROR(EINVAL);
108
2/2
✓ Branch 0 taken 15604 times.
✓ Branch 1 taken 27448 times.
43052 if (desc->flags & AV_PIX_FMT_FLAG_BE)
109 15604 return AVERROR(ENOSYS);
110
2/2
✓ Branch 0 taken 6806 times.
✓ Branch 1 taken 20642 times.
27448 if (desc->flags & ~(AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA))
111 6806 return AVERROR(ENOSYS);
112
2/2
✓ Branch 0 taken 20595 times.
✓ Branch 1 taken 47 times.
20642 if (csp == AVCOL_SPC_UNSPECIFIED)
113
2/2
✓ Branch 0 taken 6640 times.
✓ Branch 1 taken 13955 times.
20595 csp = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? AVCOL_SPC_RGB : AVCOL_SPC_SMPTE170M;
114
3/4
✓ Branch 0 taken 13955 times.
✓ Branch 1 taken 6687 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13955 times.
20642 if (!(desc->flags & AV_PIX_FMT_FLAG_RGB) && !(luma = av_csp_luma_coeffs_from_avcsp(csp)))
115 return AVERROR(EINVAL);
116
2/2
✓ Branch 0 taken 20466 times.
✓ Branch 1 taken 176 times.
20642 if (range == AVCOL_RANGE_UNSPECIFIED)
117
4/4
✓ Branch 0 taken 20134 times.
✓ Branch 1 taken 166 times.
✓ Branch 2 taken 19968 times.
✓ Branch 3 taken 166 times.
40766 range = (format == AV_PIX_FMT_YUVJ420P || format == AV_PIX_FMT_YUVJ422P ||
118
4/4
✓ Branch 0 taken 19802 times.
✓ Branch 1 taken 166 times.
✓ Branch 2 taken 19636 times.
✓ Branch 3 taken 166 times.
19968 format == AV_PIX_FMT_YUVJ444P || format == AV_PIX_FMT_YUVJ411P ||
119
2/2
✓ Branch 0 taken 6640 times.
✓ Branch 1 taken 12996 times.
19636 format == AV_PIX_FMT_YUVJ440P || csp == AVCOL_SPC_RGB)
120
2/2
✓ Branch 0 taken 20300 times.
✓ Branch 1 taken 166 times.
40766 ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
121
3/4
✓ Branch 0 taken 13104 times.
✓ Branch 1 taken 7538 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13104 times.
20642 if (range != AVCOL_RANGE_JPEG && range != AVCOL_RANGE_MPEG)
122 return AVERROR(EINVAL);
123
2/2
✓ Branch 0 taken 55326 times.
✓ Branch 1 taken 15662 times.
70988 for (unsigned i = 0; i < desc->nb_components; i++) {
124 int db;
125 55326 c = &desc->comp[i];
126 /* for now, only 8-16 bits formats */
127
4/4
✓ Branch 0 taken 53666 times.
✓ Branch 1 taken 1660 times.
✓ Branch 2 taken 664 times.
✓ Branch 3 taken 53002 times.
55326 if (c->depth < 8 || c->depth > 16)
128 2324 return AVERROR(ENOSYS);
129
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53002 times.
53002 if (c->plane >= MAX_PLANES)
130 return AVERROR(ENOSYS);
131 /* data must either be in the high or low bits, never middle */
132
4/4
✓ Branch 0 taken 4500 times.
✓ Branch 1 taken 48502 times.
✓ Branch 2 taken 664 times.
✓ Branch 3 taken 3836 times.
53002 if (c->shift && ((c->shift + c->depth) & 0x7))
133 664 return AVERROR(ENOSYS);
134 /* mixed >8 and <=8 depth */
135 52338 db = (c->depth + 7) / 8;
136
3/4
✓ Branch 0 taken 34518 times.
✓ Branch 1 taken 17820 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 34518 times.
52338 if (depthb && (depthb != db))
137 return AVERROR(ENOSYS);
138 52338 depthb = db;
139
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52338 times.
52338 if (db * (c->offset + 1) > 16)
140 return AVERROR(ENOSYS);
141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52338 times.
52338 if (c->offset % db)
142 return AVERROR(ENOSYS);
143 /* strange interleaving */
144
2/2
✓ Branch 0 taken 10896 times.
✓ Branch 1 taken 41442 times.
52338 if (pixelstep[c->plane] != 0 &&
145
2/2
✓ Branch 0 taken 1162 times.
✓ Branch 1 taken 9734 times.
10896 pixelstep[c->plane] != c->step)
146 1162 return AVERROR(ENOSYS);
147 51176 pixelstep[c->plane] = c->step;
148
2/2
✓ Branch 0 taken 830 times.
✓ Branch 1 taken 50346 times.
51176 if (pixelstep[c->plane] >= 8)
149 830 return AVERROR(ENOSYS);
150 50346 nb_planes = FFMAX(nb_planes, c->plane + 1);
151 }
152 15662 memset(draw, 0, sizeof(*draw));
153 15662 draw->desc = desc;
154 15662 draw->format = format;
155 15662 draw->nb_planes = nb_planes;
156 15662 draw->range = range;
157 15662 draw->csp = csp;
158 15662 draw->flags = flags;
159
2/2
✓ Branch 0 taken 11797 times.
✓ Branch 1 taken 3865 times.
15662 if (luma)
160 11797 ff_fill_rgb2yuv_table(luma, draw->rgb2yuv);
161 15662 memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep));
162 15662 draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w;
163 15662 draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h;
164 15662 return 0;
165 }
166
167 42828 int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
168 {
169 42828 return ff_draw_init2(draw, format, AVCOL_SPC_UNSPECIFIED, AVCOL_RANGE_UNSPECIFIED, flags);
170 }
171
172 209611 void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
173 {
174 double yuvad[4];
175 double rgbad[4];
176 209611 const AVPixFmtDescriptor *desc = draw->desc;
177
178
1/2
✓ Branch 0 taken 209611 times.
✗ Branch 1 not taken.
209611 if (rgba != color->rgba)
179 209611 memcpy(color->rgba, rgba, sizeof(color->rgba));
180
181 209611 memset(color->comp, 0, sizeof(color->comp));
182
183
2/2
✓ Branch 0 taken 838444 times.
✓ Branch 1 taken 209611 times.
1048055 for (int i = 0; i < 4; i++)
184 838444 rgbad[i] = color->rgba[i] / 255.;
185
186
2/2
✓ Branch 0 taken 54599 times.
✓ Branch 1 taken 155012 times.
209611 if (draw->desc->flags & AV_PIX_FMT_FLAG_RGB)
187 54599 memcpy(yuvad, rgbad, sizeof(double) * 3);
188 else
189 155012 ff_matrix_mul_3x3_vec(yuvad, rgbad, draw->rgb2yuv);
190
191 209611 yuvad[3] = rgbad[3];
192
193
2/2
✓ Branch 0 taken 628833 times.
✓ Branch 1 taken 209611 times.
838444 for (int i = 0; i < 3; i++) {
194
4/4
✓ Branch 0 taken 465036 times.
✓ Branch 1 taken 163797 times.
✓ Branch 2 taken 310024 times.
✓ Branch 3 taken 155012 times.
628833 int chroma = (!(draw->desc->flags & AV_PIX_FMT_FLAG_RGB) && i > 0);
195
2/2
✓ Branch 0 taken 464973 times.
✓ Branch 1 taken 163860 times.
628833 if (draw->range == AVCOL_RANGE_MPEG) {
196
2/2
✓ Branch 0 taken 309982 times.
✓ Branch 1 taken 154991 times.
464973 yuvad[i] *= (chroma ? 224. : 219.) / 255.;
197
2/2
✓ Branch 0 taken 309982 times.
✓ Branch 1 taken 154991 times.
464973 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 209601 times.
209611 if (desc->nb_components <= 2)
205 10 yuvad[1] = yuvad[3];
206
207
2/2
✓ Branch 0 taken 654844 times.
✓ Branch 1 taken 209611 times.
864455 for (unsigned i = 0; i < desc->nb_components; i++) {
208 654844 unsigned val = yuvad[i] * ((1 << (draw->desc->comp[i].depth + draw->desc->comp[i].shift)) - 1) + 0.5;
209
2/2
✓ Branch 0 taken 59665 times.
✓ Branch 1 taken 595179 times.
654844 if (desc->comp[i].depth > 8)
210 59665 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 209611 }
215
216 607550 static uint8_t *pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[],
217 int plane, int x, int y)
218 {
219 607550 return data[plane] +
220 1215100 (y >> draw->vsub[plane]) * linesize[plane] +
221 607550 (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 wp, hp;
231 uint8_t *p, *q;
232
233
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 37 times.
148 for (int 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 (int 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 211271 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 wp, hp;
251 uint8_t *p0, *p;
252 211271 FFDrawColor color_tmp = *color;
253
254
2/2
✓ Branch 0 taken 525408 times.
✓ Branch 1 taken 211271 times.
736679 for (int plane = 0; plane < draw->nb_planes; plane++) {
255 525408 p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
256 525408 wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]);
257 525408 hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 525408 times.
525408 if (!hp)
259 return;
260 525408 p = p0;
261
262 if (HAVE_BIGENDIAN && draw->desc->comp[0].depth > 8) {
263 for (int 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 2015395 times.
✓ Branch 1 taken 525408 times.
2540803 for (int x = 0; x < wp; x++) {
269 2015395 memcpy(p, color_tmp.comp[plane].u8, draw->pixelstep[plane]);
270 2015395 p += draw->pixelstep[plane];
271 }
272 525408 wp *= draw->pixelstep[plane];
273 /* copy next lines from first line */
274 525408 p = p0 + dst_linesize[plane];
275
2/2
✓ Branch 0 taken 9009469 times.
✓ Branch 1 taken 525408 times.
9534877 for (int y = 1; y < hp; y++) {
276 9009469 memcpy(p, p0, wp);
277 9009469 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
327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69660 times.
69660 if (left) {
328 unsigned suba = (left * alpha) >> hsub;
329 *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
330 dst += dx;
331 }
332
2/2
✓ Branch 0 taken 5819400 times.
✓ Branch 1 taken 69660 times.
5889060 for (int x = 0; x < w; x++) {
333 5819400 *dst = (*dst * tau + asrc) >> 24;
334 5819400 dst += dx;
335 }
336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69660 times.
69660 if (right) {
337 unsigned suba = (right * alpha) >> hsub;
338 *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
339 }
340 69660 }
341
342 11880 static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha,
343 int dx, int w, unsigned hsub, int left, int right)
344 {
345 11880 unsigned asrc = alpha * src;
346 11880 unsigned tau = 0x10001 - alpha;
347
348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11880 times.
11880 if (left) {
349 unsigned suba = (left * alpha) >> hsub;
350 uint16_t value = AV_RL16(dst);
351 AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
352 dst += dx;
353 }
354
2/2
✓ Branch 0 taken 792000 times.
✓ Branch 1 taken 11880 times.
803880 for (int x = 0; x < w; x++) {
355 792000 uint16_t value = AV_RL16(dst);
356 792000 AV_WL16(dst, (value * tau + asrc) >> 16);
357 792000 dst += dx;
358 }
359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11880 times.
11880 if (right) {
360 unsigned suba = (right * alpha) >> hsub;
361 uint16_t value = AV_RL16(dst);
362 AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
363 }
364 11880 }
365
366 956 void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
367 uint8_t *dst[], int dst_linesize[],
368 int dst_w, int dst_h,
369 int x0, int y0, int w, int h)
370 {
371 unsigned alpha, nb_planes, nb_comp;
372 int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom;
373 uint8_t *p0, *p;
374
375 1912 nb_comp = draw->desc->nb_components -
376
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));
377
378 /* TODO optimize if alpha = 0xFF */
379 956 clip_interval(dst_w, &x0, &w, NULL);
380 956 clip_interval(dst_h, &y0, &h, NULL);
381
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])
382 return;
383
2/2
✓ Branch 0 taken 846 times.
✓ Branch 1 taken 110 times.
956 if (draw->desc->comp[0].depth <= 8) {
384 /* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */
385 846 alpha = 0x10203 * color->rgba[3] + 0x2;
386 } else {
387 /* 0x101 * alpha is in the [ 2 ; 0x1001] range */
388 110 alpha = 0x101 * color->rgba[3] + 0x2;
389 }
390
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));
391 956 nb_planes += !nb_planes;
392
2/2
✓ Branch 0 taken 2556 times.
✓ Branch 1 taken 956 times.
3512 for (unsigned plane = 0; plane < nb_planes; plane++) {
393 2556 p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
394 2556 w_sub = w;
395 2556 h_sub = h;
396 2556 x_sub = x0;
397 2556 y_sub = y0;
398 2556 subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
399 2556 subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
400
2/2
✓ Branch 0 taken 7668 times.
✓ Branch 1 taken 2556 times.
10224 for (unsigned comp = 0; comp < nb_comp; comp++) {
401 7668 const int depth = draw->desc->comp[comp].depth;
402 7668 const int offset = draw->desc->comp[comp].offset;
403 7668 const int index = offset / ((depth + 7) / 8);
404
405
2/2
✓ Branch 0 taken 4800 times.
✓ Branch 1 taken 2868 times.
7668 if (draw->desc->comp[comp].plane != plane)
406 4800 continue;
407 2868 p = p0 + offset;
408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2868 times.
2868 if (top) {
409 if (depth <= 8) {
410 blend_line(p, color->comp[plane].u8[index], alpha >> 1,
411 draw->pixelstep[plane], w_sub,
412 draw->hsub[plane], left, right);
413 } else {
414 blend_line16(p, color->comp[plane].u16[index], alpha >> 1,
415 draw->pixelstep[plane], w_sub,
416 draw->hsub[plane], left, right);
417 }
418 p += dst_linesize[plane];
419 }
420
2/2
✓ Branch 0 taken 2538 times.
✓ Branch 1 taken 330 times.
2868 if (depth <= 8) {
421
2/2
✓ Branch 0 taken 69660 times.
✓ Branch 1 taken 2538 times.
72198 for (int y = 0; y < h_sub; y++) {
422 69660 blend_line(p, color->comp[plane].u8[index], alpha,
423 draw->pixelstep[plane], w_sub,
424 69660 draw->hsub[plane], left, right);
425 69660 p += dst_linesize[plane];
426 }
427 } else {
428
2/2
✓ Branch 0 taken 11880 times.
✓ Branch 1 taken 330 times.
12210 for (int y = 0; y < h_sub; y++) {
429 11880 blend_line16(p, color->comp[plane].u16[index], alpha,
430 draw->pixelstep[plane], w_sub,
431 11880 draw->hsub[plane], left, right);
432 11880 p += dst_linesize[plane];
433 }
434 }
435
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2868 times.
2868 if (bottom) {
436 if (depth <= 8) {
437 blend_line(p, color->comp[plane].u8[index], alpha >> 1,
438 draw->pixelstep[plane], w_sub,
439 draw->hsub[plane], left, right);
440 } else {
441 blend_line16(p, color->comp[plane].u16[index], alpha >> 1,
442 draw->pixelstep[plane], w_sub,
443 draw->hsub[plane], left, right);
444 }
445 }
446 }
447 }
448 }
449
450 1070080 static void blend_pixel16(uint8_t *dst, unsigned src, unsigned alpha,
451 const uint8_t *mask, int mask_linesize, int l2depth,
452 unsigned w, unsigned h, unsigned shift, unsigned xm0)
453 {
454 1070080 unsigned t = 0;
455 1070080 unsigned xmshf = 3 - l2depth;
456 1070080 unsigned xmmod = 7 >> l2depth;
457 1070080 unsigned mbits = (1 << (1 << l2depth)) - 1;
458 1070080 unsigned mmult = 255 / mbits;
459 1070080 uint16_t value = AV_RL16(dst);
460
461
2/2
✓ Branch 0 taken 1070080 times.
✓ Branch 1 taken 1070080 times.
2140160 for (unsigned y = 0; y < h; y++) {
462 1070080 unsigned xm = xm0;
463
2/2
✓ Branch 0 taken 1605120 times.
✓ Branch 1 taken 1070080 times.
2675200 for (unsigned x = 0; x < w; x++) {
464 1605120 t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
465 1605120 * mmult;
466 1605120 xm++;
467 }
468 1070080 mask += mask_linesize;
469 }
470 1070080 alpha = (t >> shift) * alpha;
471 1070080 AV_WL16(dst, ((0x10001 - alpha) * value + alpha * src) >> 16);
472 1070080 }
473
474 8018080 static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha,
475 const uint8_t *mask, int mask_linesize, int l2depth,
476 unsigned w, unsigned h, unsigned shift, unsigned xm0)
477 {
478 8018080 unsigned t = 0;
479 8018080 unsigned xmshf = 3 - l2depth;
480 8018080 unsigned xmmod = 7 >> l2depth;
481 8018080 unsigned mbits = (1 << (1 << l2depth)) - 1;
482 8018080 unsigned mmult = 255 / mbits;
483
484
2/2
✓ Branch 0 taken 9481216 times.
✓ Branch 1 taken 8018080 times.
17499296 for (unsigned y = 0; y < h; y++) {
485 9481216 unsigned xm = xm0;
486
2/2
✓ Branch 0 taken 12489216 times.
✓ Branch 1 taken 9481216 times.
21970432 for (unsigned x = 0; x < w; x++) {
487 12489216 t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
488 12489216 * mmult;
489 12489216 xm++;
490 }
491 9481216 mask += mask_linesize;
492 }
493 8018080 alpha = (t >> shift) * alpha;
494 8018080 *dst = ((0x1010101 - alpha) * *dst + alpha * src) >> 24;
495 8018080 }
496
497 163680 static void blend_line_hv16(uint8_t *dst, int dst_delta,
498 unsigned src, unsigned alpha,
499 const uint8_t *mask, int mask_linesize, int l2depth, int w,
500 unsigned hsub, unsigned vsub,
501 int xm, int left, int right, int hband)
502 {
503
504
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 163680 times.
163680 if (left) {
505 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
506 left, hband, hsub + vsub, xm);
507 dst += dst_delta;
508 xm += left;
509 }
510
2/2
✓ Branch 0 taken 1070080 times.
✓ Branch 1 taken 163680 times.
1233760 for (int x = 0; x < w; x++) {
511 1070080 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
512 1070080 1 << hsub, hband, hsub + vsub, xm);
513 1070080 dst += dst_delta;
514 1070080 xm += 1 << hsub;
515 }
516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 163680 times.
163680 if (right)
517 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
518 right, hband, hsub + vsub, xm);
519 163680 }
520
521 969204 static void blend_line_hv(uint8_t *dst, int dst_delta,
522 unsigned src, unsigned alpha,
523 const uint8_t *mask, int mask_linesize, int l2depth, int w,
524 unsigned hsub, unsigned vsub,
525 int xm, int left, int right, int hband)
526 {
527
528
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 969204 times.
969204 if (left) {
529 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
530 left, hband, hsub + vsub, xm);
531 dst += dst_delta;
532 xm += left;
533 }
534
2/2
✓ Branch 0 taken 8018080 times.
✓ Branch 1 taken 969204 times.
8987284 for (int x = 0; x < w; x++) {
535 8018080 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
536 8018080 1 << hsub, hband, hsub + vsub, xm);
537 8018080 dst += dst_delta;
538 8018080 xm += 1 << hsub;
539 }
540
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 969204 times.
969204 if (right)
541 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
542 right, hband, hsub + vsub, xm);
543 969204 }
544
545 29824 void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color,
546 uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h,
547 const uint8_t *mask, int mask_linesize, int mask_w, int mask_h,
548 int l2depth, unsigned endianness, int x0, int y0)
549 {
550 unsigned alpha, nb_planes, nb_comp;
551 int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom;
552 uint8_t *p;
553 const uint8_t *m;
554
555 59648 nb_comp = draw->desc->nb_components -
556
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));
557
558 29824 clip_interval(dst_w, &x0, &mask_w, &xm0);
559 29824 clip_interval(dst_h, &y0, &mask_h, &ym0);
560 29824 mask += ym0 * mask_linesize;
561
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])
562 return;
563
2/2
✓ Branch 0 taken 26414 times.
✓ Branch 1 taken 3410 times.
29824 if (draw->desc->comp[0].depth <= 8) {
564 /* alpha is in the [ 0 ; 0x10203 ] range,
565 alpha * mask is in the [ 0 ; 0x1010101 - 4 ] range */
566 26414 alpha = (0x10307 * color->rgba[3] + 0x3) >> 8;
567 } else {
568 3410 alpha = (0x101 * color->rgba[3] + 0x2) >> 8;
569 }
570
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));
571 29824 nb_planes += !nb_planes;
572
2/2
✓ Branch 0 taken 79364 times.
✓ Branch 1 taken 29824 times.
109188 for (unsigned plane = 0; plane < nb_planes; plane++) {
573 79364 uint8_t *p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
574 79364 w_sub = mask_w;
575 79364 h_sub = mask_h;
576 79364 x_sub = x0;
577 79364 y_sub = y0;
578 79364 subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
579 79364 subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
580
2/2
✓ Branch 0 taken 238092 times.
✓ Branch 1 taken 79364 times.
317456 for (unsigned comp = 0; comp < nb_comp; comp++) {
581 238092 const int depth = draw->desc->comp[comp].depth;
582 238092 const int offset = draw->desc->comp[comp].offset;
583 238092 const int index = offset / ((depth + 7) / 8);
584
585
2/2
✓ Branch 0 taken 148620 times.
✓ Branch 1 taken 89472 times.
238092 if (draw->desc->comp[comp].plane != plane)
586 148620 continue;
587 89472 p = p0 + offset;
588 89472 m = mask;
589
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 89292 times.
89472 if (top) {
590
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 if (depth <= 8) {
591 180 blend_line_hv(p, draw->pixelstep[plane],
592 180 color->comp[plane].u8[index], alpha,
593 m, mask_linesize, l2depth, w_sub,
594 180 draw->hsub[plane], draw->vsub[plane],
595 xm0, left, right, top);
596 } else {
597 blend_line_hv16(p, draw->pixelstep[plane],
598 color->comp[plane].u16[index], alpha,
599 m, mask_linesize, l2depth, w_sub,
600 draw->hsub[plane], draw->vsub[plane],
601 xm0, left, right, top);
602 }
603 180 p += dst_linesize[plane];
604 180 m += top * mask_linesize;
605 }
606
2/2
✓ Branch 0 taken 79242 times.
✓ Branch 1 taken 10230 times.
89472 if (depth <= 8) {
607
2/2
✓ Branch 0 taken 968844 times.
✓ Branch 1 taken 79242 times.
1048086 for (int y = 0; y < h_sub; y++) {
608 968844 blend_line_hv(p, draw->pixelstep[plane],
609 968844 color->comp[plane].u8[index], alpha,
610 m, mask_linesize, l2depth, w_sub,
611 968844 draw->hsub[plane], draw->vsub[plane],
612 968844 xm0, left, right, 1 << draw->vsub[plane]);
613 968844 p += dst_linesize[plane];
614 968844 m += mask_linesize << draw->vsub[plane];
615 }
616 } else {
617
2/2
✓ Branch 0 taken 163680 times.
✓ Branch 1 taken 10230 times.
173910 for (int y = 0; y < h_sub; y++) {
618 163680 blend_line_hv16(p, draw->pixelstep[plane],
619 163680 color->comp[plane].u16[index], alpha,
620 m, mask_linesize, l2depth, w_sub,
621 163680 draw->hsub[plane], draw->vsub[plane],
622 163680 xm0, left, right, 1 << draw->vsub[plane]);
623 163680 p += dst_linesize[plane];
624 163680 m += mask_linesize << draw->vsub[plane];
625 }
626 }
627
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 89292 times.
89472 if (bottom) {
628
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 if (depth <= 8) {
629 180 blend_line_hv(p, draw->pixelstep[plane],
630 180 color->comp[plane].u8[index], alpha,
631 m, mask_linesize, l2depth, w_sub,
632 180 draw->hsub[plane], draw->vsub[plane],
633 xm0, left, right, bottom);
634 } else {
635 blend_line_hv16(p, draw->pixelstep[plane],
636 color->comp[plane].u16[index], alpha,
637 m, mask_linesize, l2depth, w_sub,
638 draw->hsub[plane], draw->vsub[plane],
639 xm0, left, right, bottom);
640 }
641 }
642 }
643 }
644 }
645
646 230100 int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir,
647 int value)
648 {
649
2/2
✓ Branch 0 taken 206764 times.
✓ Branch 1 taken 23336 times.
230100 unsigned shift = sub_dir ? draw->vsub_max : draw->hsub_max;
650
651
2/2
✓ Branch 0 taken 105718 times.
✓ Branch 1 taken 124382 times.
230100 if (!shift)
652 105718 return value;
653
2/2
✓ Branch 0 taken 104106 times.
✓ Branch 1 taken 20276 times.
124382 if (round_dir >= 0)
654
2/2
✓ Branch 0 taken 3396 times.
✓ Branch 1 taken 100710 times.
104106 value += round_dir ? (1 << shift) - 1 : 1 << (shift - 1);
655 124382 return (value >> shift) << shift;
656 }
657
658 166 AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags)
659 {
660 FFDrawContext draw;
661 166 AVFilterFormats *fmts = NULL;
662 int ret;
663
664
2/2
✓ Branch 1 taken 42828 times.
✓ Branch 2 taken 166 times.
42994 for (enum AVPixelFormat i = 0; av_pix_fmt_desc_get(i); i++)
665
3/4
✓ Branch 1 taken 15438 times.
✓ Branch 2 taken 27390 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15438 times.
58266 if (ff_draw_init(&draw, i, flags) >= 0 &&
666 15438 (ret = ff_add_format(&fmts, i)) < 0)
667 return NULL;
668 166 return fmts;
669 }
670