LCOV - code coverage report
Current view: top level - src/libavfilter - drawutils.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 246 412 59.7 %
Date: 2017-08-17 10:06:07 Functions: 16 22 72.7 %

          Line data    Source code
       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/colorspace.h"
      27             : #include "libavutil/intreadwrite.h"
      28             : #include "libavutil/mem.h"
      29             : #include "libavutil/pixdesc.h"
      30             : #include "drawutils.h"
      31             : #include "formats.h"
      32             : 
      33             : enum { RED = 0, GREEN, BLUE, ALPHA };
      34             : 
      35       23918 : int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
      36             : {
      37       23918 :     switch (pix_fmt) {
      38           7 :     case AV_PIX_FMT_0RGB:
      39           7 :     case AV_PIX_FMT_ARGB:  rgba_map[ALPHA] = 0; rgba_map[RED  ] = 1; rgba_map[GREEN] = 2; rgba_map[BLUE ] = 3; break;
      40           5 :     case AV_PIX_FMT_0BGR:
      41           5 :     case AV_PIX_FMT_ABGR:  rgba_map[ALPHA] = 0; rgba_map[BLUE ] = 1; rgba_map[GREEN] = 2; rgba_map[RED  ] = 3; break;
      42       23833 :     case AV_PIX_FMT_RGB48LE:
      43             :     case AV_PIX_FMT_RGB48BE:
      44             :     case AV_PIX_FMT_RGBA64BE:
      45             :     case AV_PIX_FMT_RGBA64LE:
      46             :     case AV_PIX_FMT_RGB0:
      47             :     case AV_PIX_FMT_RGBA:
      48       23833 :     case AV_PIX_FMT_RGB24: rgba_map[RED  ] = 0; rgba_map[GREEN] = 1; rgba_map[BLUE ] = 2; rgba_map[ALPHA] = 3; break;
      49          11 :     case AV_PIX_FMT_BGR48LE:
      50             :     case AV_PIX_FMT_BGR48BE:
      51             :     case AV_PIX_FMT_BGRA64BE:
      52             :     case AV_PIX_FMT_BGRA64LE:
      53             :     case AV_PIX_FMT_BGRA:
      54             :     case AV_PIX_FMT_BGR0:
      55          11 :     case AV_PIX_FMT_BGR24: rgba_map[BLUE ] = 0; rgba_map[GREEN] = 1; rgba_map[RED  ] = 2; rgba_map[ALPHA] = 3; break;
      56          28 :     case AV_PIX_FMT_GBRP9LE:
      57             :     case AV_PIX_FMT_GBRP9BE:
      58             :     case AV_PIX_FMT_GBRP10LE:
      59             :     case AV_PIX_FMT_GBRP10BE:
      60             :     case AV_PIX_FMT_GBRP12LE:
      61             :     case AV_PIX_FMT_GBRP12BE:
      62             :     case AV_PIX_FMT_GBRP14LE:
      63             :     case AV_PIX_FMT_GBRP14BE:
      64             :     case AV_PIX_FMT_GBRP16LE:
      65             :     case AV_PIX_FMT_GBRP16BE:
      66             :     case AV_PIX_FMT_GBRAP:
      67             :     case AV_PIX_FMT_GBRAP10LE:
      68             :     case AV_PIX_FMT_GBRAP10BE:
      69             :     case AV_PIX_FMT_GBRAP12LE:
      70             :     case AV_PIX_FMT_GBRAP12BE:
      71             :     case AV_PIX_FMT_GBRAP16LE:
      72             :     case AV_PIX_FMT_GBRAP16BE:
      73          28 :     case AV_PIX_FMT_GBRP:  rgba_map[GREEN] = 0; rgba_map[BLUE ] = 1; rgba_map[RED  ] = 2; rgba_map[ALPHA] = 3; break;
      74          34 :     default:                    /* unsupported */
      75          34 :         return AVERROR(EINVAL);
      76             :     }
      77       23884 :     return 0;
      78             : }
      79             : 
      80           0 : int ff_fill_line_with_color(uint8_t *line[4], int pixel_step[4], int w, uint8_t dst_color[4],
      81             :                             enum AVPixelFormat pix_fmt, uint8_t rgba_color[4],
      82             :                             int *is_packed_rgba, uint8_t rgba_map_ptr[4])
      83             : {
      84           0 :     uint8_t rgba_map[4] = {0};
      85             :     int i;
      86           0 :     const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(pix_fmt);
      87             :     int hsub;
      88             : 
      89           0 :     av_assert0(pix_desc);
      90             : 
      91           0 :     hsub = pix_desc->log2_chroma_w;
      92             : 
      93           0 :     *is_packed_rgba = ff_fill_rgba_map(rgba_map, pix_fmt) >= 0;
      94             : 
      95           0 :     if (*is_packed_rgba) {
      96           0 :         pixel_step[0] = (av_get_bits_per_pixel(pix_desc))>>3;
      97           0 :         for (i = 0; i < 4; i++)
      98           0 :             dst_color[rgba_map[i]] = rgba_color[i];
      99             : 
     100           0 :         line[0] = av_malloc_array(w, pixel_step[0]);
     101           0 :         if (!line[0])
     102           0 :             return AVERROR(ENOMEM);
     103           0 :         for (i = 0; i < w; i++)
     104           0 :             memcpy(line[0] + i * pixel_step[0], dst_color, pixel_step[0]);
     105           0 :         if (rgba_map_ptr)
     106           0 :             memcpy(rgba_map_ptr, rgba_map, sizeof(rgba_map[0]) * 4);
     107             :     } else {
     108             :         int plane;
     109             : 
     110           0 :         dst_color[0] = RGB_TO_Y_CCIR(rgba_color[0], rgba_color[1], rgba_color[2]);
     111           0 :         dst_color[1] = RGB_TO_U_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0);
     112           0 :         dst_color[2] = RGB_TO_V_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0);
     113           0 :         dst_color[3] = rgba_color[3];
     114             : 
     115           0 :         for (plane = 0; plane < 4; plane++) {
     116             :             int line_size;
     117           0 :             int hsub1 = (plane == 1 || plane == 2) ? hsub : 0;
     118             : 
     119           0 :             pixel_step[plane] = 1;
     120           0 :             line_size = AV_CEIL_RSHIFT(w, hsub1) * pixel_step[plane];
     121           0 :             line[plane] = av_malloc(line_size);
     122           0 :             if (!line[plane]) {
     123           0 :                 while(plane && line[plane-1])
     124           0 :                     av_freep(&line[--plane]);
     125           0 :                 return AVERROR(ENOMEM);
     126             :             }
     127           0 :             memset(line[plane], dst_color[plane], line_size);
     128             :         }
     129             :     }
     130             : 
     131           0 :     return 0;
     132             : }
     133             : 
     134           0 : void ff_draw_rectangle(uint8_t *dst[4], int dst_linesize[4],
     135             :                        uint8_t *src[4], int pixelstep[4],
     136             :                        int hsub, int vsub, int x, int y, int w, int h)
     137             : {
     138             :     int i, plane;
     139             :     uint8_t *p;
     140             : 
     141           0 :     for (plane = 0; plane < 4 && dst[plane]; plane++) {
     142           0 :         int hsub1 = plane == 1 || plane == 2 ? hsub : 0;
     143           0 :         int vsub1 = plane == 1 || plane == 2 ? vsub : 0;
     144           0 :         int width  = AV_CEIL_RSHIFT(w, hsub1);
     145           0 :         int height = AV_CEIL_RSHIFT(h, vsub1);
     146             : 
     147           0 :         p = dst[plane] + (y >> vsub1) * dst_linesize[plane];
     148           0 :         for (i = 0; i < height; i++) {
     149           0 :             memcpy(p + (x >> hsub1) * pixelstep[plane],
     150           0 :                    src[plane], width * pixelstep[plane]);
     151           0 :             p += dst_linesize[plane];
     152             :         }
     153             :     }
     154           0 : }
     155             : 
     156           0 : void ff_copy_rectangle(uint8_t *dst[4], int dst_linesize[4],
     157             :                        uint8_t *src[4], int src_linesize[4], int pixelstep[4],
     158             :                        int hsub, int vsub, int x, int y, int y2, int w, int h)
     159             : {
     160             :     int i, plane;
     161             :     uint8_t *p;
     162             : 
     163           0 :     for (plane = 0; plane < 4 && dst[plane]; plane++) {
     164           0 :         int hsub1 = plane == 1 || plane == 2 ? hsub : 0;
     165           0 :         int vsub1 = plane == 1 || plane == 2 ? vsub : 0;
     166           0 :         int width  = AV_CEIL_RSHIFT(w, hsub1);
     167           0 :         int height = AV_CEIL_RSHIFT(h, vsub1);
     168             : 
     169           0 :         p = dst[plane] + (y >> vsub1) * dst_linesize[plane];
     170           0 :         for (i = 0; i < height; i++) {
     171           0 :             memcpy(p + (x >> hsub1) * pixelstep[plane],
     172           0 :                    src[plane] + src_linesize[plane]*(i+(y2>>vsub1)), width * pixelstep[plane]);
     173           0 :             p += dst_linesize[plane];
     174             :         }
     175             :     }
     176           0 : }
     177             : 
     178       34921 : int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
     179             : {
     180       34921 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
     181             :     const AVComponentDescriptor *c;
     182       34921 :     unsigned i, nb_planes = 0;
     183       34921 :     int pixelstep[MAX_PLANES] = { 0 };
     184             : 
     185       34921 :     if (!desc || !desc->name)
     186       16170 :         return AVERROR(EINVAL);
     187       18751 :     if (desc->flags & ~(AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PSEUDOPAL | AV_PIX_FMT_FLAG_ALPHA))
     188        9506 :         return AVERROR(ENOSYS);
     189        9245 :     if (format == AV_PIX_FMT_P010LE || format == AV_PIX_FMT_P010BE)
     190          98 :         return AVERROR(ENOSYS);
     191       32405 :     for (i = 0; i < desc->nb_components; i++) {
     192       25120 :         c = &desc->comp[i];
     193             :         /* for now, only 8-16 bits formats */
     194       25120 :         if (c->depth < 8 || c->depth > 16)
     195         980 :             return AVERROR(ENOSYS);
     196       24140 :         if (desc->flags & AV_PIX_FMT_FLAG_BE)
     197           0 :             return AVERROR(ENOSYS);
     198       24140 :         if (c->plane >= MAX_PLANES)
     199           0 :             return AVERROR(ENOSYS);
     200             :         /* strange interleaving */
     201       28025 :         if (pixelstep[c->plane] != 0 &&
     202        3885 :             pixelstep[c->plane] != c->step)
     203         392 :             return AVERROR(ENOSYS);
     204       24142 :         if (pixelstep[c->plane] == 6 &&
     205         394 :             c->depth == 16)
     206         196 :             return AVERROR(ENOSYS);
     207       23552 :         pixelstep[c->plane] = c->step;
     208       23552 :         if (pixelstep[c->plane] >= 8)
     209         294 :             return AVERROR(ENOSYS);
     210       23258 :         nb_planes = FFMAX(nb_planes, c->plane + 1);
     211             :     }
     212        7285 :     memset(draw, 0, sizeof(*draw));
     213        7285 :     draw->desc      = desc;
     214        7285 :     draw->format    = format;
     215        7285 :     draw->nb_planes = nb_planes;
     216        7285 :     draw->flags     = flags;
     217        7285 :     memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep));
     218        7285 :     draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w;
     219        7285 :     draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h;
     220       27754 :     for (i = 0; i < (desc->nb_components - !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(flags & FF_DRAW_PROCESS_ALPHA))); i++)
     221       40938 :         draw->comp_mask[desc->comp[i].plane] |=
     222       20469 :             1 << desc->comp[i].offset;
     223        7285 :     return 0;
     224             : }
     225             : 
     226       65365 : void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
     227             : {
     228             :     unsigned i;
     229             :     uint8_t rgba_map[4];
     230             : 
     231       65365 :     if (rgba != color->rgba)
     232       65365 :         memcpy(color->rgba, rgba, sizeof(color->rgba));
     233       89202 :     if ((draw->desc->flags & AV_PIX_FMT_FLAG_RGB) &&
     234       23837 :         ff_fill_rgba_map(rgba_map, draw->format) >= 0) {
     235       47674 :         if (draw->nb_planes == 1) {
     236      119115 :             for (i = 0; i < 4; i++) {
     237       95292 :                 color->comp[0].u8[rgba_map[i]] = rgba[i];
     238       95292 :                 if (draw->desc->comp[rgba_map[i]].depth > 8) {
     239           0 :                     color->comp[0].u16[rgba_map[i]] = color->comp[0].u8[rgba_map[i]] << 8;
     240             :                 }
     241             :             }
     242             :         } else {
     243          70 :             for (i = 0; i < 4; i++) {
     244          56 :                 color->comp[rgba_map[i]].u8[0] = rgba[i];
     245          56 :                 if (draw->desc->comp[rgba_map[i]].depth > 8)
     246          27 :                     color->comp[rgba_map[i]].u16[0] = color->comp[rgba_map[i]].u8[0] << (draw->desc->comp[rgba_map[i]].depth - 8);
     247             :             }
     248             :         }
     249       41528 :     } else if (draw->nb_planes >= 2) {
     250             :         /* assume YUV */
     251       41520 :         const AVPixFmtDescriptor *desc = draw->desc;
     252       41520 :         color->comp[desc->comp[0].plane].u8[desc->comp[0].offset] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
     253       41520 :         color->comp[desc->comp[1].plane].u8[desc->comp[1].offset] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
     254       41520 :         color->comp[desc->comp[2].plane].u8[desc->comp[2].offset] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
     255       41520 :         color->comp[3].u8[0] = rgba[3];
     256             : #define EXPAND(compn) \
     257             :         if (desc->comp[compn].depth > 8) \
     258             :             color->comp[desc->comp[compn].plane].u16[desc->comp[compn].offset] = \
     259             :             color->comp[desc->comp[compn].plane].u8[desc->comp[compn].offset] << \
     260             :                 (draw->desc->comp[compn].depth + draw->desc->comp[compn].shift - 8)
     261       41520 :         EXPAND(3);
     262       41520 :         EXPAND(2);
     263       41520 :         EXPAND(1);
     264       41520 :         EXPAND(0);
     265          13 :     } else if (draw->format == AV_PIX_FMT_GRAY8 || draw->format == AV_PIX_FMT_GRAY8A ||
     266          13 :                draw->format == AV_PIX_FMT_GRAY16LE || draw->format == AV_PIX_FMT_YA16LE ||
     267           7 :                draw->format == AV_PIX_FMT_GRAY9LE  ||
     268           5 :                draw->format == AV_PIX_FMT_GRAY10LE ||
     269           9 :                draw->format == AV_PIX_FMT_GRAY12LE) {
     270           7 :         const AVPixFmtDescriptor *desc = draw->desc;
     271           7 :         color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
     272           7 :         EXPAND(0);
     273           7 :         color->comp[1].u8[0] = rgba[3];
     274           7 :         EXPAND(1);
     275             :     } else {
     276           1 :         av_log(NULL, AV_LOG_WARNING,
     277           1 :                "Color conversion not implemented for %s\n", draw->desc->name);
     278           1 :         memset(color, 128, sizeof(*color));
     279             :     }
     280       65365 : }
     281             : 
     282      172274 : static uint8_t *pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[],
     283             :                            int plane, int x, int y)
     284             : {
     285      172274 :     return data[plane] +
     286      344548 :            (y >> draw->vsub[plane]) * linesize[plane] +
     287      172274 :            (x >> draw->hsub[plane]) * draw->pixelstep[plane];
     288             : }
     289             : 
     290          37 : void ff_copy_rectangle2(FFDrawContext *draw,
     291             :                         uint8_t *dst[], int dst_linesize[],
     292             :                         uint8_t *src[], int src_linesize[],
     293             :                         int dst_x, int dst_y, int src_x, int src_y,
     294             :                         int w, int h)
     295             : {
     296             :     int plane, y, wp, hp;
     297             :     uint8_t *p, *q;
     298             : 
     299         148 :     for (plane = 0; plane < draw->nb_planes; plane++) {
     300         111 :         p = pointer_at(draw, src, src_linesize, plane, src_x, src_y);
     301         111 :         q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
     302         111 :         wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]) * draw->pixelstep[plane];
     303         111 :         hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
     304       21423 :         for (y = 0; y < hp; y++) {
     305       21312 :             memcpy(q, p, wp);
     306       21312 :             p += src_linesize[plane];
     307       21312 :             q += dst_linesize[plane];
     308             :         }
     309             :     }
     310          37 : }
     311             : 
     312       66935 : void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color,
     313             :                        uint8_t *dst[], int dst_linesize[],
     314             :                        int dst_x, int dst_y, int w, int h)
     315             : {
     316             :     int plane, x, y, wp, hp;
     317             :     uint8_t *p0, *p;
     318       66935 :     FFDrawColor color_tmp = *color;
     319             : 
     320      220619 :     for (plane = 0; plane < draw->nb_planes; plane++) {
     321      153684 :         p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
     322      153684 :         wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]);
     323      153684 :         hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
     324      153684 :         if (!hp)
     325           0 :             return;
     326      153684 :         p = p0;
     327             : 
     328             :         if (HAVE_BIGENDIAN && draw->desc->comp[0].depth > 8) {
     329             :             for (x = 0; 2*x < draw->pixelstep[plane]; x++)
     330             :                 color_tmp.comp[plane].u16[x] = av_bswap16(color_tmp.comp[plane].u16[x]);
     331             :         }
     332             : 
     333             :         /* copy first line from color */
     334      992122 :         for (x = 0; x < wp; x++) {
     335      838438 :             memcpy(p, color_tmp.comp[plane].u8, draw->pixelstep[plane]);
     336      838438 :             p += draw->pixelstep[plane];
     337             :         }
     338      153684 :         wp *= draw->pixelstep[plane];
     339             :         /* copy next lines from first line */
     340      153684 :         p = p0 + dst_linesize[plane];
     341     3093148 :         for (y = 1; y < hp; y++) {
     342     2939464 :             memcpy(p, p0, wp);
     343     2939464 :             p += dst_linesize[plane];
     344             :         }
     345             :     }
     346             : }
     347             : 
     348             : /**
     349             :  * Clip interval [x; x+w[ within [0; wmax[.
     350             :  * The resulting w may be negative if the final interval is empty.
     351             :  * dx, if not null, return the difference between in and out value of x.
     352             :  */
     353       15232 : static void clip_interval(int wmax, int *x, int *w, int *dx)
     354             : {
     355       15232 :     if (dx)
     356       14756 :         *dx = 0;
     357       15232 :     if (*x < 0) {
     358           0 :         if (dx)
     359           0 :             *dx = -*x;
     360           0 :         *w += *x;
     361           0 :         *x = 0;
     362             :     }
     363       15232 :     if (*x + *w > wmax)
     364           0 :         *w = wmax - *x;
     365       15232 : }
     366             : 
     367             : /**
     368             :  * Decompose w pixels starting at x
     369             :  * into start + (w starting at x) + end
     370             :  * with x and w aligned on multiples of 1<<sub.
     371             :  */
     372       36736 : static void subsampling_bounds(int sub, int *x, int *w, int *start, int *end)
     373             : {
     374       36736 :     int mask = (1 << sub) - 1;
     375             : 
     376       36736 :     *start = (-*x) & mask;
     377       36736 :     *x += *start;
     378       36736 :     *start = FFMIN(*start, *w);
     379       36736 :     *w -= *start;
     380       36736 :     *end = *w & mask;
     381       36736 :     *w >>= sub;
     382       36736 : }
     383             : 
     384       22848 : static int component_used(FFDrawContext *draw, int plane, int comp)
     385             : {
     386       22848 :     return (draw->comp_mask[plane] >> comp) & 1;
     387             : }
     388             : 
     389             : /* If alpha is in the [ 0 ; 0x1010101 ] range,
     390             :    then alpha * value is in the [ 0 ; 0xFFFFFFFF ] range,
     391             :    and >> 24 gives a correct rounding. */
     392       22176 : static void blend_line(uint8_t *dst, unsigned src, unsigned alpha,
     393             :                        int dx, int w, unsigned hsub, int left, int right)
     394             : {
     395       22176 :     unsigned asrc = alpha * src;
     396       22176 :     unsigned tau = 0x1010101 - alpha;
     397             :     int x;
     398             : 
     399       22176 :     if (left) {
     400           0 :         unsigned suba = (left * alpha) >> hsub;
     401           0 :         *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
     402           0 :         dst += dx;
     403             :     }
     404     2063376 :     for (x = 0; x < w; x++) {
     405     2041200 :         *dst = (*dst * tau + asrc) >> 24;
     406     2041200 :         dst += dx;
     407             :     }
     408       22176 :     if (right) {
     409           0 :         unsigned suba = (right * alpha) >> hsub;
     410           0 :         *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
     411             :     }
     412       22176 : }
     413             : 
     414           0 : static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha,
     415             :                          int dx, int w, unsigned hsub, int left, int right)
     416             : {
     417           0 :     unsigned asrc = alpha * src;
     418           0 :     unsigned tau = 0x10001 - alpha;
     419             :     int x;
     420             : 
     421           0 :     if (left) {
     422           0 :         unsigned suba = (left * alpha) >> hsub;
     423           0 :         uint16_t value = AV_RL16(dst);
     424           0 :         AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
     425           0 :         dst += dx;
     426             :     }
     427           0 :     for (x = 0; x < w; x++) {
     428           0 :         uint16_t value = AV_RL16(dst);
     429           0 :         AV_WL16(dst, (value * tau + asrc) >> 16);
     430           0 :         dst += dx;
     431             :     }
     432           0 :     if (right) {
     433           0 :         unsigned suba = (right * alpha) >> hsub;
     434           0 :         uint16_t value = AV_RL16(dst);
     435           0 :         AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
     436             :     }
     437           0 : }
     438             : 
     439         238 : void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
     440             :                         uint8_t *dst[], int dst_linesize[],
     441             :                         int dst_w, int dst_h,
     442             :                         int x0, int y0, int w, int h)
     443             : {
     444             :     unsigned alpha, nb_planes, nb_comp, plane, comp;
     445             :     int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y;
     446             :     uint8_t *p0, *p;
     447             : 
     448             :     /* TODO optimize if alpha = 0xFF */
     449         238 :     clip_interval(dst_w, &x0, &w, NULL);
     450         238 :     clip_interval(dst_h, &y0, &h, NULL);
     451         238 :     if (w <= 0 || h <= 0 || !color->rgba[3])
     452           0 :         return;
     453         238 :     if (draw->desc->comp[0].depth <= 8) {
     454             :         /* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */
     455         238 :         alpha = 0x10203 * color->rgba[3] + 0x2;
     456             :     } else {
     457             :         /* 0x101 * alpha is in the [ 2 ; 0x1001] range */
     458           0 :         alpha = 0x101 * color->rgba[3] + 0x2;
     459             :     }
     460         238 :     nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
     461         238 :     nb_planes += !nb_planes;
     462         812 :     for (plane = 0; plane < nb_planes; plane++) {
     463         574 :         nb_comp = draw->pixelstep[plane];
     464         574 :         p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
     465         574 :         w_sub = w;
     466         574 :         h_sub = h;
     467         574 :         x_sub = x0;
     468         574 :         y_sub = y0;
     469         574 :         subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
     470         574 :         subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
     471        1288 :         for (comp = 0; comp < nb_comp; comp++) {
     472         714 :             const int depth = draw->desc->comp[comp].depth;
     473             : 
     474         714 :             if (!component_used(draw, plane, comp))
     475           0 :                 continue;
     476         714 :             p = p0 + comp;
     477         714 :             if (top) {
     478           0 :                 if (depth <= 8) {
     479           0 :                     blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
     480             :                                draw->pixelstep[plane], w_sub,
     481           0 :                                draw->hsub[plane], left, right);
     482             :                 } else {
     483           0 :                     blend_line16(p, color->comp[plane].u16[comp], alpha >> 1,
     484             :                                  draw->pixelstep[plane], w_sub,
     485           0 :                                  draw->hsub[plane], left, right);
     486             :                 }
     487           0 :                 p += dst_linesize[plane];
     488             :             }
     489         714 :             if (depth <= 8) {
     490       22890 :                 for (y = 0; y < h_sub; y++) {
     491       44352 :                     blend_line(p, color->comp[plane].u8[comp], alpha,
     492             :                                draw->pixelstep[plane], w_sub,
     493       22176 :                                draw->hsub[plane], left, right);
     494       22176 :                     p += dst_linesize[plane];
     495             :                 }
     496             :             } else {
     497           0 :                 for (y = 0; y < h_sub; y++) {
     498           0 :                     blend_line16(p, color->comp[plane].u16[comp], alpha,
     499             :                                  draw->pixelstep[plane], w_sub,
     500           0 :                                  draw->hsub[plane], left, right);
     501           0 :                     p += dst_linesize[plane];
     502             :                 }
     503             :             }
     504         714 :             if (bottom) {
     505           0 :                 if (depth <= 8) {
     506           0 :                     blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
     507             :                                draw->pixelstep[plane], w_sub,
     508           0 :                                draw->hsub[plane], left, right);
     509             :                 } else {
     510           0 :                     blend_line16(p, color->comp[plane].u16[comp], alpha >> 1,
     511             :                                  draw->pixelstep[plane], w_sub,
     512           0 :                                  draw->hsub[plane], left, right);
     513             :                 }
     514             :             }
     515             :         }
     516             :     }
     517             : }
     518             : 
     519           0 : static void blend_pixel16(uint8_t *dst, unsigned src, unsigned alpha,
     520             :                           const uint8_t *mask, int mask_linesize, int l2depth,
     521             :                           unsigned w, unsigned h, unsigned shift, unsigned xm0)
     522             : {
     523           0 :     unsigned xm, x, y, t = 0;
     524           0 :     unsigned xmshf = 3 - l2depth;
     525           0 :     unsigned xmmod = 7 >> l2depth;
     526           0 :     unsigned mbits = (1 << (1 << l2depth)) - 1;
     527           0 :     unsigned mmult = 255 / mbits;
     528           0 :     uint16_t value = AV_RL16(dst);
     529             : 
     530           0 :     for (y = 0; y < h; y++) {
     531           0 :         xm = xm0;
     532           0 :         for (x = 0; x < w; x++) {
     533           0 :             t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
     534           0 :                  * mmult;
     535           0 :             xm++;
     536             :         }
     537           0 :         mask += mask_linesize;
     538             :     }
     539           0 :     alpha = (t >> shift) * alpha;
     540           0 :     AV_WL16(dst, ((0x10001 - alpha) * value + alpha * src) >> 16);
     541           0 : }
     542             : 
     543     2757888 : static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha,
     544             :                         const uint8_t *mask, int mask_linesize, int l2depth,
     545             :                         unsigned w, unsigned h, unsigned shift, unsigned xm0)
     546             : {
     547     2757888 :     unsigned xm, x, y, t = 0;
     548     2757888 :     unsigned xmshf = 3 - l2depth;
     549     2757888 :     unsigned xmmod = 7 >> l2depth;
     550     2757888 :     unsigned mbits = (1 << (1 << l2depth)) - 1;
     551     2757888 :     unsigned mmult = 255 / mbits;
     552             : 
     553     5754112 :     for (y = 0; y < h; y++) {
     554     2996224 :         xm = xm0;
     555     6469120 :         for (x = 0; x < w; x++) {
     556     6945792 :             t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
     557     3472896 :                  * mmult;
     558     3472896 :             xm++;
     559             :         }
     560     2996224 :         mask += mask_linesize;
     561             :     }
     562     2757888 :     alpha = (t >> shift) * alpha;
     563     2757888 :     *dst = ((0x1010101 - alpha) * *dst + alpha * src) >> 24;
     564     2757888 : }
     565             : 
     566           0 : static void blend_line_hv16(uint8_t *dst, int dst_delta,
     567             :                             unsigned src, unsigned alpha,
     568             :                             const uint8_t *mask, int mask_linesize, int l2depth, int w,
     569             :                             unsigned hsub, unsigned vsub,
     570             :                             int xm, int left, int right, int hband)
     571             : {
     572             :     int x;
     573             : 
     574           0 :     if (left) {
     575           0 :         blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
     576             :                       left, hband, hsub + vsub, xm);
     577           0 :         dst += dst_delta;
     578           0 :         xm += left;
     579             :     }
     580           0 :     for (x = 0; x < w; x++) {
     581           0 :         blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
     582           0 :                       1 << hsub, hband, hsub + vsub, xm);
     583           0 :         dst += dst_delta;
     584           0 :         xm += 1 << hsub;
     585             :     }
     586           0 :     if (right)
     587           0 :         blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
     588             :                       right, hband, hsub + vsub, xm);
     589           0 : }
     590             : 
     591      305536 : static void blend_line_hv(uint8_t *dst, int dst_delta,
     592             :                           unsigned src, unsigned alpha,
     593             :                           const uint8_t *mask, int mask_linesize, int l2depth, int w,
     594             :                           unsigned hsub, unsigned vsub,
     595             :                           int xm, int left, int right, int hband)
     596             : {
     597             :     int x;
     598             : 
     599      305536 :     if (left) {
     600           0 :         blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
     601             :                     left, hband, hsub + vsub, xm);
     602           0 :         dst += dst_delta;
     603           0 :         xm += left;
     604             :     }
     605     3063424 :     for (x = 0; x < w; x++) {
     606     5515776 :         blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
     607     2757888 :                     1 << hsub, hband, hsub + vsub, xm);
     608     2757888 :         dst += dst_delta;
     609     2757888 :         xm += 1 << hsub;
     610             :     }
     611      305536 :     if (right)
     612           0 :         blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
     613             :                     right, hband, hsub + vsub, xm);
     614      305536 : }
     615             : 
     616        7378 : void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color,
     617             :                    uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h,
     618             :                    const uint8_t *mask,  int mask_linesize, int mask_w, int mask_h,
     619             :                    int l2depth, unsigned endianness, int x0, int y0)
     620             : {
     621             :     unsigned alpha, nb_planes, nb_comp, plane, comp;
     622             :     int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y;
     623             :     uint8_t *p0, *p;
     624             :     const uint8_t *m;
     625             : 
     626        7378 :     clip_interval(dst_w, &x0, &mask_w, &xm0);
     627        7378 :     clip_interval(dst_h, &y0, &mask_h, &ym0);
     628        7378 :     mask += ym0 * mask_linesize;
     629        7378 :     if (mask_w <= 0 || mask_h <= 0 || !color->rgba[3])
     630           0 :         return;
     631        7378 :     if (draw->desc->comp[0].depth <= 8) {
     632             :         /* alpha is in the [ 0 ; 0x10203 ] range,
     633             :            alpha * mask is in the [ 0 ; 0x1010101 - 4 ] range */
     634        7378 :         alpha = (0x10307 * color->rgba[3] + 0x3) >> 8;
     635             :     } else {
     636           0 :         alpha = (0x101 * color->rgba[3] + 0x2) >> 8;
     637             :     }
     638        7378 :     nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
     639        7378 :     nb_planes += !nb_planes;
     640       25172 :     for (plane = 0; plane < nb_planes; plane++) {
     641       17794 :         nb_comp = draw->pixelstep[plane];
     642       17794 :         p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
     643       17794 :         w_sub = mask_w;
     644       17794 :         h_sub = mask_h;
     645       17794 :         x_sub = x0;
     646       17794 :         y_sub = y0;
     647       17794 :         subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
     648       17794 :         subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
     649       39928 :         for (comp = 0; comp < nb_comp; comp++) {
     650       22134 :             const int depth = draw->desc->comp[comp].depth;
     651             : 
     652       22134 :             if (!component_used(draw, plane, comp))
     653           0 :                 continue;
     654       22134 :             p = p0 + comp;
     655       22134 :             m = mask;
     656       22134 :             if (top) {
     657           0 :                 if (depth <= 8) {
     658           0 :                     blend_line_hv(p, draw->pixelstep[plane],
     659           0 :                                   color->comp[plane].u8[comp], alpha,
     660             :                                   m, mask_linesize, l2depth, w_sub,
     661           0 :                                   draw->hsub[plane], draw->vsub[plane],
     662             :                                   xm0, left, right, top);
     663             :                 } else {
     664           0 :                     blend_line_hv16(p, draw->pixelstep[plane],
     665           0 :                                     color->comp[plane].u16[comp], alpha,
     666             :                                     m, mask_linesize, l2depth, w_sub,
     667           0 :                                     draw->hsub[plane], draw->vsub[plane],
     668             :                                     xm0, left, right, top);
     669             :                 }
     670           0 :                 p += dst_linesize[plane];
     671           0 :                 m += top * mask_linesize;
     672             :             }
     673       22134 :             if (depth <= 8) {
     674      327670 :                 for (y = 0; y < h_sub; y++) {
     675     1222144 :                     blend_line_hv(p, draw->pixelstep[plane],
     676      305536 :                                   color->comp[plane].u8[comp], alpha,
     677             :                                   m, mask_linesize, l2depth, w_sub,
     678      611072 :                                   draw->hsub[plane], draw->vsub[plane],
     679      305536 :                                   xm0, left, right, 1 << draw->vsub[plane]);
     680      305536 :                     p += dst_linesize[plane];
     681      305536 :                     m += mask_linesize << draw->vsub[plane];
     682             :                 }
     683             :             } else {
     684           0 :                 for (y = 0; y < h_sub; y++) {
     685           0 :                     blend_line_hv16(p, draw->pixelstep[plane],
     686           0 :                                     color->comp[plane].u16[comp], alpha,
     687             :                                     m, mask_linesize, l2depth, w_sub,
     688           0 :                                     draw->hsub[plane], draw->vsub[plane],
     689           0 :                                     xm0, left, right, 1 << draw->vsub[plane]);
     690           0 :                     p += dst_linesize[plane];
     691           0 :                     m += mask_linesize << draw->vsub[plane];
     692             :                 }
     693             :             }
     694       22134 :             if (bottom) {
     695           0 :                 if (depth <= 8) {
     696           0 :                     blend_line_hv(p, draw->pixelstep[plane],
     697           0 :                                   color->comp[plane].u8[comp], alpha,
     698             :                                   m, mask_linesize, l2depth, w_sub,
     699           0 :                                   draw->hsub[plane], draw->vsub[plane],
     700             :                                   xm0, left, right, bottom);
     701             :                 } else {
     702           0 :                     blend_line_hv16(p, draw->pixelstep[plane],
     703           0 :                                     color->comp[plane].u16[comp], alpha,
     704             :                                     m, mask_linesize, l2depth, w_sub,
     705           0 :                                     draw->hsub[plane], draw->vsub[plane],
     706             :                                     xm0, left, right, bottom);
     707             :                 }
     708             :             }
     709             :         }
     710             :     }
     711             : }
     712             : 
     713       70742 : int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir,
     714             :                          int value)
     715             : {
     716       70742 :     unsigned shift = sub_dir ? draw->vsub_max : draw->hsub_max;
     717             : 
     718       70742 :     if (!shift)
     719       50855 :         return value;
     720       19887 :     if (round_dir >= 0)
     721       16758 :         value += round_dir ? (1 << shift) - 1 : 1 << (shift - 1);
     722       19887 :     return (value >> shift) << shift;
     723             : }
     724             : 
     725          98 : AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags)
     726             : {
     727             :     enum AVPixelFormat i;
     728             :     FFDrawContext draw;
     729          98 :     AVFilterFormats *fmts = NULL;
     730             :     int ret;
     731             : 
     732       34888 :     for (i = 0; av_pix_fmt_desc_get(i); i++)
     733       41944 :         if (ff_draw_init(&draw, i, flags) >= 0 &&
     734        7154 :             (ret = ff_add_format(&fmts, i)) < 0)
     735           0 :             return NULL;
     736          98 :     return fmts;
     737             : }

Generated by: LCOV version 1.13