FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/drawutils.c
Date: 2025-09-17 22:08:16
Exec Total Coverage
Lines: 344 402 85.6%
Functions: 22 22 100.0%
Branches: 215 270 79.6%

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 1144 static int fill_map(const AVPixFmtDescriptor *desc, uint8_t *map)
36 {
37
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1144 times.
1144 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 1110 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1144 times.
1144 av_assert0(desc->nb_components == 3 + !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA));
41
2/2
✓ Branch 0 taken 913 times.
✓ Branch 1 taken 231 times.
1144 if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) {
42
2/2
✓ Branch 2 taken 295 times.
✓ Branch 3 taken 618 times.
913 if (desc->nb_components != av_pix_fmt_count_planes(av_pix_fmt_desc_get_id(desc)))
43 295 return AVERROR(EINVAL);
44 618 map[RED] = desc->comp[0].plane;
45 618 map[GREEN] = desc->comp[1].plane;
46 618 map[BLUE] = desc->comp[2].plane;
47
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 602 times.
618 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 846 times.
846 av_assert0(map[RED] != map[GREEN]);
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 846 times.
846 av_assert0(map[GREEN] != map[BLUE]);
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 846 times.
846 av_assert0(map[BLUE] != map[RED]);
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 846 times.
846 av_assert0(map[RED] != map[ALPHA]);
74
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 846 times.
846 av_assert0(map[GREEN] != map[ALPHA]);
75
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 846 times.
846 av_assert0(map[BLUE] != map[ALPHA]);
76
77 846 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 600 int ff_fill_ayuv_map(uint8_t *ayuv_map, enum AVPixelFormat pix_fmt)
89 {
90 600 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 600 times.
600 if (desc->flags & AV_PIX_FMT_FLAG_RGB)
92 return AVERROR(EINVAL);
93 600 return fill_map(desc, ayuv_map);
94 }
95
96 45886 int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSpace csp,
97 enum AVColorRange range, enum AVAlphaMode alpha, unsigned flags)
98 {
99 45886 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
100 45886 const AVLumaCoefficients *luma = NULL;
101 const AVComponentDescriptor *c;
102 45886 unsigned nb_planes = 0;
103 45886 int pixelstep[MAX_PLANES] = { 0 };
104 45886 int depthb = 0;
105
106
2/4
✓ Branch 0 taken 45886 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 45886 times.
45886 if (!desc || !desc->name)
107 return AVERROR(EINVAL);
108
2/2
✓ Branch 0 taken 16758 times.
✓ Branch 1 taken 29128 times.
45886 if (desc->flags & AV_PIX_FMT_FLAG_BE)
109 16758 return AVERROR(ENOSYS);
110
2/2
✓ Branch 0 taken 7182 times.
✓ Branch 1 taken 21946 times.
29128 if (desc->flags & ~(AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA))
111 7182 return AVERROR(ENOSYS);
112
2/2
✓ Branch 0 taken 21896 times.
✓ Branch 1 taken 50 times.
21946 if (csp == AVCOL_SPC_UNSPECIFIED)
113
2/2
✓ Branch 0 taken 7182 times.
✓ Branch 1 taken 14714 times.
21896 csp = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? AVCOL_SPC_RGB : AVCOL_SPC_SMPTE170M;
114
3/4
✓ Branch 0 taken 14714 times.
✓ Branch 1 taken 7232 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14714 times.
21946 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 21765 times.
✓ Branch 1 taken 181 times.
21946 if (range == AVCOL_RANGE_UNSPECIFIED)
117
4/4
✓ Branch 0 taken 21423 times.
✓ Branch 1 taken 171 times.
✓ Branch 2 taken 21252 times.
✓ Branch 3 taken 171 times.
43359 range = (format == AV_PIX_FMT_YUVJ420P || format == AV_PIX_FMT_YUVJ422P ||
118
4/4
✓ Branch 0 taken 21081 times.
✓ Branch 1 taken 171 times.
✓ Branch 2 taken 20910 times.
✓ Branch 3 taken 171 times.
21252 format == AV_PIX_FMT_YUVJ444P || format == AV_PIX_FMT_YUVJ411P ||
119
2/2
✓ Branch 0 taken 7182 times.
✓ Branch 1 taken 13728 times.
20910 format == AV_PIX_FMT_YUVJ440P || csp == AVCOL_SPC_RGB)
120
2/2
✓ Branch 0 taken 21594 times.
✓ Branch 1 taken 171 times.
43359 ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
121
3/4
✓ Branch 0 taken 13838 times.
✓ Branch 1 taken 8108 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13838 times.
21946 if (range != AVCOL_RANGE_JPEG && range != AVCOL_RANGE_MPEG)
122 return AVERROR(EINVAL);
123
2/2
✓ Branch 0 taken 59038 times.
✓ Branch 1 taken 16816 times.
75854 for (unsigned i = 0; i < desc->nb_components; i++) {
124 int db;
125 59038 c = &desc->comp[i];
126 /* for now, only 8-16 bits formats */
127
4/4
✓ Branch 0 taken 57328 times.
✓ Branch 1 taken 1710 times.
✓ Branch 2 taken 684 times.
✓ Branch 3 taken 56644 times.
59038 if (c->depth < 8 || c->depth > 16)
128 2394 return AVERROR(ENOSYS);
129
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56644 times.
56644 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 6699 times.
✓ Branch 1 taken 49945 times.
✓ Branch 2 taken 684 times.
✓ Branch 3 taken 6015 times.
56644 if (c->shift && ((c->shift + c->depth) & 0x7))
133 684 return AVERROR(ENOSYS);
134 /* mixed >8 and <=8 depth */
135 55960 db = (c->depth + 7) / 8;
136
3/4
✓ Branch 0 taken 36921 times.
✓ Branch 1 taken 19039 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36921 times.
55960 if (depthb && (depthb != db))
137 return AVERROR(ENOSYS);
138 55960 depthb = db;
139
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55960 times.
55960 if (db * (c->offset + 1) > 16)
140 return AVERROR(ENOSYS);
141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55960 times.
55960 if (c->offset % db)
142 return AVERROR(ENOSYS);
143 /* strange interleaving */
144
2/2
✓ Branch 0 taken 11223 times.
✓ Branch 1 taken 44737 times.
55960 if (pixelstep[c->plane] != 0 &&
145
2/2
✓ Branch 0 taken 1197 times.
✓ Branch 1 taken 10026 times.
11223 pixelstep[c->plane] != c->step)
146 1197 return AVERROR(ENOSYS);
147 54763 pixelstep[c->plane] = c->step;
148
2/2
✓ Branch 0 taken 855 times.
✓ Branch 1 taken 53908 times.
54763 if (pixelstep[c->plane] >= 8)
149 855 return AVERROR(ENOSYS);
150 53908 nb_planes = FFMAX(nb_planes, c->plane + 1);
151 }
152 16816 memset(draw, 0, sizeof(*draw));
153 16816 draw->desc = desc;
154 16816 draw->format = format;
155 16816 draw->nb_planes = nb_planes;
156 16816 draw->range = range;
157 16816 draw->csp = csp;
158 16816 draw->alpha = alpha;
159 16816 draw->flags = flags;
160
2/2
✓ Branch 0 taken 12491 times.
✓ Branch 1 taken 4325 times.
16816 if (luma)
161 12491 ff_fill_rgb2yuv_table(luma, draw->rgb2yuv);
162 16816 memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep));
163 16816 draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w;
164 16816 draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h;
165 16816 return 0;
166 }
167
168 229 int ff_draw_init_from_link(FFDrawContext *draw, const AVFilterLink *link,
169 unsigned flags)
170 {
171 229 return ff_draw_init2(draw, link->format, link->colorspace, link->color_range, link->alpha_mode, flags);
172 }
173
174 45657 int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
175 {
176 45657 return ff_draw_init2(draw, format, AVCOL_SPC_UNSPECIFIED, AVCOL_RANGE_UNSPECIFIED, AVALPHA_MODE_UNSPECIFIED, flags);
177 }
178
179 209616 void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
180 {
181 double yuvad[4];
182 double rgbad[4];
183 209616 const AVPixFmtDescriptor *desc = draw->desc;
184
185
1/2
✓ Branch 0 taken 209616 times.
✗ Branch 1 not taken.
209616 if (rgba != color->rgba)
186 209616 memcpy(color->rgba, rgba, sizeof(color->rgba));
187
188 209616 memset(color->comp, 0, sizeof(color->comp));
189
190
2/2
✓ Branch 0 taken 838464 times.
✓ Branch 1 taken 209616 times.
1048080 for (int i = 0; i < 4; i++)
191 838464 rgbad[i] = color->rgba[i] / 255.;
192
193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209616 times.
209616 if (draw->alpha == AVALPHA_MODE_PREMULTIPLIED) {
194 for (int i = 0; i < 3; i++)
195 rgbad[i] *= rgbad[3];
196 }
197
198
2/2
✓ Branch 0 taken 54602 times.
✓ Branch 1 taken 155014 times.
209616 if (draw->desc->flags & AV_PIX_FMT_FLAG_RGB)
199 54602 memcpy(yuvad, rgbad, sizeof(double) * 3);
200 else
201 155014 ff_matrix_mul_3x3_vec(yuvad, rgbad, draw->rgb2yuv);
202
203 209616 yuvad[3] = rgbad[3];
204
205
2/2
✓ Branch 0 taken 628848 times.
✓ Branch 1 taken 209616 times.
838464 for (int i = 0; i < 3; i++) {
206
4/4
✓ Branch 0 taken 465042 times.
✓ Branch 1 taken 163806 times.
✓ Branch 2 taken 310028 times.
✓ Branch 3 taken 155014 times.
628848 int chroma = (!(draw->desc->flags & AV_PIX_FMT_FLAG_RGB) && i > 0);
207
2/2
✓ Branch 0 taken 464979 times.
✓ Branch 1 taken 163869 times.
628848 if (draw->range == AVCOL_RANGE_MPEG) {
208
2/2
✓ Branch 0 taken 309986 times.
✓ Branch 1 taken 154993 times.
464979 yuvad[i] *= (chroma ? 224. : 219.) / 255.;
209
2/2
✓ Branch 0 taken 309986 times.
✓ Branch 1 taken 154993 times.
464979 yuvad[i] += (chroma ? 128. : 16.) / 255.;
210
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 163827 times.
163869 } else if (chroma) {
211 42 yuvad[i] += 0.5;
212 }
213 }
214
215 // Ensure we place the alpha appropriately for gray formats
216
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 209606 times.
209616 if (desc->nb_components <= 2)
217 10 yuvad[1] = yuvad[3];
218
219
2/2
✓ Branch 0 taken 654859 times.
✓ Branch 1 taken 209616 times.
864475 for (unsigned i = 0; i < desc->nb_components; i++) {
220 654859 unsigned val = yuvad[i] * ((1 << (draw->desc->comp[i].depth + draw->desc->comp[i].shift)) - 1) + 0.5;
221
2/2
✓ Branch 0 taken 59677 times.
✓ Branch 1 taken 595182 times.
654859 if (desc->comp[i].depth > 8)
222 59677 color->comp[desc->comp[i].plane].u16[desc->comp[i].offset / 2] = val;
223 else
224 595182 color->comp[desc->comp[i].plane].u8[desc->comp[i].offset] = val;
225 }
226 209616 }
227
228 608737 static uint8_t *pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[],
229 int plane, int x, int y)
230 {
231 608737 return data[plane] +
232 1217474 (y >> draw->vsub[plane]) * linesize[plane] +
233 608737 (x >> draw->hsub[plane]) * draw->pixelstep[plane];
234 }
235
236 40 void ff_copy_rectangle2(FFDrawContext *draw,
237 uint8_t *dst[], int dst_linesize[],
238 uint8_t *src[], int src_linesize[],
239 int dst_x, int dst_y, int src_x, int src_y,
240 int w, int h)
241 {
242 int wp, hp;
243 uint8_t *p, *q;
244
245
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 40 times.
160 for (int plane = 0; plane < draw->nb_planes; plane++) {
246 120 p = pointer_at(draw, src, src_linesize, plane, src_x, src_y);
247 120 q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
248 120 wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]) * draw->pixelstep[plane];
249 120 hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
250
2/2
✓ Branch 0 taken 23040 times.
✓ Branch 1 taken 120 times.
23160 for (int y = 0; y < hp; y++) {
251 23040 memcpy(q, p, wp);
252 23040 p += src_linesize[plane];
253 23040 q += dst_linesize[plane];
254 }
255 }
256 40 }
257
258 211727 void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color,
259 uint8_t *dst[], int dst_linesize[],
260 int dst_x, int dst_y, int w, int h)
261 {
262 int wp, hp;
263 uint8_t *p0, *p;
264 211727 FFDrawColor color_tmp = *color;
265
266
2/2
✓ Branch 0 taken 526577 times.
✓ Branch 1 taken 211727 times.
738304 for (int plane = 0; plane < draw->nb_planes; plane++) {
267 526577 p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
268 526577 wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]);
269 526577 hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 526577 times.
526577 if (!hp)
271 return;
272 526577 p = p0;
273
274 if (HAVE_BIGENDIAN && draw->desc->comp[0].depth > 8) {
275 for (int x = 0; 2*x < draw->pixelstep[plane]; x++)
276 color_tmp.comp[plane].u16[x] = av_bswap16(color_tmp.comp[plane].u16[x]);
277 }
278
279 /* copy first line from color */
280
2/2
✓ Branch 0 taken 2306733 times.
✓ Branch 1 taken 526577 times.
2833310 for (int x = 0; x < wp; x++) {
281 2306733 memcpy(p, color_tmp.comp[plane].u8, draw->pixelstep[plane]);
282 2306733 p += draw->pixelstep[plane];
283 }
284 526577 wp *= draw->pixelstep[plane];
285 /* copy next lines from first line */
286 526577 p = p0 + dst_linesize[plane];
287
2/2
✓ Branch 0 taken 9198872 times.
✓ Branch 1 taken 526577 times.
9725449 for (int y = 1; y < hp; y++) {
288 9198872 memcpy(p, p0, wp);
289 9198872 p += dst_linesize[plane];
290 }
291 }
292 }
293
294 /**
295 * Clip interval [x; x+w[ within [0; wmax[.
296 * The resulting w may be negative if the final interval is empty.
297 * dx, if not null, return the difference between in and out value of x.
298 */
299 61560 static void clip_interval(int wmax, int *x, int *w, int *dx)
300 {
301
2/2
✓ Branch 0 taken 59648 times.
✓ Branch 1 taken 1912 times.
61560 if (dx)
302 59648 *dx = 0;
303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61560 times.
61560 if (*x < 0) {
304 if (dx)
305 *dx = -*x;
306 *w += *x;
307 *x = 0;
308 }
309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61560 times.
61560 if (*x + *w > wmax)
310 *w = wmax - *x;
311 61560 }
312
313 /**
314 * Decompose w pixels starting at x
315 * into start + (w starting at x) + end
316 * with x and w aligned on multiples of 1<<sub.
317 */
318 163840 static void subsampling_bounds(int sub, int *x, int *w, int *start, int *end)
319 {
320 163840 int mask = (1 << sub) - 1;
321
322 163840 *start = (-*x) & mask;
323 163840 *x += *start;
324 163840 *start = FFMIN(*start, *w);
325 163840 *w -= *start;
326 163840 *end = *w & mask;
327 163840 *w >>= sub;
328 163840 }
329
330 /* If alpha is in the [ 0 ; 0x1010101 ] range,
331 then alpha * value is in the [ 0 ; 0xFFFFFFFF ] range,
332 and >> 24 gives a correct rounding. */
333 69660 static void blend_line(uint8_t *dst, unsigned src, unsigned alpha,
334 int dx, int w, unsigned hsub, int left, int right)
335 {
336 69660 unsigned asrc = alpha * src;
337 69660 unsigned tau = 0x1010101 - alpha;
338
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69660 times.
69660 if (left) {
340 unsigned suba = (left * alpha) >> hsub;
341 *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
342 dst += dx;
343 }
344
2/2
✓ Branch 0 taken 5819400 times.
✓ Branch 1 taken 69660 times.
5889060 for (int x = 0; x < w; x++) {
345 5819400 *dst = (*dst * tau + asrc) >> 24;
346 5819400 dst += dx;
347 }
348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69660 times.
69660 if (right) {
349 unsigned suba = (right * alpha) >> hsub;
350 *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
351 }
352 69660 }
353
354 11880 static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha,
355 int dx, int w, unsigned hsub, int left, int right)
356 {
357 11880 unsigned asrc = alpha * src;
358 11880 unsigned tau = 0x10001 - alpha;
359
360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11880 times.
11880 if (left) {
361 unsigned suba = (left * alpha) >> hsub;
362 uint16_t value = AV_RL16(dst);
363 AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
364 dst += dx;
365 }
366
2/2
✓ Branch 0 taken 792000 times.
✓ Branch 1 taken 11880 times.
803880 for (int x = 0; x < w; x++) {
367 792000 uint16_t value = AV_RL16(dst);
368 792000 AV_WL16(dst, (value * tau + asrc) >> 16);
369 792000 dst += dx;
370 }
371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11880 times.
11880 if (right) {
372 unsigned suba = (right * alpha) >> hsub;
373 uint16_t value = AV_RL16(dst);
374 AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
375 }
376 11880 }
377
378 956 void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
379 uint8_t *dst[], int dst_linesize[],
380 int dst_w, int dst_h,
381 int x0, int y0, int w, int h)
382 {
383 unsigned alpha, nb_planes, nb_comp;
384 int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom;
385 uint8_t *p0, *p;
386
387 1912 nb_comp = draw->desc->nb_components -
388
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));
389
390 /* TODO optimize if alpha = 0xFF */
391 956 clip_interval(dst_w, &x0, &w, NULL);
392 956 clip_interval(dst_h, &y0, &h, NULL);
393
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])
394 return;
395
2/2
✓ Branch 0 taken 846 times.
✓ Branch 1 taken 110 times.
956 if (draw->desc->comp[0].depth <= 8) {
396 /* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */
397 846 alpha = 0x10203 * color->rgba[3] + 0x2;
398 } else {
399 /* 0x101 * alpha is in the [ 2 ; 0x1001] range */
400 110 alpha = 0x101 * color->rgba[3] + 0x2;
401 }
402
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));
403 956 nb_planes += !nb_planes;
404
2/2
✓ Branch 0 taken 2556 times.
✓ Branch 1 taken 956 times.
3512 for (unsigned plane = 0; plane < nb_planes; plane++) {
405 2556 p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
406 2556 w_sub = w;
407 2556 h_sub = h;
408 2556 x_sub = x0;
409 2556 y_sub = y0;
410 2556 subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
411 2556 subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
412
2/2
✓ Branch 0 taken 7668 times.
✓ Branch 1 taken 2556 times.
10224 for (unsigned comp = 0; comp < nb_comp; comp++) {
413 7668 const int depth = draw->desc->comp[comp].depth;
414 7668 const int offset = draw->desc->comp[comp].offset;
415 7668 const int index = offset / ((depth + 7) / 8);
416
417
2/2
✓ Branch 0 taken 4800 times.
✓ Branch 1 taken 2868 times.
7668 if (draw->desc->comp[comp].plane != plane)
418 4800 continue;
419 2868 p = p0 + offset;
420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2868 times.
2868 if (top) {
421 if (depth <= 8) {
422 blend_line(p, color->comp[plane].u8[index], alpha >> 1,
423 draw->pixelstep[plane], w_sub,
424 draw->hsub[plane], left, right);
425 } else {
426 blend_line16(p, color->comp[plane].u16[index], alpha >> 1,
427 draw->pixelstep[plane], w_sub,
428 draw->hsub[plane], left, right);
429 }
430 p += dst_linesize[plane];
431 }
432
2/2
✓ Branch 0 taken 2538 times.
✓ Branch 1 taken 330 times.
2868 if (depth <= 8) {
433
2/2
✓ Branch 0 taken 69660 times.
✓ Branch 1 taken 2538 times.
72198 for (int y = 0; y < h_sub; y++) {
434 69660 blend_line(p, color->comp[plane].u8[index], alpha,
435 draw->pixelstep[plane], w_sub,
436 69660 draw->hsub[plane], left, right);
437 69660 p += dst_linesize[plane];
438 }
439 } else {
440
2/2
✓ Branch 0 taken 11880 times.
✓ Branch 1 taken 330 times.
12210 for (int y = 0; y < h_sub; y++) {
441 11880 blend_line16(p, color->comp[plane].u16[index], alpha,
442 draw->pixelstep[plane], w_sub,
443 11880 draw->hsub[plane], left, right);
444 11880 p += dst_linesize[plane];
445 }
446 }
447
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2868 times.
2868 if (bottom) {
448 if (depth <= 8) {
449 blend_line(p, color->comp[plane].u8[index], alpha >> 1,
450 draw->pixelstep[plane], w_sub,
451 draw->hsub[plane], left, right);
452 } else {
453 blend_line16(p, color->comp[plane].u16[index], alpha >> 1,
454 draw->pixelstep[plane], w_sub,
455 draw->hsub[plane], left, right);
456 }
457 }
458 }
459 }
460 }
461
462 1070080 static void blend_pixel16(uint8_t *dst, unsigned src, unsigned alpha,
463 const uint8_t *mask, int mask_linesize, int l2depth,
464 unsigned w, unsigned h, unsigned shift, unsigned xm0)
465 {
466 1070080 unsigned t = 0;
467 1070080 unsigned xmshf = 3 - l2depth;
468 1070080 unsigned xmmod = 7 >> l2depth;
469 1070080 unsigned mbits = (1 << (1 << l2depth)) - 1;
470 1070080 unsigned mmult = 255 / mbits;
471 1070080 uint16_t value = AV_RL16(dst);
472
473
2/2
✓ Branch 0 taken 1070080 times.
✓ Branch 1 taken 1070080 times.
2140160 for (unsigned y = 0; y < h; y++) {
474 1070080 unsigned xm = xm0;
475
2/2
✓ Branch 0 taken 1605120 times.
✓ Branch 1 taken 1070080 times.
2675200 for (unsigned x = 0; x < w; x++) {
476 1605120 t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
477 1605120 * mmult;
478 1605120 xm++;
479 }
480 1070080 mask += mask_linesize;
481 }
482 1070080 alpha = (t >> shift) * alpha;
483 1070080 AV_WL16(dst, ((0x10001 - alpha) * value + alpha * src) >> 16);
484 1070080 }
485
486 8018080 static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha,
487 const uint8_t *mask, int mask_linesize, int l2depth,
488 unsigned w, unsigned h, unsigned shift, unsigned xm0)
489 {
490 8018080 unsigned t = 0;
491 8018080 unsigned xmshf = 3 - l2depth;
492 8018080 unsigned xmmod = 7 >> l2depth;
493 8018080 unsigned mbits = (1 << (1 << l2depth)) - 1;
494 8018080 unsigned mmult = 255 / mbits;
495
496
2/2
✓ Branch 0 taken 9481216 times.
✓ Branch 1 taken 8018080 times.
17499296 for (unsigned y = 0; y < h; y++) {
497 9481216 unsigned xm = xm0;
498
2/2
✓ Branch 0 taken 12489216 times.
✓ Branch 1 taken 9481216 times.
21970432 for (unsigned x = 0; x < w; x++) {
499 12489216 t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
500 12489216 * mmult;
501 12489216 xm++;
502 }
503 9481216 mask += mask_linesize;
504 }
505 8018080 alpha = (t >> shift) * alpha;
506 8018080 *dst = ((0x1010101 - alpha) * *dst + alpha * src) >> 24;
507 8018080 }
508
509 163680 static void blend_line_hv16(uint8_t *dst, int dst_delta,
510 unsigned src, unsigned alpha,
511 const uint8_t *mask, int mask_linesize, int l2depth, int w,
512 unsigned hsub, unsigned vsub,
513 int xm, int left, int right, int hband)
514 {
515
516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 163680 times.
163680 if (left) {
517 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
518 left, hband, hsub + vsub, xm);
519 dst += dst_delta;
520 xm += left;
521 }
522
2/2
✓ Branch 0 taken 1070080 times.
✓ Branch 1 taken 163680 times.
1233760 for (int x = 0; x < w; x++) {
523 1070080 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
524 1070080 1 << hsub, hband, hsub + vsub, xm);
525 1070080 dst += dst_delta;
526 1070080 xm += 1 << hsub;
527 }
528
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 163680 times.
163680 if (right)
529 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
530 right, hband, hsub + vsub, xm);
531 163680 }
532
533 969204 static void blend_line_hv(uint8_t *dst, int dst_delta,
534 unsigned src, unsigned alpha,
535 const uint8_t *mask, int mask_linesize, int l2depth, int w,
536 unsigned hsub, unsigned vsub,
537 int xm, int left, int right, int hband)
538 {
539
540
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 969204 times.
969204 if (left) {
541 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
542 left, hband, hsub + vsub, xm);
543 dst += dst_delta;
544 xm += left;
545 }
546
2/2
✓ Branch 0 taken 8018080 times.
✓ Branch 1 taken 969204 times.
8987284 for (int x = 0; x < w; x++) {
547 8018080 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
548 8018080 1 << hsub, hband, hsub + vsub, xm);
549 8018080 dst += dst_delta;
550 8018080 xm += 1 << hsub;
551 }
552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 969204 times.
969204 if (right)
553 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
554 right, hband, hsub + vsub, xm);
555 969204 }
556
557 29824 void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color,
558 uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h,
559 const uint8_t *mask, int mask_linesize, int mask_w, int mask_h,
560 int l2depth, unsigned endianness, int x0, int y0)
561 {
562 unsigned alpha, nb_planes, nb_comp;
563 int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom;
564 uint8_t *p;
565 const uint8_t *m;
566
567 59648 nb_comp = draw->desc->nb_components -
568
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));
569
570 29824 clip_interval(dst_w, &x0, &mask_w, &xm0);
571 29824 clip_interval(dst_h, &y0, &mask_h, &ym0);
572 29824 mask += ym0 * mask_linesize;
573
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])
574 return;
575
2/2
✓ Branch 0 taken 26414 times.
✓ Branch 1 taken 3410 times.
29824 if (draw->desc->comp[0].depth <= 8) {
576 /* alpha is in the [ 0 ; 0x10203 ] range,
577 alpha * mask is in the [ 0 ; 0x1010101 - 4 ] range */
578 26414 alpha = (0x10307 * color->rgba[3] + 0x3) >> 8;
579 } else {
580 3410 alpha = (0x101 * color->rgba[3] + 0x2) >> 8;
581 }
582
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));
583 29824 nb_planes += !nb_planes;
584
2/2
✓ Branch 0 taken 79364 times.
✓ Branch 1 taken 29824 times.
109188 for (unsigned plane = 0; plane < nb_planes; plane++) {
585 79364 uint8_t *p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
586 79364 w_sub = mask_w;
587 79364 h_sub = mask_h;
588 79364 x_sub = x0;
589 79364 y_sub = y0;
590 79364 subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
591 79364 subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
592
2/2
✓ Branch 0 taken 238092 times.
✓ Branch 1 taken 79364 times.
317456 for (unsigned comp = 0; comp < nb_comp; comp++) {
593 238092 const int depth = draw->desc->comp[comp].depth;
594 238092 const int offset = draw->desc->comp[comp].offset;
595 238092 const int index = offset / ((depth + 7) / 8);
596
597
2/2
✓ Branch 0 taken 148620 times.
✓ Branch 1 taken 89472 times.
238092 if (draw->desc->comp[comp].plane != plane)
598 148620 continue;
599 89472 p = p0 + offset;
600 89472 m = mask;
601
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 89292 times.
89472 if (top) {
602
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 if (depth <= 8) {
603 180 blend_line_hv(p, draw->pixelstep[plane],
604 180 color->comp[plane].u8[index], alpha,
605 m, mask_linesize, l2depth, w_sub,
606 180 draw->hsub[plane], draw->vsub[plane],
607 xm0, left, right, top);
608 } else {
609 blend_line_hv16(p, draw->pixelstep[plane],
610 color->comp[plane].u16[index], alpha,
611 m, mask_linesize, l2depth, w_sub,
612 draw->hsub[plane], draw->vsub[plane],
613 xm0, left, right, top);
614 }
615 180 p += dst_linesize[plane];
616 180 m += top * mask_linesize;
617 }
618
2/2
✓ Branch 0 taken 79242 times.
✓ Branch 1 taken 10230 times.
89472 if (depth <= 8) {
619
2/2
✓ Branch 0 taken 968844 times.
✓ Branch 1 taken 79242 times.
1048086 for (int y = 0; y < h_sub; y++) {
620 968844 blend_line_hv(p, draw->pixelstep[plane],
621 968844 color->comp[plane].u8[index], alpha,
622 m, mask_linesize, l2depth, w_sub,
623 968844 draw->hsub[plane], draw->vsub[plane],
624 968844 xm0, left, right, 1 << draw->vsub[plane]);
625 968844 p += dst_linesize[plane];
626 968844 m += mask_linesize << draw->vsub[plane];
627 }
628 } else {
629
2/2
✓ Branch 0 taken 163680 times.
✓ Branch 1 taken 10230 times.
173910 for (int y = 0; y < h_sub; y++) {
630 163680 blend_line_hv16(p, draw->pixelstep[plane],
631 163680 color->comp[plane].u16[index], alpha,
632 m, mask_linesize, l2depth, w_sub,
633 163680 draw->hsub[plane], draw->vsub[plane],
634 163680 xm0, left, right, 1 << draw->vsub[plane]);
635 163680 p += dst_linesize[plane];
636 163680 m += mask_linesize << draw->vsub[plane];
637 }
638 }
639
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 89292 times.
89472 if (bottom) {
640
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 if (depth <= 8) {
641 180 blend_line_hv(p, draw->pixelstep[plane],
642 180 color->comp[plane].u8[index], alpha,
643 m, mask_linesize, l2depth, w_sub,
644 180 draw->hsub[plane], draw->vsub[plane],
645 xm0, left, right, bottom);
646 } else {
647 blend_line_hv16(p, draw->pixelstep[plane],
648 color->comp[plane].u16[index], alpha,
649 m, mask_linesize, l2depth, w_sub,
650 draw->hsub[plane], draw->vsub[plane],
651 xm0, left, right, bottom);
652 }
653 }
654 }
655 }
656 }
657
658 230124 int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir,
659 int value)
660 {
661
2/2
✓ Branch 0 taken 206776 times.
✓ Branch 1 taken 23348 times.
230124 unsigned shift = sub_dir ? draw->vsub_max : draw->hsub_max;
662
663
2/2
✓ Branch 0 taken 105742 times.
✓ Branch 1 taken 124382 times.
230124 if (!shift)
664 105742 return value;
665
2/2
✓ Branch 0 taken 104106 times.
✓ Branch 1 taken 20276 times.
124382 if (round_dir >= 0)
666
2/2
✓ Branch 0 taken 3396 times.
✓ Branch 1 taken 100710 times.
104106 value += round_dir ? (1 << shift) - 1 : 1 << (shift - 1);
667 124382 return (value >> shift) << shift;
668 }
669
670 171 AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags)
671 {
672 FFDrawContext draw;
673 171 AVFilterFormats *fmts = NULL;
674 int ret;
675
676
2/2
✓ Branch 1 taken 45657 times.
✓ Branch 2 taken 171 times.
45828 for (enum AVPixelFormat i = 0; av_pix_fmt_desc_get(i); i++)
677
3/4
✓ Branch 1 taken 16587 times.
✓ Branch 2 taken 29070 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16587 times.
62244 if (ff_draw_init(&draw, i, flags) >= 0 &&
678 16587 (ret = ff_add_format(&fmts, i)) < 0)
679 return NULL;
680 171 return fmts;
681 }
682