FFmpeg
Loading...
Searching...
No Matches
drawutils.c
Go to the documentation of this file.
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"
28#include "libavutil/pixdesc.h"
29#include "colorspace.h"
30#include "drawutils.h"
31#include "formats.h"
32
33enum { RED = 0, GREEN, BLUE, ALPHA };
34
35static int fill_map(const AVPixFmtDescriptor *desc, uint8_t *map)
36{
39 return AVERROR(EINVAL);
40 av_assert0(desc->nb_components == 3 + !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA));
41 if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) {
43 return AVERROR(EINVAL);
44 map[RED] = desc->comp[0].plane;
45 map[GREEN] = desc->comp[1].plane;
46 map[BLUE] = desc->comp[2].plane;
47 map[ALPHA] = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) ? desc->comp[3].plane : 3;
48 } else {
49 int had0 = 0;
50 unsigned depthb = 0;
51 for (unsigned i = 0; i < desc->nb_components; i++) {
52 /* all components must have same depth in bytes */
53 unsigned db = (desc->comp[i].depth + 7) / 8;
54 unsigned pos = desc->comp[i].offset / db;
55 if (depthb && (depthb != db))
56 return AVERROR(ENOSYS);
57
58 if (desc->comp[i].offset % db)
59 return AVERROR(ENOSYS);
60
61 had0 |= pos == 0;
62 map[i] = pos;
63 depthb = db;
64 }
65
66 if (desc->nb_components == 3)
67 map[ALPHA] = had0 ? 3 : 0;
68 }
69
76
77 return 0;
78}
79
80int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
81{
83 if (!(desc->flags & AV_PIX_FMT_FLAG_RGB))
84 return AVERROR(EINVAL);
85 return fill_map(desc, rgba_map);
86}
87
88int ff_fill_ayuv_map(uint8_t *ayuv_map, enum AVPixelFormat pix_fmt)
89{
91 if (desc->flags & AV_PIX_FMT_FLAG_RGB)
92 return AVERROR(EINVAL);
93 return fill_map(desc, ayuv_map);
94}
95
97 enum AVColorRange range, enum AVAlphaMode alpha, unsigned flags)
98{
100 const AVLumaCoefficients *luma = NULL;
102 unsigned nb_planes = 0;
103 int pixelstep[MAX_PLANES] = { 0 };
104 int depthb = 0;
105
106 if (!desc || !desc->name)
107 return AVERROR(EINVAL);
108 if (desc->flags & AV_PIX_FMT_FLAG_BE)
109 return AVERROR(ENOSYS);
111 return AVERROR(ENOSYS);
112 if (csp == AVCOL_SPC_UNSPECIFIED)
114 if (!(desc->flags & AV_PIX_FMT_FLAG_RGB) && !(luma = av_csp_luma_coeffs_from_avcsp(csp)))
115 return AVERROR(EINVAL);
122 return AVERROR(EINVAL);
123 for (unsigned i = 0; i < desc->nb_components; i++) {
124 int db;
125 c = &desc->comp[i];
126 /* for now, only 8-16 bits formats */
127 if (c->depth < 8 || c->depth > 16)
128 return AVERROR(ENOSYS);
129 if (c->plane >= MAX_PLANES)
130 return AVERROR(ENOSYS);
131 /* data must either be in the high or low bits, never middle */
132 if (c->shift && ((c->shift + c->depth) & 0x7))
133 return AVERROR(ENOSYS);
134 /* mixed >8 and <=8 depth */
135 db = (c->depth + 7) / 8;
136 if (depthb && (depthb != db))
137 return AVERROR(ENOSYS);
138 depthb = db;
139 if (db * (c->offset + 1) > 16)
140 return AVERROR(ENOSYS);
141 if (c->offset % db)
142 return AVERROR(ENOSYS);
143 /* strange interleaving */
144 if (pixelstep[c->plane] != 0 &&
145 pixelstep[c->plane] != c->step)
146 return AVERROR(ENOSYS);
147 pixelstep[c->plane] = c->step;
148 if (pixelstep[c->plane] >= 8)
149 return AVERROR(ENOSYS);
150 nb_planes = FFMAX(nb_planes, c->plane + 1);
151 }
152 memset(draw, 0, sizeof(*draw));
153 draw->desc = desc;
154 draw->format = format;
155 draw->nb_planes = nb_planes;
156 draw->range = range;
157 draw->csp = csp;
158 draw->alpha = alpha;
159 draw->flags = flags;
160 if (luma)
161 ff_fill_rgb2yuv_table(luma, draw->rgb2yuv);
162 memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep));
163 draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w;
164 draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h;
165 return 0;
166}
167
169 unsigned flags)
170{
171 return ff_draw_init2(draw, link->format, link->colorspace, link->color_range, link->alpha_mode, flags);
172}
173
178
179void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
180{
181 double yuvad[4];
182 double rgbad[4];
183 const AVPixFmtDescriptor *desc = draw->desc;
184
185 if (rgba != color->rgba)
186 memcpy(color->rgba, rgba, sizeof(color->rgba));
187
188 memset(color->comp, 0, sizeof(color->comp));
189
190 for (int i = 0; i < 4; i++)
191 rgbad[i] = color->rgba[i] / 255.;
192
193 if (draw->alpha == AVALPHA_MODE_PREMULTIPLIED) {
194 for (int i = 0; i < 3; i++)
195 rgbad[i] *= rgbad[3];
196 }
197
198 if (draw->desc->flags & AV_PIX_FMT_FLAG_RGB)
199 memcpy(yuvad, rgbad, sizeof(double) * 3);
200 else
201 ff_matrix_mul_3x3_vec(yuvad, rgbad, draw->rgb2yuv);
202
203 yuvad[3] = rgbad[3];
204
205 for (int i = 0; i < 3; i++) {
206 int chroma = (!(draw->desc->flags & AV_PIX_FMT_FLAG_RGB) && i > 0);
207 if (draw->range == AVCOL_RANGE_MPEG) {
208 yuvad[i] *= (chroma ? 224. : 219.) / 255.;
209 yuvad[i] += (chroma ? 128. : 16.) / 255.;
210 } else if (chroma) {
211 yuvad[i] += 0.5;
212 }
213 }
214
215 // Ensure we place the alpha appropriately for gray formats
216 if (desc->nb_components <= 2)
217 yuvad[1] = yuvad[3];
218
219 for (unsigned i = 0; i < desc->nb_components; i++) {
220 unsigned val = yuvad[i] * ((1 << (draw->desc->comp[i].depth + draw->desc->comp[i].shift)) - 1) + 0.5;
221 if (desc->comp[i].depth > 8)
222 color->comp[desc->comp[i].plane].u16[desc->comp[i].offset / 2] = val;
223 else
224 color->comp[desc->comp[i].plane].u8[desc->comp[i].offset] = val;
225 }
226}
227
228static uint8_t *pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[],
229 int plane, int x, int y)
230{
231 return data[plane] +
232 (y >> draw->vsub[plane]) * linesize[plane] +
233 (x >> draw->hsub[plane]) * draw->pixelstep[plane];
234}
235
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 for (int plane = 0; plane < draw->nb_planes; plane++) {
246 p = pointer_at(draw, src, src_linesize, plane, src_x, src_y);
247 q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
248 wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]) * draw->pixelstep[plane];
249 hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
250 for (int y = 0; y < hp; y++) {
251 memcpy(q, p, wp);
252 p += src_linesize[plane];
253 q += dst_linesize[plane];
254 }
255 }
256}
257
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 FFDrawColor color_tmp = *color;
265
266 for (int plane = 0; plane < draw->nb_planes; plane++) {
267 p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
268 wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]);
269 hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
270 if (!hp)
271 return;
272 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 for (int x = 0; x < wp; x++) {
281 memcpy(p, color_tmp.comp[plane].u8, draw->pixelstep[plane]);
282 p += draw->pixelstep[plane];
283 }
284 wp *= draw->pixelstep[plane];
285 /* copy next lines from first line */
286 p = p0 + dst_linesize[plane];
287 for (int y = 1; y < hp; y++) {
288 memcpy(p, p0, wp);
289 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 */
299static void clip_interval(int wmax, int *x, int *w, int *dx)
300{
301 if (dx)
302 *dx = 0;
303 if (*x < 0) {
304 if (dx)
305 *dx = -*x;
306 *w += *x;
307 *x = 0;
308 }
309 if (*x + *w > wmax)
310 *w = wmax - *x;
311}
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 */
318static void subsampling_bounds(int sub, int *x, int *w, int *start, int *end)
319{
320 int mask = (1 << sub) - 1;
321
322 *start = (-*x) & mask;
323 *x += *start;
324 *start = FFMIN(*start, *w);
325 *w -= *start;
326 *end = *w & mask;
327 *w >>= sub;
328}
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. */
333static void blend_line(uint8_t *dst, unsigned src, unsigned alpha,
334 int dx, int w, unsigned hsub, int left, int right)
335{
336 unsigned asrc = alpha * src;
337 unsigned tau = 0x1010101 - alpha;
338
339 if (left) {
340 unsigned suba = (left * alpha) >> hsub;
341 *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
342 dst += dx;
343 }
344 for (int x = 0; x < w; x++) {
345 *dst = (*dst * tau + asrc) >> 24;
346 dst += dx;
347 }
348 if (right) {
349 unsigned suba = (right * alpha) >> hsub;
350 *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
351 }
352}
353
354static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha,
355 int dx, int w, unsigned hsub, int left, int right)
356{
357 unsigned asrc = alpha * src;
358 unsigned tau = 0x10001 - alpha;
359
360 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 for (int x = 0; x < w; x++) {
367 uint16_t value = AV_RL16(dst);
368 AV_WL16(dst, (value * tau + asrc) >> 16);
369 dst += dx;
370 }
371 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}
377
378/* the colour as blended: its transparency is already in the coverage, so it covers the alpha plane fully */
380{
381 const AVPixFmtDescriptor *desc = draw->desc;
382 const AVComponentDescriptor *alpha = &desc->comp[desc->nb_components - 1];
383 FFDrawColor over = *color;
384
385 if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && draw->flags & FF_DRAW_PROCESS_ALPHA) {
386 if (alpha->depth <= 8)
387 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 return over;
392}
393
395 uint8_t *dst[], int dst_linesize[],
396 int dst_w, int dst_h,
397 int x0, int y0, int w, int h)
398{
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 nb_comp = draw->desc->nb_components -
405 !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
406
407 /* TODO optimize if alpha = 0xFF */
408 clip_interval(dst_w, &x0, &w, NULL);
409 clip_interval(dst_h, &y0, &h, NULL);
410 if (w <= 0 || h <= 0 || !color->rgba[3])
411 return;
412 if (draw->desc->comp[0].depth <= 8) {
413 /* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */
414 alpha = 0x10203 * color->rgba[3] + 0x2;
415 } else {
416 /* 0x101 * alpha is in the [ 2 ; 0x1001] range */
417 alpha = 0x101 * color->rgba[3] + 0x2;
418 }
419 nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
420 nb_planes += !nb_planes;
421 for (unsigned plane = 0; plane < nb_planes; plane++) {
422 p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
423 w_sub = w;
424 h_sub = h;
425 x_sub = x0;
426 y_sub = y0;
427 subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
428 subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
429 for (unsigned comp = 0; comp < nb_comp; comp++) {
430 const int depth = draw->desc->comp[comp].depth;
431 const int offset = draw->desc->comp[comp].offset;
432 const int index = offset / ((depth + 7) / 8);
433
434 if (draw->desc->comp[comp].plane != plane)
435 continue;
436 p = p0 + offset;
437 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 if (depth <= 8) {
450 for (int y = 0; y < h_sub; y++) {
451 blend_line(p, over.comp[plane].u8[index], alpha,
452 draw->pixelstep[plane], w_sub,
453 draw->hsub[plane], left, right);
454 p += dst_linesize[plane];
455 }
456 } else {
457 for (int y = 0; y < h_sub; y++) {
458 blend_line16(p, over.comp[plane].u16[index], alpha,
459 draw->pixelstep[plane], w_sub,
460 draw->hsub[plane], left, right);
461 p += dst_linesize[plane];
462 }
463 }
464 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
479static 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 unsigned t = 0;
484 unsigned xmshf = 3 - l2depth;
485 unsigned xmmod = 7 >> l2depth;
486 unsigned mbits = (1 << (1 << l2depth)) - 1;
487 unsigned mmult = 255 / mbits;
488 uint16_t value = AV_RL16(dst);
489
490 for (unsigned y = 0; y < h; y++) {
491 unsigned xm = xm0;
492 for (unsigned x = 0; x < w; x++) {
493 t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
494 * mmult;
495 xm++;
496 }
497 mask += mask_linesize;
498 }
499 alpha = (t >> shift) * alpha;
500 AV_WL16(dst, ((0x10001 - alpha) * value + alpha * src) >> 16);
501}
502
503static 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 unsigned t = 0;
508 unsigned xmshf = 3 - l2depth;
509 unsigned xmmod = 7 >> l2depth;
510 unsigned mbits = (1 << (1 << l2depth)) - 1;
511 unsigned mmult = 255 / mbits;
512
513 for (unsigned y = 0; y < h; y++) {
514 unsigned xm = xm0;
515 for (unsigned x = 0; x < w; x++) {
516 t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
517 * mmult;
518 xm++;
519 }
520 mask += mask_linesize;
521 }
522 alpha = (t >> shift) * alpha;
523 *dst = ((0x1010101 - alpha) * *dst + alpha * src) >> 24;
524}
525
526static 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 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 for (int x = 0; x < w; x++) {
540 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
541 1 << hsub, hband, hsub + vsub, xm);
542 dst += dst_delta;
543 xm += 1 << hsub;
544 }
545 if (right)
546 blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
547 right, hband, hsub + vsub, xm);
548}
549
550static 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 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 for (int x = 0; x < w; x++) {
564 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
565 1 << hsub, hband, hsub + vsub, xm);
566 dst += dst_delta;
567 xm += 1 << hsub;
568 }
569 if (right)
570 blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
571 right, hband, hsub + vsub, xm);
572}
573
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{
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 nb_comp = draw->desc->nb_components -
586 !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
587
588 clip_interval(dst_w, &x0, &mask_w, &xm0);
589 clip_interval(dst_h, &y0, &mask_h, &ym0);
590 mask += ym0 * mask_linesize;
591 if (mask_w <= 0 || mask_h <= 0 || !color->rgba[3])
592 return;
593 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 alpha = (0x10307 * color->rgba[3] + 0x3) >> 8;
597 } else {
598 alpha = (0x101 * color->rgba[3] + 0x2) >> 8;
599 }
600 nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
601 nb_planes += !nb_planes;
602 for (unsigned plane = 0; plane < nb_planes; plane++) {
603 uint8_t *p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
604 w_sub = mask_w;
605 h_sub = mask_h;
606 x_sub = x0;
607 y_sub = y0;
608 subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
609 subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
610 for (unsigned comp = 0; comp < nb_comp; comp++) {
611 const int depth = draw->desc->comp[comp].depth;
612 const int offset = draw->desc->comp[comp].offset;
613 const int index = offset / ((depth + 7) / 8);
614
615 if (draw->desc->comp[comp].plane != plane)
616 continue;
617 p = p0 + offset;
618 m = mask;
619 if (top) {
620 if (depth <= 8) {
621 blend_line_hv(p, draw->pixelstep[plane],
622 over.comp[plane].u8[index], alpha,
623 m, mask_linesize, l2depth, w_sub,
624 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 p += dst_linesize[plane];
634 m += top * mask_linesize;
635 }
636 if (depth <= 8) {
637 for (int y = 0; y < h_sub; y++) {
638 blend_line_hv(p, draw->pixelstep[plane],
639 over.comp[plane].u8[index], alpha,
640 m, mask_linesize, l2depth, w_sub,
641 draw->hsub[plane], draw->vsub[plane],
642 xm0, left, right, 1 << draw->vsub[plane]);
643 p += dst_linesize[plane];
644 m += mask_linesize << draw->vsub[plane];
645 }
646 } else {
647 for (int y = 0; y < h_sub; y++) {
648 blend_line_hv16(p, draw->pixelstep[plane],
649 over.comp[plane].u16[index], alpha,
650 m, mask_linesize, l2depth, w_sub,
651 draw->hsub[plane], draw->vsub[plane],
652 xm0, left, right, 1 << draw->vsub[plane]);
653 p += dst_linesize[plane];
654 m += mask_linesize << draw->vsub[plane];
655 }
656 }
657 if (bottom) {
658 if (depth <= 8) {
659 blend_line_hv(p, draw->pixelstep[plane],
660 over.comp[plane].u8[index], alpha,
661 m, mask_linesize, l2depth, w_sub,
662 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
676int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir,
677 int value)
678{
679 unsigned shift = sub_dir ? draw->vsub_max : draw->hsub_max;
680
681 if (!shift)
682 return value;
683 if (round_dir >= 0)
684 value += round_dir ? (1 << shift) - 1 : 1 << (shift - 1);
685 return (value >> shift) << shift;
686}
687
689{
691 AVFilterFormats *fmts = NULL;
692 int ret;
693
694 for (enum AVPixelFormat i = 0; av_pix_fmt_desc_get(i); i++)
695 if (ff_draw_init(&draw, i, flags) >= 0 &&
696 (ret = ff_add_format(&fmts, i)) < 0)
697 return NULL;
698 return fmts;
699}
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
static double val(void *priv, double ch)
Definition aeval.c:77
static const char *const format[]
Definition af_aiir.c:445
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
static int draw(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Convenience header that includes libavutil's core.
static int BS_FUNC left(const BSCTX *bc)
Return the number of the bits left in a buffer.
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define AV_CEIL_RSHIFT(a, b)
Definition common.h:60
#define NULL
Definition coverity.c:32
Colorspace value utility functions for libavutil.
static enum AVPixelFormat pix_fmt
void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h, int x0, int y0, int w, int h)
Blend a rectangle with an uniform color.
Definition drawutils.c:394
static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha, const uint8_t *mask, int mask_linesize, int l2depth, unsigned w, unsigned h, unsigned shift, unsigned xm0)
Definition drawutils.c:503
void ff_copy_rectangle2(FFDrawContext *draw, uint8_t *dst[], int dst_linesize[], uint8_t *src[], int src_linesize[], int dst_x, int dst_y, int src_x, int src_y, int w, int h)
Copy a rectangle from an image to another.
Definition drawutils.c:236
int ff_fill_ayuv_map(uint8_t *ayuv_map, enum AVPixelFormat pix_fmt)
Definition drawutils.c:88
static uint8_t * pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[], int plane, int x, int y)
Definition drawutils.c:228
int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir, int value)
Round a dimension according to subsampling.
Definition drawutils.c:676
static void clip_interval(int wmax, int *x, int *w, int *dx)
Clip interval [x; x+w[ within [0; wmax[.
Definition drawutils.c:299
static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha, int dx, int w, unsigned hsub, int left, int right)
Definition drawutils.c:354
int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
Definition drawutils.c:174
static FFDrawColor blended_color(FFDrawContext *draw, const FFDrawColor *color)
Definition drawutils.c:379
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
Definition drawutils.c:179
static void blend_pixel16(uint8_t *dst, unsigned src, unsigned alpha, const uint8_t *mask, int mask_linesize, int l2depth, unsigned w, unsigned h, unsigned shift, unsigned xm0)
Definition drawutils.c:479
int ff_draw_init2(FFDrawContext *draw, enum AVPixelFormat format, enum AVColorSpace csp, enum AVColorRange range, enum AVAlphaMode alpha, unsigned flags)
Init a draw context.
Definition drawutils.c:96
int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
Definition drawutils.c:80
static void blend_line_hv(uint8_t *dst, int dst_delta, unsigned src, unsigned alpha, const uint8_t *mask, int mask_linesize, int l2depth, int w, unsigned hsub, unsigned vsub, int xm, int left, int right, int hband)
Definition drawutils.c:550
static void subsampling_bounds(int sub, int *x, int *w, int *start, int *end)
Decompose w pixels starting at x into start + (w starting at x) + end with x and w aligned on multipl...
Definition drawutils.c:318
static void blend_line_hv16(uint8_t *dst, int dst_delta, unsigned src, unsigned alpha, const uint8_t *mask, int mask_linesize, int l2depth, int w, unsigned hsub, unsigned vsub, int xm, int left, int right, int hband)
Definition drawutils.c:526
AVFilterFormats * ff_draw_supported_pixel_formats(unsigned flags)
Return the list of pixel formats supported by the draw functions.
Definition drawutils.c:688
void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_x, int dst_y, int w, int h)
Fill a rectangle with an uniform color.
Definition drawutils.c:258
@ ALPHA
Definition drawutils.c:33
static void blend_line(uint8_t *dst, unsigned src, unsigned alpha, int dx, int w, unsigned hsub, int left, int right)
Definition drawutils.c:333
static int fill_map(const AVPixFmtDescriptor *desc, uint8_t *map)
Definition drawutils.c:35
int ff_draw_init_from_link(FFDrawContext *draw, const AVFilterLink *link, unsigned flags)
Init a draw context, taking the format, colorspace and range from the given filter link.
Definition drawutils.c:168
void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h, const uint8_t *mask, int mask_linesize, int mask_w, int mask_h, int l2depth, unsigned endianness, int x0, int y0)
Blend an alpha mask with an uniform color.
Definition drawutils.c:574
misc drawing utilities
#define FF_DRAW_PROCESS_ALPHA
Process alpha pixel component.
Definition drawutils.h:64
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
Definition eamad.c:79
double value
Definition eval.c:102
#define MAX_PLANES
Definition ffv1.h:44
int ff_add_format(AVFilterFormats **avff, int64_t fmt)
Add fmt to the list of media formats contained in *avff.
Definition formats.c:571
#define AVERROR(e)
Definition error.h:45
const struct AVLumaCoefficients * av_csp_luma_coeffs_from_avcsp(enum AVColorSpace csp)
Retrieves the Luma coefficients necessary to construct a conversion matrix from an enum constant desc...
Definition csp.c:58
int index
Definition gxfenc.c:90
const VDPAUPixFmtMap * map
static const int16_t alpha[]
Definition ilbcdata.h:55
#define AV_RL16(p)
#define AV_WL16(p, v)
unsigned offset
Definition libaomenc.c:763
static int shift(int a, int b)
Definition bonk.c:261
void ff_matrix_mul_3x3_vec(double dst[3], const double vec[3], const double mat[3][3])
Definition colorspace.c:66
void ff_fill_rgb2yuv_table(const AVLumaCoefficients *coeffs, double rgb2yuv[3][3])
Definition colorspace.c:125
const char * desc
Definition libsvtav1.c:83
uint8_t w
Definition llvidencdsp.c:39
static const uint16_t mask[17]
Definition lzw.c:38
#define FFMIN(a, b)
Definition macros.h:49
#define FFMAX(a, b)
Definition macros.h:47
enum AVColorRange range
const char data[16]
Definition mxf.c:149
enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc)
Definition pixdesc.c:3479
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3500
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
#define AV_PIX_FMT_FLAG_ALPHA
The pixel format has an alpha channel.
Definition pixdesc.h:147
#define AV_PIX_FMT_FLAG_BITSTREAM
All values of a component are bit-wise packed end to end.
Definition pixdesc.h:124
#define AV_PIX_FMT_FLAG_RGB
The pixel format contains RGB-like data (as opposed to YUV/grayscale).
Definition pixdesc.h:136
#define AV_PIX_FMT_FLAG_HWACCEL
Pixel format is an HW accelerated format.
Definition pixdesc.h:128
#define AV_PIX_FMT_FLAG_PLANAR
At least one pixel component is not in the first data plane.
Definition pixdesc.h:132
#define AV_PIX_FMT_FLAG_BE
Pixel format is big-endian.
Definition pixdesc.h:116
#define AV_PIX_FMT_FLAG_XYZ
The pixel format contains XYZ-like data (as opposed to YUV/RGB/grayscale).
Definition pixdesc.h:163
#define AV_PIX_FMT_FLAG_BAYER
The pixel format is following a Bayer pattern.
Definition pixdesc.h:152
#define AV_PIX_FMT_FLAG_PAL
Pixel format has a palette in data[1], values are indexes in this palette.
Definition pixdesc.h:120
AVColorRange
Visual content value range.
Definition pixfmt.h:748
@ AVCOL_RANGE_MPEG
Narrow or limited range content.
Definition pixfmt.h:766
@ AVCOL_RANGE_UNSPECIFIED
Definition pixfmt.h:749
@ AVCOL_RANGE_JPEG
Full range content.
Definition pixfmt.h:783
AVAlphaMode
Correlation between the alpha channel and color values.
Definition pixfmt.h:816
@ AVALPHA_MODE_UNSPECIFIED
Unknown alpha handling, or no alpha channel.
Definition pixfmt.h:817
@ AVALPHA_MODE_PREMULTIPLIED
Alpha channel is multiplied into color values.
Definition pixfmt.h:818
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_YUVJ440P
planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range
Definition pixfmt.h:107
@ AV_PIX_FMT_YUVJ411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor ...
Definition pixfmt.h:283
@ AV_PIX_FMT_YUVJ422P
planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting col...
Definition pixfmt.h:86
@ AV_PIX_FMT_YUVJ444P
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition pixfmt.h:87
@ AV_PIX_FMT_YUVJ420P
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
Definition pixfmt.h:85
AVColorSpace
YUV colorspace type.
Definition pixfmt.h:706
@ AVCOL_SPC_RGB
order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB), YZX and ST 428-1
Definition pixfmt.h:707
@ AVCOL_SPC_UNSPECIFIED
Definition pixfmt.h:709
@ AVCOL_SPC_SMPTE170M
also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above
Definition pixfmt.h:713
#define av_bswap16
Definition bswap.h:28
unsigned int pos
Definition spdifenc.c:431
A list of supported formats for one end of a filter link.
Definition formats.h:64
Struct containing luma coefficients to be used for RGB to YUV/YCoCg, or similar calculations.
Definition csp.h:48
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
uint16_t u16[8]
Definition drawutils.h:56
union FFDrawColor::@125210232202265035037051142373134026157344251103 comp[MAX_PLANES]
uint8_t u8[16]
Definition drawutils.h:57
#define src
Definition vp8dsp.c:248
#define BLUE
#define RED
#define GREEN
static void hsub(htype *dst, const htype *src, int bins)
Definition vf_median.c:74
static av_always_inline void chroma(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, int column, int mirror, int jobnr, int nb_jobs)
static double c[64]