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

Generated by: LCOV version 1.13