FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/drawutils.c
Date: 2026-11-01 12:52:33
Exec Total Coverage
Lines: 356 413 86.2%
Functions: 23 23 100.0%
Branches: 227 276 82.2%

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 1189 static int fill_map(const AVPixFmtDescriptor *desc, uint8_t *map)
36 {
37
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1189 times.
1189 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 35 times.
✓ Branch 1 taken 1154 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1189 times.
1189 av_assert0(desc->nb_components == 3 + !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA));
41
2/2
✓ Branch 0 taken 949 times.
✓ Branch 1 taken 240 times.
1189 if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) {
42
2/2
✓ Branch 2 taken 307 times.
✓ Branch 3 taken 642 times.
949 if (desc->nb_components != av_pix_fmt_count_planes(av_pix_fmt_desc_get_id(desc)))
43 307 return AVERROR(EINVAL);
44 642 map[RED] = desc->comp[0].plane;
45 642 map[GREEN] = desc->comp[1].plane;
46 642 map[BLUE] = desc->comp[2].plane;
47
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 626 times.
642 map[ALPHA] = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? desc->comp[3].plane : 3;
48 } else {
49 240 int had0 = 0;
50 240 unsigned depthb = 0;
51
2/2
✓ Branch 0 taken 734 times.
✓ Branch 1 taken 237 times.
971 for (unsigned i = 0; i < desc->nb_components; i++) {
52 /* all components must have same depth in bytes */
53 734 unsigned db = (desc->comp[i].depth + 7) / 8;
54 734 unsigned pos = desc->comp[i].offset / db;
55
3/4
✓ Branch 0 taken 494 times.
✓ Branch 1 taken 240 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 494 times.
734 if (depthb && (depthb != db))
56 ✗ return AVERROR(ENOSYS);
57
58
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 731 times.
734 if (desc->comp[i].offset % db)
59 3 return AVERROR(ENOSYS);
60
61 731 had0 |= pos == 0;
62 731 map[i] = pos;
63 731 depthb = db;
64 }
65
66
2/2
✓ Branch 0 taken 218 times.
✓ Branch 1 taken 19 times.
237 if (desc->nb_components == 3)
67
1/2
✓ Branch 0 taken 218 times.
✗ Branch 1 not taken.
218 map[ALPHA] = had0 ? 3 : 0;
68 }
69
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 879 times.
879 av_assert0(map[RED] != map[GREEN]);
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 879 times.
879 av_assert0(map[GREEN] != map[BLUE]);
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 879 times.
879 av_assert0(map[BLUE] != map[RED]);
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 879 times.
879 av_assert0(map[RED] != map[ALPHA]);
74
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 879 times.
879 av_assert0(map[GREEN] != map[ALPHA]);
75
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 879 times.
879 av_assert0(map[BLUE] != map[ALPHA]);
76
77 879 return 0;
78 }
79
80 618 int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
81 {
82 618 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
83
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 565 times.
618 if (!(desc->flags & AV_PIX_FMT_FLAG_RGB))
84 53 return AVERROR(EINVAL);
85 565 return fill_map(desc, rgba_map);
86 }
87
88 624 int ff_fill_ayuv_map(uint8_t *ayuv_map, enum AVPixelFormat pix_fmt)
89 {
90 624 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 624 times.
624 if (desc->flags & AV_PIX_FMT_FLAG_RGB)
92 ✗ return AVERROR(EINVAL);
93 624 return fill_map(desc, ayuv_map);
94 }
95
96 69434 int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSpace csp,
97 enum AVColorRange range, enum AVAlphaMode alpha, unsigned flags)
98 {
99 69434 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
100 69434 const AVLumaCoefficients *luma = NULL;
101 const AVComponentDescriptor *c;
102 69434 unsigned nb_planes = 0;
103 69434 int pixelstep[MAX_PLANES] = { 0 };
104 69434 int depthb = 0;
105
106
2/4
✓ Branch 0 taken 69434 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 69434 times.
69434 if (!desc || !desc->name)
107 ✗ return AVERROR(EINVAL);
108
2/2
✓ Branch 0 taken 25344 times.
✓ Branch 1 taken 44090 times.
69434 if (desc->flags & AV_PIX_FMT_FLAG_BE)
109 25344 return AVERROR(ENOSYS);
110
2/2
✓ Branch 0 taken 11264 times.
✓ Branch 1 taken 32826 times.
44090 if (desc->flags & ~(AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA))
111 11264 return AVERROR(ENOSYS);
112
2/2
✓ Branch 0 taken 32771 times.
✓ Branch 1 taken 55 times.
32826 if (csp == AVCOL_SPC_UNSPECIFIED)
113
2/2
✓ Branch 0 taken 10753 times.
✓ Branch 1 taken 22018 times.
32771 csp = (desc->flags & AV_PIX_FMT_FLAG_RGB) ? AVCOL_SPC_RGB : AVCOL_SPC_SMPTE170M;
114
3/4
✓ Branch 0 taken 22018 times.
✓ Branch 1 taken 10808 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22018 times.
32826 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 32632 times.
✓ Branch 1 taken 194 times.
32826 if (range == AVCOL_RANGE_UNSPECIFIED)
117
4/4
✓ Branch 0 taken 32120 times.
✓ Branch 1 taken 256 times.
✓ Branch 2 taken 31864 times.
✓ Branch 3 taken 256 times.
65008 range = (format == AV_PIX_FMT_YUVJ420P || format == AV_PIX_FMT_YUVJ422P ||
118
4/4
✓ Branch 0 taken 31608 times.
✓ Branch 1 taken 256 times.
✓ Branch 2 taken 31352 times.
✓ Branch 3 taken 256 times.
31864 format == AV_PIX_FMT_YUVJ444P || format == AV_PIX_FMT_YUVJ411P ||
119
2/2
✓ Branch 0 taken 10753 times.
✓ Branch 1 taken 20599 times.
31352 format == AV_PIX_FMT_YUVJ440P || csp == AVCOL_SPC_RGB)
120
2/2
✓ Branch 0 taken 32376 times.
✓ Branch 1 taken 256 times.
65008 ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
121
3/4
✓ Branch 0 taken 20716 times.
✓ Branch 1 taken 12110 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20716 times.
32826 if (range != AVCOL_RANGE_JPEG && range != AVCOL_RANGE_MPEG)
122 ✗ return AVERROR(EINVAL);
123
2/2
✓ Branch 0 taken 88279 times.
✓ Branch 1 taken 25146 times.
113425 for (unsigned i = 0; i < desc->nb_components; i++) {
124 int db;
125 88279 c = &desc->comp[i];
126 /* for now, only 8-16 bits formats */
127
4/4
✓ Branch 0 taken 85719 times.
✓ Branch 1 taken 2560 times.
✓ Branch 2 taken 1024 times.
✓ Branch 3 taken 84695 times.
88279 if (c->depth < 8 || c->depth > 16)
128 3584 return AVERROR(ENOSYS);
129
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84695 times.
84695 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 10014 times.
✓ Branch 1 taken 74681 times.
✓ Branch 2 taken 1024 times.
✓ Branch 3 taken 8990 times.
84695 if (c->shift && ((c->shift + c->depth) & 0x7))
133 1024 return AVERROR(ENOSYS);
134 /* mixed >8 and <=8 depth */
135 83671 db = (c->depth + 7) / 8;
136
3/4
✓ Branch 0 taken 55197 times.
✓ Branch 1 taken 28474 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55197 times.
83671 if (depthb && (depthb != db))
137 ✗ return AVERROR(ENOSYS);
138 83671 depthb = db;
139
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83671 times.
83671 if (db * (c->offset + 1) > 16)
140 ✗ return AVERROR(ENOSYS);
141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83671 times.
83671 if (c->offset % db)
142 ✗ return AVERROR(ENOSYS);
143 /* strange interleaving */
144
2/2
✓ Branch 0 taken 16761 times.
✓ Branch 1 taken 66910 times.
83671 if (pixelstep[c->plane] != 0 &&
145
2/2
✓ Branch 0 taken 1792 times.
✓ Branch 1 taken 14969 times.
16761 pixelstep[c->plane] != c->step)
146 1792 return AVERROR(ENOSYS);
147 81879 pixelstep[c->plane] = c->step;
148
2/2
✓ Branch 0 taken 1280 times.
✓ Branch 1 taken 80599 times.
81879 if (pixelstep[c->plane] >= 8)
149 1280 return AVERROR(ENOSYS);
150 80599 nb_planes = FFMAX(nb_planes, c->plane + 1);
151 }
152 25146 memset(draw, 0, sizeof(*draw));
153 25146 draw->desc = desc;
154 25146 draw->format = format;
155 25146 draw->nb_planes = nb_planes;
156 25146 draw->range = range;
157 25146 draw->csp = csp;
158 25146 draw->alpha = alpha;
159 25146 draw->flags = flags;
160
2/2
✓ Branch 0 taken 18690 times.
✓ Branch 1 taken 6456 times.
25146 if (luma)
161 18690 ff_fill_rgb2yuv_table(luma, draw->rgb2yuv);
162 25146 memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep));
163 25146 draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w;
164 25146 draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h;
165 25146 return 0;
166 }
167
168 313 int ff_draw_init_from_link(FFDrawContext *draw, const AVFilterLink *link,
169 unsigned flags)
170 {
171 313 return ff_draw_init2(draw, link->format, link->colorspace, link->color_range, link->alpha_mode, flags);
172 }
173
174 69121 int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
175 {
176 69121 return ff_draw_init2(draw, format, AVCOL_SPC_UNSPECIFIED, AVCOL_RANGE_UNSPECIFIED, AVALPHA_MODE_UNSPECIFIED, flags);
177 }
178
179 235227 void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
180 {
181 double yuvad[4];
182 double rgbad[4];
183 235227 const AVPixFmtDescriptor *desc = draw->desc;
184
185
1/2
✓ Branch 0 taken 235227 times.
✗ Branch 1 not taken.
235227 if (rgba != color->rgba)
186 235227 memcpy(color->rgba, rgba, sizeof(color->rgba));
187
188 235227 memset(color->comp, 0, sizeof(color->comp));
189
190
2/2
✓ Branch 0 taken 940908 times.
✓ Branch 1 taken 235227 times.
1176135 for (int i = 0; i < 4; i++)
191 940908 rgbad[i] = color->rgba[i] / 255.;
192
193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 235227 times.
235227 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 54710 times.
✓ Branch 1 taken 180517 times.
235227 if (draw->desc->flags & AV_PIX_FMT_FLAG_RGB)
199 54710 memcpy(yuvad, rgbad, sizeof(double) * 3);
200 else
201 180517 ff_matrix_mul_3x3_vec(yuvad, rgbad, draw->rgb2yuv);
202
203 235227 yuvad[3] = rgbad[3];
204
205
2/2
✓ Branch 0 taken 705681 times.
✓ Branch 1 taken 235227 times.
940908 for (int i = 0; i < 3; i++) {
206
4/4
✓ Branch 0 taken 541551 times.
✓ Branch 1 taken 164130 times.
✓ Branch 2 taken 361034 times.
✓ Branch 3 taken 180517 times.
705681 int chroma = (!(draw->desc->flags & AV_PIX_FMT_FLAG_RGB) && i > 0);
207
2/2
✓ Branch 0 taken 541470 times.
✓ Branch 1 taken 164211 times.
705681 if (draw->range == AVCOL_RANGE_MPEG) {
208
2/2
✓ Branch 0 taken 360980 times.
✓ Branch 1 taken 180490 times.
541470 yuvad[i] *= (chroma ? 224. : 219.) / 255.;
209
2/2
✓ Branch 0 taken 360980 times.
✓ Branch 1 taken 180490 times.
541470 yuvad[i] += (chroma ? 128. : 16.) / 255.;
210
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 164157 times.
164211 } else if (chroma) {
211 54 yuvad[i] += 0.5;
212 }
213 }
214
215 // Ensure we place the alpha appropriately for gray formats
216
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 235208 times.
235227 if (desc->nb_components <= 2)
217 19 yuvad[1] = yuvad[3];
218
219
2/2
✓ Branch 0 taken 731795 times.
✓ Branch 1 taken 235227 times.
967022 for (unsigned i = 0; i < desc->nb_components; i++) {
220 731795 unsigned val = yuvad[i] * ((1 << (draw->desc->comp[i].depth + draw->desc->comp[i].shift)) - 1) + 0.5;
221
2/2
✓ Branch 0 taken 59864 times.
✓ Branch 1 taken 671931 times.
731795 if (desc->comp[i].depth > 8)
222 59864 color->comp[desc->comp[i].plane].u16[desc->comp[i].offset / 2] = val;
223 else
224 671931 color->comp[desc->comp[i].plane].u8[desc->comp[i].offset] = val;
225 }
226 235227 }
227
228 704896 static uint8_t *pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[],
229 int plane, int x, int y)
230 {
231 704896 return data[plane] +
232 1409792 (y >> draw->vsub[plane]) * linesize[plane] +
233 704896 (x >> draw->hsub[plane]) * draw->pixelstep[plane];
234 }
235
236 90 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 270 times.
✓ Branch 1 taken 90 times.
360 for (int plane = 0; plane < draw->nb_planes; plane++) {
246 270 p = pointer_at(draw, src, src_linesize, plane, src_x, src_y);
247 270 q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
248 270 wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]) * draw->pixelstep[plane];
249 270 hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
250
2/2
✓ Branch 0 taken 51840 times.
✓ Branch 1 taken 270 times.
52110 for (int y = 0; y < hp; y++) {
251 51840 memcpy(q, p, wp);
252 51840 p += src_linesize[plane];
253 51840 q += dst_linesize[plane];
254 }
255 }
256 90 }
257
258 237567 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 237567 FFDrawColor color_tmp = *color;
265
266
2/2
✓ Branch 0 taken 604023 times.
✓ Branch 1 taken 237567 times.
841590 for (int plane = 0; plane < draw->nb_planes; plane++) {
267 604023 p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
268 604023 wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]);
269 604023 hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 604023 times.
604023 if (!hp)
271 ✗ return;
272 604023 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 2682219 times.
✓ Branch 1 taken 604023 times.
3286242 for (int x = 0; x < wp; x++) {
281 2682219 memcpy(p, color_tmp.comp[plane].u8, draw->pixelstep[plane]);
282 2682219 p += draw->pixelstep[plane];
283 }
284 604023 wp *= draw->pixelstep[plane];
285 /* copy next lines from first line */
286 604023 p = p0 + dst_linesize[plane];
287
2/2
✓ Branch 0 taken 10310359 times.
✓ Branch 1 taken 604023 times.
10914382 for (int y = 1; y < hp; y++) {
288 10310359 memcpy(p, p0, wp);
289 10310359 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 74650 static void clip_interval(int wmax, int *x, int *w, int *dx)
300 {
301
2/2
✓ Branch 0 taken 72312 times.
✓ Branch 1 taken 2338 times.
74650 if (dx)
302 72312 *dx = 0;
303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74650 times.
74650 if (*x < 0) {
304 ✗ if (dx)
305 ✗ *dx = -*x;
306 ✗ *w += *x;
307 ✗ *x = 0;
308 }
309
2/2
✓ Branch 0 taken 663 times.
✓ Branch 1 taken 73987 times.
74650 if (*x + *w > wmax)
310 663 *w = wmax - *x;
311 74650 }
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 200666 static void subsampling_bounds(int sub, int *x, int *w, int *start, int *end)
319 {
320 200666 int mask = (1 << sub) - 1;
321
322 200666 *start = (-*x) & mask;
323 200666 *x += *start;
324 200666 *start = FFMIN(*start, *w);
325 200666 *w -= *start;
326 200666 *end = *w & mask;
327 200666 *w >>= sub;
328 200666 }
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 84692 static void blend_line(uint8_t *dst, unsigned src, unsigned alpha,
334 int dx, int w, unsigned hsub, int left, int right)
335 {
336 84692 unsigned asrc = alpha * src;
337 84692 unsigned tau = 0x1010101 - alpha;
338
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84692 times.
84692 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 6873922 times.
✓ Branch 1 taken 84692 times.
6958614 for (int x = 0; x < w; x++) {
345 6873922 *dst = (*dst * tau + asrc) >> 24;
346 6873922 dst += dx;
347 }
348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84692 times.
84692 if (right) {
349 ✗ unsigned suba = (right * alpha) >> hsub;
350 ✗ *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
351 }
352 84692 }
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 /* the colour as blended: its transparency is already in the coverage, so it covers the alpha plane fully */
379 37325 static FFDrawColor blended_color(FFDrawContext *draw, const FFDrawColor *color)
380 {
381 37325 const AVPixFmtDescriptor *desc = draw->desc;
382 37325 const AVComponentDescriptor *alpha = &desc->comp[desc->nb_components - 1];
383 37325 FFDrawColor over = *color;
384
385
4/4
✓ Branch 0 taken 2559 times.
✓ Branch 1 taken 34766 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2557 times.
37325 if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && draw->flags & FF_DRAW_PROCESS_ALPHA) {
386
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (alpha->depth <= 8)
387 2 over.comp[alpha->plane].u8[alpha->offset] = 0xFF;
388 else
389 ✗ over.comp[alpha->plane].u16[alpha->offset / 2] = (1 << alpha->depth) - 1;
390 }
391 37325 return over;
392 }
393
394 1169 void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
395 uint8_t *dst[], int dst_linesize[],
396 int dst_w, int dst_h,
397 int x0, int y0, int w, int h)
398 {
399 1169 FFDrawColor over = blended_color(draw, color);
400 unsigned alpha, nb_planes, nb_comp;
401 int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom;
402 uint8_t *p0, *p;
403
404 2338 nb_comp = draw->desc->nb_components -
405
4/4
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 1095 times.
✓ Branch 2 taken 73 times.
✓ Branch 3 taken 1 times.
1169 !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
406
407 /* TODO optimize if alpha = 0xFF */
408 1169 clip_interval(dst_w, &x0, &w, NULL);
409 1169 clip_interval(dst_h, &y0, &h, NULL);
410
3/6
✓ Branch 0 taken 1169 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1169 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1169 times.
1169 if (w <= 0 || h <= 0 || !color->rgba[3])
411 ✗ return;
412
2/2
✓ Branch 0 taken 1059 times.
✓ Branch 1 taken 110 times.
1169 if (draw->desc->comp[0].depth <= 8) {
413 /* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */
414 1059 alpha = 0x10203 * color->rgba[3] + 0x2;
415 } else {
416 /* 0x101 * alpha is in the [ 2 ; 0x1001] range */
417 110 alpha = 0x101 * color->rgba[3] + 0x2;
418 }
419
4/4
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 1095 times.
✓ Branch 2 taken 73 times.
✓ Branch 3 taken 1 times.
1169 nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
420 1169 nb_planes += !nb_planes;
421
2/2
✓ Branch 0 taken 3191 times.
✓ Branch 1 taken 1169 times.
4360 for (unsigned plane = 0; plane < nb_planes; plane++) {
422 3191 p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
423 3191 w_sub = w;
424 3191 h_sub = h;
425 3191 x_sub = x0;
426 3191 y_sub = y0;
427 3191 subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
428 3191 subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
429
2/2
✓ Branch 0 taken 9574 times.
✓ Branch 1 taken 3191 times.
12765 for (unsigned comp = 0; comp < nb_comp; comp++) {
430 9574 const int depth = draw->desc->comp[comp].depth;
431 9574 const int offset = draw->desc->comp[comp].offset;
432 9574 const int index = offset / ((depth + 7) / 8);
433
434
2/2
✓ Branch 0 taken 6066 times.
✓ Branch 1 taken 3508 times.
9574 if (draw->desc->comp[comp].plane != plane)
435 6066 continue;
436 3508 p = p0 + offset;
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3508 times.
3508 if (top) {
438 ✗ if (depth <= 8) {
439 ✗ blend_line(p, over.comp[plane].u8[index], alpha >> 1,
440 draw->pixelstep[plane], w_sub,
441 ✗ draw->hsub[plane], left, right);
442 } else {
443 ✗ blend_line16(p, over.comp[plane].u16[index], alpha >> 1,
444 draw->pixelstep[plane], w_sub,
445 ✗ draw->hsub[plane], left, right);
446 }
447 ✗ p += dst_linesize[plane];
448 }
449
2/2
✓ Branch 0 taken 3178 times.
✓ Branch 1 taken 330 times.
3508 if (depth <= 8) {
450
2/2
✓ Branch 0 taken 84692 times.
✓ Branch 1 taken 3178 times.
87870 for (int y = 0; y < h_sub; y++) {
451 84692 blend_line(p, over.comp[plane].u8[index], alpha,
452 draw->pixelstep[plane], w_sub,
453 84692 draw->hsub[plane], left, right);
454 84692 p += dst_linesize[plane];
455 }
456 } else {
457
2/2
✓ Branch 0 taken 11880 times.
✓ Branch 1 taken 330 times.
12210 for (int y = 0; y < h_sub; y++) {
458 11880 blend_line16(p, over.comp[plane].u16[index], alpha,
459 draw->pixelstep[plane], w_sub,
460 11880 draw->hsub[plane], left, right);
461 11880 p += dst_linesize[plane];
462 }
463 }
464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3508 times.
3508 if (bottom) {
465 ✗ if (depth <= 8) {
466 ✗ blend_line(p, over.comp[plane].u8[index], alpha >> 1,
467 draw->pixelstep[plane], w_sub,
468 ✗ draw->hsub[plane], left, right);
469 } else {
470 ✗ blend_line16(p, over.comp[plane].u16[index], alpha >> 1,
471 draw->pixelstep[plane], w_sub,
472 ✗ draw->hsub[plane], left, right);
473 }
474 }
475 }
476 }
477 }
478
479 1070080 static void blend_pixel16(uint8_t *dst, unsigned src, unsigned alpha,
480 const uint8_t *mask, int mask_linesize, int l2depth,
481 unsigned w, unsigned h, unsigned shift, unsigned xm0)
482 {
483 1070080 unsigned t = 0;
484 1070080 unsigned xmshf = 3 - l2depth;
485 1070080 unsigned xmmod = 7 >> l2depth;
486 1070080 unsigned mbits = (1 << (1 << l2depth)) - 1;
487 1070080 unsigned mmult = 255 / mbits;
488 1070080 uint16_t value = AV_RL16(dst);
489
490
2/2
✓ Branch 0 taken 1070080 times.
✓ Branch 1 taken 1070080 times.
2140160 for (unsigned y = 0; y < h; y++) {
491 1070080 unsigned xm = xm0;
492
2/2
✓ Branch 0 taken 1605120 times.
✓ Branch 1 taken 1070080 times.
2675200 for (unsigned x = 0; x < w; x++) {
493 1605120 t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
494 1605120 * mmult;
495 1605120 xm++;
496 }
497 1070080 mask += mask_linesize;
498 }
499 1070080 alpha = (t >> shift) * alpha;
500 1070080 AV_WL16(dst, ((0x10001 - alpha) * value + alpha * src) >> 16);
501 1070080 }
502
503 9397804 static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha,
504 const uint8_t *mask, int mask_linesize, int l2depth,
505 unsigned w, unsigned h, unsigned shift, unsigned xm0)
506 {
507 9397804 unsigned t = 0;
508 9397804 unsigned xmshf = 3 - l2depth;
509 9397804 unsigned xmmod = 7 >> l2depth;
510 9397804 unsigned mbits = (1 << (1 << l2depth)) - 1;
511 9397804 unsigned mmult = 255 / mbits;
512
513
2/2
✓ Branch 0 taken 11314660 times.
✓ Branch 1 taken 9397804 times.
20712464 for (unsigned y = 0; y < h; y++) {
514 11314660 unsigned xm = xm0;
515
2/2
✓ Branch 0 taken 15232852 times.
✓ Branch 1 taken 11314660 times.
26547512 for (unsigned x = 0; x < w; x++) {
516 15232852 t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
517 15232852 * mmult;
518 15232852 xm++;
519 }
520 11314660 mask += mask_linesize;
521 }
522 9397804 alpha = (t >> shift) * alpha;
523 9397804 *dst = ((0x1010101 - alpha) * *dst + alpha * src) >> 24;
524 9397804 }
525
526 163680 static void blend_line_hv16(uint8_t *dst, int dst_delta,
527 unsigned src, unsigned alpha,
528 const uint8_t *mask, int mask_linesize, int l2depth, int w,
529 unsigned hsub, unsigned vsub,
530 int xm, int left, int right, int hband)
531 {
532
533
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 163680 times.
163680 if (left) {
534 ✗ blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
535 left, hband, hsub + vsub, xm);
536 ✗ dst += dst_delta;
537 ✗ xm += left;
538 }
539
2/2
✓ Branch 0 taken 1070080 times.
✓ Branch 1 taken 163680 times.
1233760 for (int x = 0; x < w; x++) {
540 1070080 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
541 1070080 1 << hsub, hband, hsub + vsub, xm);
542 1070080 dst += dst_delta;
543 1070080 xm += 1 << hsub;
544 }
545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 163680 times.
163680 if (right)
546 ✗ blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
547 right, hband, hsub + vsub, xm);
548 163680 }
549
550 1159796 static void blend_line_hv(uint8_t *dst, int dst_delta,
551 unsigned src, unsigned alpha,
552 const uint8_t *mask, int mask_linesize, int l2depth, int w,
553 unsigned hsub, unsigned vsub,
554 int xm, int left, int right, int hband)
555 {
556
557
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1159796 times.
1159796 if (left) {
558 ✗ blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
559 left, hband, hsub + vsub, xm);
560 ✗ dst += dst_delta;
561 ✗ xm += left;
562 }
563
2/2
✓ Branch 0 taken 9397804 times.
✓ Branch 1 taken 1159796 times.
10557600 for (int x = 0; x < w; x++) {
564 9397804 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
565 9397804 1 << hsub, hband, hsub + vsub, xm);
566 9397804 dst += dst_delta;
567 9397804 xm += 1 << hsub;
568 }
569
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1159796 times.
1159796 if (right)
570 ✗ blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
571 right, hband, hsub + vsub, xm);
572 1159796 }
573
574 36156 void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color,
575 uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h,
576 const uint8_t *mask, int mask_linesize, int mask_w, int mask_h,
577 int l2depth, unsigned endianness, int x0, int y0)
578 {
579 36156 FFDrawColor over = blended_color(draw, color);
580 unsigned alpha, nb_planes, nb_comp;
581 int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom;
582 uint8_t *p;
583 const uint8_t *m;
584
585 72312 nb_comp = draw->desc->nb_components -
586
4/4
✓ Branch 0 taken 2485 times.
✓ Branch 1 taken 33671 times.
✓ Branch 2 taken 2484 times.
✓ Branch 3 taken 1 times.
36156 !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
587
588 36156 clip_interval(dst_w, &x0, &mask_w, &xm0);
589 36156 clip_interval(dst_h, &y0, &mask_h, &ym0);
590 36156 mask += ym0 * mask_linesize;
591
5/6
✓ Branch 0 taken 35776 times.
✓ Branch 1 taken 380 times.
✓ Branch 2 taken 35762 times.
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 35762 times.
36156 if (mask_w <= 0 || mask_h <= 0 || !color->rgba[3])
592 394 return;
593
2/2
✓ Branch 0 taken 32352 times.
✓ Branch 1 taken 3410 times.
35762 if (draw->desc->comp[0].depth <= 8) {
594 /* alpha is in the [ 0 ; 0x10203 ] range,
595 alpha * mask is in the [ 0 ; 0x1010101 - 4 ] range */
596 32352 alpha = (0x10307 * color->rgba[3] + 0x3) >> 8;
597 } else {
598 3410 alpha = (0x101 * color->rgba[3] + 0x2) >> 8;
599 }
600
4/4
✓ Branch 0 taken 2469 times.
✓ Branch 1 taken 33293 times.
✓ Branch 2 taken 2468 times.
✓ Branch 3 taken 1 times.
35762 nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
601 35762 nb_planes += !nb_planes;
602
2/2
✓ Branch 0 taken 97142 times.
✓ Branch 1 taken 35762 times.
132904 for (unsigned plane = 0; plane < nb_planes; plane++) {
603 97142 uint8_t *p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
604 97142 w_sub = mask_w;
605 97142 h_sub = mask_h;
606 97142 x_sub = x0;
607 97142 y_sub = y0;
608 97142 subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
609 97142 subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
610
2/2
✓ Branch 0 taken 291427 times.
✓ Branch 1 taken 97142 times.
388569 for (unsigned comp = 0; comp < nb_comp; comp++) {
611 291427 const int depth = draw->desc->comp[comp].depth;
612 291427 const int offset = draw->desc->comp[comp].offset;
613 291427 const int index = offset / ((depth + 7) / 8);
614
615
2/2
✓ Branch 0 taken 184140 times.
✓ Branch 1 taken 107287 times.
291427 if (draw->desc->comp[comp].plane != plane)
616 184140 continue;
617 107287 p = p0 + offset;
618 107287 m = mask;
619
2/2
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 106935 times.
107287 if (top) {
620
1/2
✓ Branch 0 taken 352 times.
✗ Branch 1 not taken.
352 if (depth <= 8) {
621 352 blend_line_hv(p, draw->pixelstep[plane],
622 352 over.comp[plane].u8[index], alpha,
623 m, mask_linesize, l2depth, w_sub,
624 352 draw->hsub[plane], draw->vsub[plane],
625 xm0, left, right, top);
626 } else {
627 ✗ blend_line_hv16(p, draw->pixelstep[plane],
628 ✗ over.comp[plane].u16[index], alpha,
629 m, mask_linesize, l2depth, w_sub,
630 ✗ draw->hsub[plane], draw->vsub[plane],
631 xm0, left, right, top);
632 }
633 352 p += dst_linesize[plane];
634 352 m += top * mask_linesize;
635 }
636
2/2
✓ Branch 0 taken 97057 times.
✓ Branch 1 taken 10230 times.
107287 if (depth <= 8) {
637
2/2
✓ Branch 0 taken 1159092 times.
✓ Branch 1 taken 97057 times.
1256149 for (int y = 0; y < h_sub; y++) {
638 1159092 blend_line_hv(p, draw->pixelstep[plane],
639 1159092 over.comp[plane].u8[index], alpha,
640 m, mask_linesize, l2depth, w_sub,
641 1159092 draw->hsub[plane], draw->vsub[plane],
642 1159092 xm0, left, right, 1 << draw->vsub[plane]);
643 1159092 p += dst_linesize[plane];
644 1159092 m += mask_linesize << draw->vsub[plane];
645 }
646 } else {
647
2/2
✓ Branch 0 taken 163680 times.
✓ Branch 1 taken 10230 times.
173910 for (int y = 0; y < h_sub; y++) {
648 163680 blend_line_hv16(p, draw->pixelstep[plane],
649 163680 over.comp[plane].u16[index], alpha,
650 m, mask_linesize, l2depth, w_sub,
651 163680 draw->hsub[plane], draw->vsub[plane],
652 163680 xm0, left, right, 1 << draw->vsub[plane]);
653 163680 p += dst_linesize[plane];
654 163680 m += mask_linesize << draw->vsub[plane];
655 }
656 }
657
2/2
✓ Branch 0 taken 352 times.
✓ Branch 1 taken 106935 times.
107287 if (bottom) {
658
1/2
✓ Branch 0 taken 352 times.
✗ Branch 1 not taken.
352 if (depth <= 8) {
659 352 blend_line_hv(p, draw->pixelstep[plane],
660 352 over.comp[plane].u8[index], alpha,
661 m, mask_linesize, l2depth, w_sub,
662 352 draw->hsub[plane], draw->vsub[plane],
663 xm0, left, right, bottom);
664 } else {
665 ✗ blend_line_hv16(p, draw->pixelstep[plane],
666 ✗ over.comp[plane].u16[index], alpha,
667 m, mask_linesize, l2depth, w_sub,
668 ✗ draw->hsub[plane], draw->vsub[plane],
669 xm0, left, right, bottom);
670 }
671 }
672 }
673 }
674 }
675
676 260158 int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir,
677 int value)
678 {
679
2/2
✓ Branch 0 taken 231826 times.
✓ Branch 1 taken 28332 times.
260158 unsigned shift = sub_dir ? draw->vsub_max : draw->hsub_max;
680
681
2/2
✓ Branch 0 taken 105956 times.
✓ Branch 1 taken 154202 times.
260158 if (!shift)
682 105956 return value;
683
2/2
✓ Branch 0 taken 127754 times.
✓ Branch 1 taken 26448 times.
154202 if (round_dir >= 0)
684
2/2
✓ Branch 0 taken 4376 times.
✓ Branch 1 taken 123378 times.
127754 value += round_dir ? (1 << shift) - 1 : 1 << (shift - 1);
685 154202 return (value >> shift) << shift;
686 }
687
688 255 AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags)
689 {
690 FFDrawContext draw;
691 255 AVFilterFormats *fmts = NULL;
692 int ret;
693
694
2/2
✓ Branch 1 taken 68850 times.
✓ Branch 2 taken 255 times.
69105 for (enum AVPixelFormat i = 0; av_pix_fmt_desc_get(i); i++)
695
3/4
✓ Branch 1 taken 24735 times.
✓ Branch 2 taken 44115 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24735 times.
93585 if (ff_draw_init(&draw, i, flags) >= 0 &&
696 24735 (ret = ff_add_format(&fmts, i)) < 0)
697 ✗ return NULL;
698 255 return fmts;
699 }
700