LCOV - code coverage report
Current view: top level - libavfilter - drawutils.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 302 418 72.2 %
Date: 2018-05-20 11:54:08 Functions: 19 22 86.4 %

          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       50914 : int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
      36             : {
      37       50914 :     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       50825 :     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       50825 :     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          30 :     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          30 :     case AV_PIX_FMT_GBRP:  rgba_map[GREEN] = 0; rgba_map[BLUE ] = 1; rgba_map[RED  ] = 2; rgba_map[ALPHA] = 3; break;
      74          36 :     default:                    /* unsupported */
      75          36 :         return AVERROR(EINVAL);
      76             :     }
      77       50878 :     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       21448 : int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
     179             : {
     180       21448 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
     181             :     const AVComponentDescriptor *c;
     182       21448 :     unsigned i, nb_planes = 0;
     183       21448 :     int pixelstep[MAX_PLANES] = { 0 };
     184       21448 :     int full_range = 0;
     185             : 
     186       21448 :     if (!desc || !desc->name)
     187           0 :         return AVERROR(EINVAL);
     188       21448 :     if (desc->flags & ~(AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | FF_PSEUDOPAL | AV_PIX_FMT_FLAG_ALPHA))
     189       10465 :         return AVERROR(ENOSYS);
     190       10983 :     if (format == AV_PIX_FMT_P010LE || format == AV_PIX_FMT_P010BE || format == AV_PIX_FMT_P016LE || format == AV_PIX_FMT_P016BE)
     191         230 :         return AVERROR(ENOSYS);
     192       10753 :     if (format == AV_PIX_FMT_YUVJ420P || format == AV_PIX_FMT_YUVJ422P || format == AV_PIX_FMT_YUVJ444P ||
     193       10284 :         format == AV_PIX_FMT_YUVJ411P || format == AV_PIX_FMT_YUVJ440P)
     194         586 :         full_range = 1;
     195       37871 :     for (i = 0; i < desc->nb_components; i++) {
     196       29303 :         c = &desc->comp[i];
     197             :         /* for now, only 8-16 bits formats */
     198       29303 :         if (c->depth < 8 || c->depth > 16)
     199        1150 :             return AVERROR(ENOSYS);
     200       28153 :         if (desc->flags & AV_PIX_FMT_FLAG_BE)
     201           0 :             return AVERROR(ENOSYS);
     202       28153 :         if (c->plane >= MAX_PLANES)
     203           0 :             return AVERROR(ENOSYS);
     204             :         /* strange interleaving */
     205       32593 :         if (pixelstep[c->plane] != 0 &&
     206        4440 :             pixelstep[c->plane] != c->step)
     207         460 :             return AVERROR(ENOSYS);
     208       28155 :         if (pixelstep[c->plane] == 6 &&
     209         462 :             c->depth == 16)
     210         230 :             return AVERROR(ENOSYS);
     211       27463 :         pixelstep[c->plane] = c->step;
     212       27463 :         if (pixelstep[c->plane] >= 8)
     213         345 :             return AVERROR(ENOSYS);
     214       27118 :         nb_planes = FFMAX(nb_planes, c->plane + 1);
     215             :     }
     216        8568 :     memset(draw, 0, sizeof(*draw));
     217        8568 :     draw->desc      = desc;
     218        8568 :     draw->format    = format;
     219        8568 :     draw->nb_planes = nb_planes;
     220        8568 :     draw->flags     = flags;
     221        8568 :     draw->full_range = full_range;
     222        8568 :     memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep));
     223        8568 :     draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w;
     224        8568 :     draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h;
     225       32414 :     for (i = 0; i < (desc->nb_components - !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(flags & FF_DRAW_PROCESS_ALPHA))); i++)
     226       47692 :         draw->comp_mask[desc->comp[i].plane] |=
     227       23846 :             1 << desc->comp[i].offset;
     228        8568 :     return 0;
     229             : }
     230             : 
     231      141591 : void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
     232             : {
     233             :     unsigned i;
     234             :     uint8_t rgba_map[4];
     235             : 
     236      141591 :     if (rgba != color->rgba)
     237      141591 :         memcpy(color->rgba, rgba, sizeof(color->rgba));
     238      192418 :     if ((draw->desc->flags & AV_PIX_FMT_FLAG_RGB) &&
     239       50827 :         ff_fill_rgba_map(rgba_map, draw->format) >= 0) {
     240      101654 :         if (draw->nb_planes == 1) {
     241      254065 :             for (i = 0; i < 4; i++) {
     242      203252 :                 color->comp[0].u8[rgba_map[i]] = rgba[i];
     243      203252 :                 if (draw->desc->comp[rgba_map[i]].depth > 8) {
     244           0 :                     color->comp[0].u16[rgba_map[i]] = color->comp[0].u8[rgba_map[i]] << 8;
     245             :                 }
     246             :             }
     247             :         } else {
     248          70 :             for (i = 0; i < 4; i++) {
     249          56 :                 color->comp[rgba_map[i]].u8[0] = rgba[i];
     250          56 :                 if (draw->desc->comp[rgba_map[i]].depth > 8)
     251          27 :                     color->comp[rgba_map[i]].u16[0] = color->comp[rgba_map[i]].u8[0] << (draw->desc->comp[rgba_map[i]].depth - 8);
     252             :             }
     253             :         }
     254       90764 :     } else if (draw->nb_planes >= 2) {
     255             :         /* assume YUV */
     256       90754 :         const AVPixFmtDescriptor *desc = draw->desc;
     257       90754 :         color->comp[desc->comp[0].plane].u8[desc->comp[0].offset] = draw->full_range ? RGB_TO_Y_JPEG(rgba[0], rgba[1], rgba[2]) : RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
     258       90754 :         color->comp[desc->comp[1].plane].u8[desc->comp[1].offset] = draw->full_range ? RGB_TO_U_JPEG(rgba[0], rgba[1], rgba[2]) : RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
     259       90754 :         color->comp[desc->comp[2].plane].u8[desc->comp[2].offset] = draw->full_range ? RGB_TO_V_JPEG(rgba[0], rgba[1], rgba[2]) : RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
     260       90754 :         color->comp[3].u8[0] = rgba[3];
     261             : #define EXPAND(compn) \
     262             :         if (desc->comp[compn].depth > 8) \
     263             :             color->comp[desc->comp[compn].plane].u16[desc->comp[compn].offset] = \
     264             :             color->comp[desc->comp[compn].plane].u8[desc->comp[compn].offset] << \
     265             :                 (draw->desc->comp[compn].depth + draw->desc->comp[compn].shift - 8)
     266       90754 :         EXPAND(3);
     267       90754 :         EXPAND(2);
     268       90754 :         EXPAND(1);
     269       90754 :         EXPAND(0);
     270          16 :     } else if (draw->format == AV_PIX_FMT_GRAY8 || draw->format == AV_PIX_FMT_GRAY8A ||
     271          16 :                draw->format == AV_PIX_FMT_GRAY16LE || draw->format == AV_PIX_FMT_YA16LE ||
     272           9 :                draw->format == AV_PIX_FMT_GRAY9LE  ||
     273           7 :                draw->format == AV_PIX_FMT_GRAY10LE ||
     274           5 :                draw->format == AV_PIX_FMT_GRAY12LE ||
     275          11 :                draw->format == AV_PIX_FMT_GRAY14LE) {
     276           9 :         const AVPixFmtDescriptor *desc = draw->desc;
     277           9 :         color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
     278           9 :         EXPAND(0);
     279           9 :         color->comp[1].u8[0] = rgba[3];
     280           9 :         EXPAND(1);
     281             :     } else {
     282           1 :         av_log(NULL, AV_LOG_WARNING,
     283           1 :                "Color conversion not implemented for %s\n", draw->desc->name);
     284           1 :         memset(color, 128, sizeof(*color));
     285             :     }
     286      141591 : }
     287             : 
     288      375968 : static uint8_t *pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[],
     289             :                            int plane, int x, int y)
     290             : {
     291      375968 :     return data[plane] +
     292      751936 :            (y >> draw->vsub[plane]) * linesize[plane] +
     293      375968 :            (x >> draw->hsub[plane]) * draw->pixelstep[plane];
     294             : }
     295             : 
     296          37 : void ff_copy_rectangle2(FFDrawContext *draw,
     297             :                         uint8_t *dst[], int dst_linesize[],
     298             :                         uint8_t *src[], int src_linesize[],
     299             :                         int dst_x, int dst_y, int src_x, int src_y,
     300             :                         int w, int h)
     301             : {
     302             :     int plane, y, wp, hp;
     303             :     uint8_t *p, *q;
     304             : 
     305         148 :     for (plane = 0; plane < draw->nb_planes; plane++) {
     306         111 :         p = pointer_at(draw, src, src_linesize, plane, src_x, src_y);
     307         111 :         q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
     308         111 :         wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]) * draw->pixelstep[plane];
     309         111 :         hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
     310       21423 :         for (y = 0; y < hp; y++) {
     311       21312 :             memcpy(q, p, wp);
     312       21312 :             p += src_linesize[plane];
     313       21312 :             q += dst_linesize[plane];
     314             :         }
     315             :     }
     316          37 : }
     317             : 
     318      143237 : void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color,
     319             :                        uint8_t *dst[], int dst_linesize[],
     320             :                        int dst_x, int dst_y, int w, int h)
     321             : {
     322             :     int plane, x, y, wp, hp;
     323             :     uint8_t *p0, *p;
     324      143237 :     FFDrawColor color_tmp = *color;
     325             : 
     326      471791 :     for (plane = 0; plane < draw->nb_planes; plane++) {
     327      328554 :         p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
     328      328554 :         wp = AV_CEIL_RSHIFT(w, draw->hsub[plane]);
     329      328554 :         hp = AV_CEIL_RSHIFT(h, draw->vsub[plane]);
     330      328554 :         if (!hp)
     331           0 :             return;
     332      328554 :         p = p0;
     333             : 
     334             :         if (HAVE_BIGENDIAN && draw->desc->comp[0].depth > 8) {
     335             :             for (x = 0; 2*x < draw->pixelstep[plane]; x++)
     336             :                 color_tmp.comp[plane].u16[x] = av_bswap16(color_tmp.comp[plane].u16[x]);
     337             :         }
     338             : 
     339             :         /* copy first line from color */
     340     1690708 :         for (x = 0; x < wp; x++) {
     341     1362154 :             memcpy(p, color_tmp.comp[plane].u8, draw->pixelstep[plane]);
     342     1362154 :             p += draw->pixelstep[plane];
     343             :         }
     344      328554 :         wp *= draw->pixelstep[plane];
     345             :         /* copy next lines from first line */
     346      328554 :         p = p0 + dst_linesize[plane];
     347     6414500 :         for (y = 1; y < hp; y++) {
     348     6085946 :             memcpy(p, p0, wp);
     349     6085946 :             p += dst_linesize[plane];
     350             :         }
     351             :     }
     352             : }
     353             : 
     354             : /**
     355             :  * Clip interval [x; x+w[ within [0; wmax[.
     356             :  * The resulting w may be negative if the final interval is empty.
     357             :  * dx, if not null, return the difference between in and out value of x.
     358             :  */
     359       37848 : static void clip_interval(int wmax, int *x, int *w, int *dx)
     360             : {
     361       37848 :     if (dx)
     362       36664 :         *dx = 0;
     363       37848 :     if (*x < 0) {
     364           0 :         if (dx)
     365           0 :             *dx = -*x;
     366           0 :         *w += *x;
     367           0 :         *x = 0;
     368             :     }
     369       37848 :     if (*x + *w > wmax)
     370           0 :         *w = wmax - *x;
     371       37848 : }
     372             : 
     373             : /**
     374             :  * Decompose w pixels starting at x
     375             :  * into start + (w starting at x) + end
     376             :  * with x and w aligned on multiples of 1<<sub.
     377             :  */
     378       94384 : static void subsampling_bounds(int sub, int *x, int *w, int *start, int *end)
     379             : {
     380       94384 :     int mask = (1 << sub) - 1;
     381             : 
     382       94384 :     *start = (-*x) & mask;
     383       94384 :     *x += *start;
     384       94384 :     *start = FFMIN(*start, *w);
     385       94384 :     *w -= *start;
     386       94384 :     *end = *w & mask;
     387       94384 :     *w >>= sub;
     388       94384 : }
     389             : 
     390       69572 : static int component_used(FFDrawContext *draw, int plane, int comp)
     391             : {
     392       69572 :     return (draw->comp_mask[plane] >> comp) & 1;
     393             : }
     394             : 
     395             : /* If alpha is in the [ 0 ; 0x1010101 ] range,
     396             :    then alpha * value is in the [ 0 ; 0xFFFFFFFF ] range,
     397             :    and >> 24 gives a correct rounding. */
     398       42984 : static void blend_line(uint8_t *dst, unsigned src, unsigned alpha,
     399             :                        int dx, int w, unsigned hsub, int left, int right)
     400             : {
     401       42984 :     unsigned asrc = alpha * src;
     402       42984 :     unsigned tau = 0x1010101 - alpha;
     403             :     int x;
     404             : 
     405       42984 :     if (left) {
     406           0 :         unsigned suba = (left * alpha) >> hsub;
     407           0 :         *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
     408           0 :         dst += dx;
     409             :     }
     410     3851784 :     for (x = 0; x < w; x++) {
     411     3808800 :         *dst = (*dst * tau + asrc) >> 24;
     412     3808800 :         dst += dx;
     413             :     }
     414       42984 :     if (right) {
     415           0 :         unsigned suba = (right * alpha) >> hsub;
     416           0 :         *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
     417             :     }
     418       42984 : }
     419             : 
     420       11880 : static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha,
     421             :                          int dx, int w, unsigned hsub, int left, int right)
     422             : {
     423       11880 :     unsigned asrc = alpha * src;
     424       11880 :     unsigned tau = 0x10001 - alpha;
     425             :     int x;
     426             : 
     427       11880 :     if (left) {
     428           0 :         unsigned suba = (left * alpha) >> hsub;
     429           0 :         uint16_t value = AV_RL16(dst);
     430           0 :         AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
     431           0 :         dst += dx;
     432             :     }
     433      803880 :     for (x = 0; x < w; x++) {
     434      792000 :         uint16_t value = AV_RL16(dst);
     435      792000 :         AV_WL16(dst, (value * tau + asrc) >> 16);
     436      792000 :         dst += dx;
     437             :     }
     438       11880 :     if (right) {
     439           0 :         unsigned suba = (right * alpha) >> hsub;
     440           0 :         uint16_t value = AV_RL16(dst);
     441           0 :         AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
     442             :     }
     443       11880 : }
     444             : 
     445         592 : void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
     446             :                         uint8_t *dst[], int dst_linesize[],
     447             :                         int dst_w, int dst_h,
     448             :                         int x0, int y0, int w, int h)
     449             : {
     450             :     unsigned alpha, nb_planes, nb_comp, plane, comp;
     451             :     int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y;
     452             :     uint8_t *p0, *p;
     453             : 
     454             :     /* TODO optimize if alpha = 0xFF */
     455         592 :     clip_interval(dst_w, &x0, &w, NULL);
     456         592 :     clip_interval(dst_h, &y0, &h, NULL);
     457         592 :     if (w <= 0 || h <= 0 || !color->rgba[3])
     458           0 :         return;
     459         592 :     if (draw->desc->comp[0].depth <= 8) {
     460             :         /* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */
     461         482 :         alpha = 0x10203 * color->rgba[3] + 0x2;
     462             :     } else {
     463             :         /* 0x101 * alpha is in the [ 2 ; 0x1001] range */
     464         110 :         alpha = 0x101 * color->rgba[3] + 0x2;
     465             :     }
     466         592 :     nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
     467         592 :     nb_planes += !nb_planes;
     468        2068 :     for (plane = 0; plane < nb_planes; plane++) {
     469        1476 :         nb_comp = draw->pixelstep[plane];
     470        1476 :         p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
     471        1476 :         w_sub = w;
     472        1476 :         h_sub = h;
     473        1476 :         x_sub = x0;
     474        1476 :         y_sub = y0;
     475        1476 :         subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
     476        1476 :         subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
     477        3652 :         for (comp = 0; comp < nb_comp; comp++) {
     478        2176 :             const int depth = draw->desc->comp[comp].depth;
     479             : 
     480        2176 :             if (!component_used(draw, plane, comp))
     481         400 :                 continue;
     482        1776 :             p = p0 + comp;
     483        1776 :             if (top) {
     484           0 :                 if (depth <= 8) {
     485           0 :                     blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
     486             :                                draw->pixelstep[plane], w_sub,
     487           0 :                                draw->hsub[plane], left, right);
     488             :                 } else {
     489           0 :                     blend_line16(p, color->comp[plane].u16[comp], alpha >> 1,
     490             :                                  draw->pixelstep[plane], w_sub,
     491           0 :                                  draw->hsub[plane], left, right);
     492             :                 }
     493           0 :                 p += dst_linesize[plane];
     494             :             }
     495        1776 :             if (depth <= 8) {
     496       44430 :                 for (y = 0; y < h_sub; y++) {
     497       85968 :                     blend_line(p, color->comp[plane].u8[comp], alpha,
     498             :                                draw->pixelstep[plane], w_sub,
     499       42984 :                                draw->hsub[plane], left, right);
     500       42984 :                     p += dst_linesize[plane];
     501             :                 }
     502             :             } else {
     503       12210 :                 for (y = 0; y < h_sub; y++) {
     504       23760 :                     blend_line16(p, color->comp[plane].u16[comp], alpha,
     505             :                                  draw->pixelstep[plane], w_sub,
     506       11880 :                                  draw->hsub[plane], left, right);
     507       11880 :                     p += dst_linesize[plane];
     508             :                 }
     509             :             }
     510        1776 :             if (bottom) {
     511           0 :                 if (depth <= 8) {
     512           0 :                     blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
     513             :                                draw->pixelstep[plane], w_sub,
     514           0 :                                draw->hsub[plane], left, right);
     515             :                 } else {
     516           0 :                     blend_line16(p, color->comp[plane].u16[comp], alpha >> 1,
     517             :                                  draw->pixelstep[plane], w_sub,
     518           0 :                                  draw->hsub[plane], left, right);
     519             :                 }
     520             :             }
     521             :         }
     522             :     }
     523             : }
     524             : 
     525     1070080 : static void blend_pixel16(uint8_t *dst, unsigned src, unsigned alpha,
     526             :                           const uint8_t *mask, int mask_linesize, int l2depth,
     527             :                           unsigned w, unsigned h, unsigned shift, unsigned xm0)
     528             : {
     529     1070080 :     unsigned xm, x, y, t = 0;
     530     1070080 :     unsigned xmshf = 3 - l2depth;
     531     1070080 :     unsigned xmmod = 7 >> l2depth;
     532     1070080 :     unsigned mbits = (1 << (1 << l2depth)) - 1;
     533     1070080 :     unsigned mmult = 255 / mbits;
     534     1070080 :     uint16_t value = AV_RL16(dst);
     535             : 
     536     2140160 :     for (y = 0; y < h; y++) {
     537     1070080 :         xm = xm0;
     538     2675200 :         for (x = 0; x < w; x++) {
     539     3210240 :             t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
     540     1605120 :                  * mmult;
     541     1605120 :             xm++;
     542             :         }
     543     1070080 :         mask += mask_linesize;
     544             :     }
     545     1070080 :     alpha = (t >> shift) * alpha;
     546     1070080 :     AV_WL16(dst, ((0x10001 - alpha) * value + alpha * src) >> 16);
     547     1070080 : }
     548             : 
     549     5133312 : static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha,
     550             :                         const uint8_t *mask, int mask_linesize, int l2depth,
     551             :                         unsigned w, unsigned h, unsigned shift, unsigned xm0)
     552             : {
     553     5133312 :     unsigned xm, x, y, t = 0;
     554     5133312 :     unsigned xmshf = 3 - l2depth;
     555     5133312 :     unsigned xmmod = 7 >> l2depth;
     556     5133312 :     unsigned mbits = (1 << (1 << l2depth)) - 1;
     557     5133312 :     unsigned mmult = 255 / mbits;
     558             : 
     559    10879488 :     for (y = 0; y < h; y++) {
     560     5746176 :         xm = xm0;
     561    12764160 :         for (x = 0; x < w; x++) {
     562    14035968 :             t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
     563     7017984 :                  * mmult;
     564     7017984 :             xm++;
     565             :         }
     566     5746176 :         mask += mask_linesize;
     567             :     }
     568     5133312 :     alpha = (t >> shift) * alpha;
     569     5133312 :     *dst = ((0x1010101 - alpha) * *dst + alpha * src) >> 24;
     570     5133312 : }
     571             : 
     572      163680 : static void blend_line_hv16(uint8_t *dst, int dst_delta,
     573             :                             unsigned src, unsigned alpha,
     574             :                             const uint8_t *mask, int mask_linesize, int l2depth, int w,
     575             :                             unsigned hsub, unsigned vsub,
     576             :                             int xm, int left, int right, int hband)
     577             : {
     578             :     int x;
     579             : 
     580      163680 :     if (left) {
     581           0 :         blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
     582             :                       left, hband, hsub + vsub, xm);
     583           0 :         dst += dst_delta;
     584           0 :         xm += left;
     585             :     }
     586     1233760 :     for (x = 0; x < w; x++) {
     587     2140160 :         blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
     588     1070080 :                       1 << hsub, hband, hsub + vsub, xm);
     589     1070080 :         dst += dst_delta;
     590     1070080 :         xm += 1 << hsub;
     591             :     }
     592      163680 :     if (right)
     593           0 :         blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
     594             :                       right, hband, hsub + vsub, xm);
     595      163680 : }
     596             : 
     597      591264 : static void blend_line_hv(uint8_t *dst, int dst_delta,
     598             :                           unsigned src, unsigned alpha,
     599             :                           const uint8_t *mask, int mask_linesize, int l2depth, int w,
     600             :                           unsigned hsub, unsigned vsub,
     601             :                           int xm, int left, int right, int hband)
     602             : {
     603             :     int x;
     604             : 
     605      591264 :     if (left) {
     606           0 :         blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
     607             :                     left, hband, hsub + vsub, xm);
     608           0 :         dst += dst_delta;
     609           0 :         xm += left;
     610             :     }
     611     5724576 :     for (x = 0; x < w; x++) {
     612    10266624 :         blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
     613     5133312 :                     1 << hsub, hband, hsub + vsub, xm);
     614     5133312 :         dst += dst_delta;
     615     5133312 :         xm += 1 << hsub;
     616             :     }
     617      591264 :     if (right)
     618           0 :         blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
     619             :                     right, hband, hsub + vsub, xm);
     620      591264 : }
     621             : 
     622       18332 : void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color,
     623             :                    uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h,
     624             :                    const uint8_t *mask,  int mask_linesize, int mask_w, int mask_h,
     625             :                    int l2depth, unsigned endianness, int x0, int y0)
     626             : {
     627             :     unsigned alpha, nb_planes, nb_comp, plane, comp;
     628             :     int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y;
     629             :     uint8_t *p0, *p;
     630             :     const uint8_t *m;
     631             : 
     632       18332 :     clip_interval(dst_w, &x0, &mask_w, &xm0);
     633       18332 :     clip_interval(dst_h, &y0, &mask_h, &ym0);
     634       18332 :     mask += ym0 * mask_linesize;
     635       18332 :     if (mask_w <= 0 || mask_h <= 0 || !color->rgba[3])
     636           0 :         return;
     637       18332 :     if (draw->desc->comp[0].depth <= 8) {
     638             :         /* alpha is in the [ 0 ; 0x10203 ] range,
     639             :            alpha * mask is in the [ 0 ; 0x1010101 - 4 ] range */
     640       14922 :         alpha = (0x10307 * color->rgba[3] + 0x3) >> 8;
     641             :     } else {
     642        3410 :         alpha = (0x101 * color->rgba[3] + 0x2) >> 8;
     643             :     }
     644       18332 :     nb_planes = draw->nb_planes - !!(draw->desc->flags & AV_PIX_FMT_FLAG_ALPHA && !(draw->flags & FF_DRAW_PROCESS_ALPHA));
     645       18332 :     nb_planes += !nb_planes;
     646       64048 :     for (plane = 0; plane < nb_planes; plane++) {
     647       45716 :         nb_comp = draw->pixelstep[plane];
     648       45716 :         p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
     649       45716 :         w_sub = mask_w;
     650       45716 :         h_sub = mask_h;
     651       45716 :         x_sub = x0;
     652       45716 :         y_sub = y0;
     653       45716 :         subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
     654       45716 :         subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
     655      113112 :         for (comp = 0; comp < nb_comp; comp++) {
     656       67396 :             const int depth = draw->desc->comp[comp].depth;
     657             : 
     658       67396 :             if (!component_used(draw, plane, comp))
     659       12400 :                 continue;
     660       54996 :             p = p0 + comp;
     661       54996 :             m = mask;
     662       54996 :             if (top) {
     663           0 :                 if (depth <= 8) {
     664           0 :                     blend_line_hv(p, draw->pixelstep[plane],
     665           0 :                                   color->comp[plane].u8[comp], alpha,
     666             :                                   m, mask_linesize, l2depth, w_sub,
     667           0 :                                   draw->hsub[plane], draw->vsub[plane],
     668             :                                   xm0, left, right, top);
     669             :                 } else {
     670           0 :                     blend_line_hv16(p, draw->pixelstep[plane],
     671           0 :                                     color->comp[plane].u16[comp], alpha,
     672             :                                     m, mask_linesize, l2depth, w_sub,
     673           0 :                                     draw->hsub[plane], draw->vsub[plane],
     674             :                                     xm0, left, right, top);
     675             :                 }
     676           0 :                 p += dst_linesize[plane];
     677           0 :                 m += top * mask_linesize;
     678             :             }
     679       54996 :             if (depth <= 8) {
     680      636030 :                 for (y = 0; y < h_sub; y++) {
     681     2365056 :                     blend_line_hv(p, draw->pixelstep[plane],
     682      591264 :                                   color->comp[plane].u8[comp], alpha,
     683             :                                   m, mask_linesize, l2depth, w_sub,
     684     1182528 :                                   draw->hsub[plane], draw->vsub[plane],
     685      591264 :                                   xm0, left, right, 1 << draw->vsub[plane]);
     686      591264 :                     p += dst_linesize[plane];
     687      591264 :                     m += mask_linesize << draw->vsub[plane];
     688             :                 }
     689             :             } else {
     690      173910 :                 for (y = 0; y < h_sub; y++) {
     691      654720 :                     blend_line_hv16(p, draw->pixelstep[plane],
     692      163680 :                                     color->comp[plane].u16[comp], alpha,
     693             :                                     m, mask_linesize, l2depth, w_sub,
     694      327360 :                                     draw->hsub[plane], draw->vsub[plane],
     695      163680 :                                     xm0, left, right, 1 << draw->vsub[plane]);
     696      163680 :                     p += dst_linesize[plane];
     697      163680 :                     m += mask_linesize << draw->vsub[plane];
     698             :                 }
     699             :             }
     700       54996 :             if (bottom) {
     701           0 :                 if (depth <= 8) {
     702           0 :                     blend_line_hv(p, draw->pixelstep[plane],
     703           0 :                                   color->comp[plane].u8[comp], alpha,
     704             :                                   m, mask_linesize, l2depth, w_sub,
     705           0 :                                   draw->hsub[plane], draw->vsub[plane],
     706             :                                   xm0, left, right, bottom);
     707             :                 } else {
     708           0 :                     blend_line_hv16(p, draw->pixelstep[plane],
     709           0 :                                     color->comp[plane].u16[comp], alpha,
     710             :                                     m, mask_linesize, l2depth, w_sub,
     711           0 :                                     draw->hsub[plane], draw->vsub[plane],
     712             :                                     xm0, left, right, bottom);
     713             :                 }
     714             :             }
     715             :         }
     716             :     }
     717             : }
     718             : 
     719      154434 : int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir,
     720             :                          int value)
     721             : {
     722      154434 :     unsigned shift = sub_dir ? draw->vsub_max : draw->hsub_max;
     723             : 
     724      154434 :     if (!shift)
     725      100691 :         return value;
     726       53743 :     if (round_dir >= 0)
     727       44172 :         value += round_dir ? (1 << shift) - 1 : 1 << (shift - 1);
     728       53743 :     return (value >> shift) << shift;
     729             : }
     730             : 
     731         115 : AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags)
     732             : {
     733             :     enum AVPixelFormat i;
     734             :     FFDrawContext draw;
     735         115 :     AVFilterFormats *fmts = NULL;
     736             :     int ret;
     737             : 
     738       21390 :     for (i = 0; av_pix_fmt_desc_get(i); i++)
     739       29670 :         if (ff_draw_init(&draw, i, flags) >= 0 &&
     740        8395 :             (ret = ff_add_format(&fmts, i)) < 0)
     741           0 :             return NULL;
     742         115 :     return fmts;
     743             : }

Generated by: LCOV version 1.13