Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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/mem.h"
  28. #include "libavutil/pixdesc.h"
  29. #include "drawutils.h"
  30. #include "formats.h"
  31.  
  32. enum { RED = 0, GREEN, BLUE, ALPHA };
  33.  
  34. int ff_fill_rgba_map(uint8_t *rgba_map, enum AVPixelFormat pix_fmt)
  35. {
  36.     switch (pix_fmt) {
  37.     case AV_PIX_FMT_0RGB:
  38.     case AV_PIX_FMT_ARGB:  rgba_map[ALPHA] = 0; rgba_map[RED  ] = 1; rgba_map[GREEN] = 2; rgba_map[BLUE ] = 3; break;
  39.     case AV_PIX_FMT_0BGR:
  40.     case AV_PIX_FMT_ABGR:  rgba_map[ALPHA] = 0; rgba_map[BLUE ] = 1; rgba_map[GREEN] = 2; rgba_map[RED  ] = 3; break;
  41.     case AV_PIX_FMT_RGB48LE:
  42.     case AV_PIX_FMT_RGB48BE:
  43.     case AV_PIX_FMT_RGBA64BE:
  44.     case AV_PIX_FMT_RGBA64LE:
  45.     case AV_PIX_FMT_RGB0:
  46.     case AV_PIX_FMT_RGBA:
  47.     case AV_PIX_FMT_RGB24: rgba_map[RED  ] = 0; rgba_map[GREEN] = 1; rgba_map[BLUE ] = 2; rgba_map[ALPHA] = 3; break;
  48.     case AV_PIX_FMT_BGR48LE:
  49.     case AV_PIX_FMT_BGR48BE:
  50.     case AV_PIX_FMT_BGRA64BE:
  51.     case AV_PIX_FMT_BGRA64LE:
  52.     case AV_PIX_FMT_BGRA:
  53.     case AV_PIX_FMT_BGR0:
  54.     case AV_PIX_FMT_BGR24: rgba_map[BLUE ] = 0; rgba_map[GREEN] = 1; rgba_map[RED  ] = 2; rgba_map[ALPHA] = 3; break;
  55.     case AV_PIX_FMT_GBRAP:
  56.     case AV_PIX_FMT_GBRP:  rgba_map[GREEN] = 0; rgba_map[BLUE ] = 1; rgba_map[RED  ] = 2; rgba_map[ALPHA] = 3; break;
  57.     default:                    /* unsupported */
  58.         return AVERROR(EINVAL);
  59.     }
  60.     return 0;
  61. }
  62.  
  63. int ff_fill_line_with_color(uint8_t *line[4], int pixel_step[4], int w, uint8_t dst_color[4],
  64.                             enum AVPixelFormat pix_fmt, uint8_t rgba_color[4],
  65.                             int *is_packed_rgba, uint8_t rgba_map_ptr[4])
  66. {
  67.     uint8_t rgba_map[4] = {0};
  68.     int i;
  69.     const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(pix_fmt);
  70.     int hsub;
  71.  
  72.     av_assert0(pix_desc);
  73.  
  74.     hsub = pix_desc->log2_chroma_w;
  75.  
  76.     *is_packed_rgba = ff_fill_rgba_map(rgba_map, pix_fmt) >= 0;
  77.  
  78.     if (*is_packed_rgba) {
  79.         pixel_step[0] = (av_get_bits_per_pixel(pix_desc))>>3;
  80.         for (i = 0; i < 4; i++)
  81.             dst_color[rgba_map[i]] = rgba_color[i];
  82.  
  83.         line[0] = av_malloc_array(w, pixel_step[0]);
  84.         if (!line[0])
  85.             return AVERROR(ENOMEM);
  86.         for (i = 0; i < w; i++)
  87.             memcpy(line[0] + i * pixel_step[0], dst_color, pixel_step[0]);
  88.         if (rgba_map_ptr)
  89.             memcpy(rgba_map_ptr, rgba_map, sizeof(rgba_map[0]) * 4);
  90.     } else {
  91.         int plane;
  92.  
  93.         dst_color[0] = RGB_TO_Y_CCIR(rgba_color[0], rgba_color[1], rgba_color[2]);
  94.         dst_color[1] = RGB_TO_U_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0);
  95.         dst_color[2] = RGB_TO_V_CCIR(rgba_color[0], rgba_color[1], rgba_color[2], 0);
  96.         dst_color[3] = rgba_color[3];
  97.  
  98.         for (plane = 0; plane < 4; plane++) {
  99.             int line_size;
  100.             int hsub1 = (plane == 1 || plane == 2) ? hsub : 0;
  101.  
  102.             pixel_step[plane] = 1;
  103.             line_size = FF_CEIL_RSHIFT(w, hsub1) * pixel_step[plane];
  104.             line[plane] = av_malloc(line_size);
  105.             if (!line[plane]) {
  106.                 while(plane && line[plane-1])
  107.                     av_freep(&line[--plane]);
  108.                 return AVERROR(ENOMEM);
  109.             }
  110.             memset(line[plane], dst_color[plane], line_size);
  111.         }
  112.     }
  113.  
  114.     return 0;
  115. }
  116.  
  117. void ff_draw_rectangle(uint8_t *dst[4], int dst_linesize[4],
  118.                        uint8_t *src[4], int pixelstep[4],
  119.                        int hsub, int vsub, int x, int y, int w, int h)
  120. {
  121.     int i, plane;
  122.     uint8_t *p;
  123.  
  124.     for (plane = 0; plane < 4 && dst[plane]; plane++) {
  125.         int hsub1 = plane == 1 || plane == 2 ? hsub : 0;
  126.         int vsub1 = plane == 1 || plane == 2 ? vsub : 0;
  127.         int width  = FF_CEIL_RSHIFT(w, hsub1);
  128.         int height = FF_CEIL_RSHIFT(h, vsub1);
  129.  
  130.         p = dst[plane] + (y >> vsub1) * dst_linesize[plane];
  131.         for (i = 0; i < height; i++) {
  132.             memcpy(p + (x >> hsub1) * pixelstep[plane],
  133.                    src[plane], width * pixelstep[plane]);
  134.             p += dst_linesize[plane];
  135.         }
  136.     }
  137. }
  138.  
  139. void ff_copy_rectangle(uint8_t *dst[4], int dst_linesize[4],
  140.                        uint8_t *src[4], int src_linesize[4], int pixelstep[4],
  141.                        int hsub, int vsub, int x, int y, int y2, int w, int h)
  142. {
  143.     int i, plane;
  144.     uint8_t *p;
  145.  
  146.     for (plane = 0; plane < 4 && dst[plane]; plane++) {
  147.         int hsub1 = plane == 1 || plane == 2 ? hsub : 0;
  148.         int vsub1 = plane == 1 || plane == 2 ? vsub : 0;
  149.         int width  = FF_CEIL_RSHIFT(w, hsub1);
  150.         int height = FF_CEIL_RSHIFT(h, vsub1);
  151.  
  152.         p = dst[plane] + (y >> vsub1) * dst_linesize[plane];
  153.         for (i = 0; i < height; i++) {
  154.             memcpy(p + (x >> hsub1) * pixelstep[plane],
  155.                    src[plane] + src_linesize[plane]*(i+(y2>>vsub1)), width * pixelstep[plane]);
  156.             p += dst_linesize[plane];
  157.         }
  158.     }
  159. }
  160.  
  161. int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
  162. {
  163.     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
  164.     const AVComponentDescriptor *c;
  165.     unsigned i, nb_planes = 0;
  166.     int pixelstep[MAX_PLANES] = { 0 };
  167.  
  168.     if (!desc || !desc->name)
  169.         return AVERROR(EINVAL);
  170.     if (desc->flags & ~(AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PSEUDOPAL | AV_PIX_FMT_FLAG_ALPHA))
  171.         return AVERROR(ENOSYS);
  172.     for (i = 0; i < desc->nb_components; i++) {
  173.         c = &desc->comp[i];
  174.         /* for now, only 8-bits formats */
  175.         if (c->depth_minus1 != 8 - 1)
  176.             return AVERROR(ENOSYS);
  177.         if (c->plane >= MAX_PLANES)
  178.             return AVERROR(ENOSYS);
  179.         /* strange interleaving */
  180.         if (pixelstep[c->plane] != 0 &&
  181.             pixelstep[c->plane] != c->step_minus1 + 1)
  182.             return AVERROR(ENOSYS);
  183.         pixelstep[c->plane] = c->step_minus1 + 1;
  184.         if (pixelstep[c->plane] >= 8)
  185.             return AVERROR(ENOSYS);
  186.         nb_planes = FFMAX(nb_planes, c->plane + 1);
  187.     }
  188.     if ((desc->log2_chroma_w || desc->log2_chroma_h) && nb_planes < 3)
  189.         return AVERROR(ENOSYS); /* exclude NV12 and NV21 */
  190.     memset(draw, 0, sizeof(*draw));
  191.     draw->desc      = desc;
  192.     draw->format    = format;
  193.     draw->nb_planes = nb_planes;
  194.     memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep));
  195.     draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w;
  196.     draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h;
  197.     for (i = 0; i < ((desc->nb_components - 1) | 1); i++)
  198.         draw->comp_mask[desc->comp[i].plane] |=
  199.             1 << (desc->comp[i].offset_plus1 - 1);
  200.     return 0;
  201. }
  202.  
  203. void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
  204. {
  205.     unsigned i;
  206.     uint8_t rgba_map[4];
  207.  
  208.     if (rgba != color->rgba)
  209.         memcpy(color->rgba, rgba, sizeof(color->rgba));
  210.     if ((draw->desc->flags & AV_PIX_FMT_FLAG_RGB) &&
  211.         ff_fill_rgba_map(rgba_map, draw->format) >= 0) {
  212.         if (draw->nb_planes == 1) {
  213.         for (i = 0; i < 4; i++)
  214.             color->comp[0].u8[rgba_map[i]] = rgba[i];
  215.         } else {
  216.             for (i = 0; i < 4; i++)
  217.                 color->comp[rgba_map[i]].u8[0] = rgba[i];
  218.         }
  219.     } else if (draw->nb_planes == 3 || draw->nb_planes == 4) {
  220.         /* assume YUV */
  221.         color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
  222.         color->comp[1].u8[0] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
  223.         color->comp[2].u8[0] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
  224.         color->comp[3].u8[0] = rgba[3];
  225.     } else if (draw->format == AV_PIX_FMT_GRAY8 || draw->format == AV_PIX_FMT_GRAY8A) {
  226.         color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
  227.         color->comp[1].u8[0] = rgba[3];
  228.     } else {
  229.         av_log(NULL, AV_LOG_WARNING,
  230.                "Color conversion not implemented for %s\n", draw->desc->name);
  231.         memset(color, 128, sizeof(*color));
  232.     }
  233. }
  234.  
  235. static uint8_t *pointer_at(FFDrawContext *draw, uint8_t *data[], int linesize[],
  236.                            int plane, int x, int y)
  237. {
  238.     return data[plane] +
  239.            (y >> draw->vsub[plane]) * linesize[plane] +
  240.            (x >> draw->hsub[plane]) * draw->pixelstep[plane];
  241. }
  242.  
  243. void ff_copy_rectangle2(FFDrawContext *draw,
  244.                         uint8_t *dst[], int dst_linesize[],
  245.                         uint8_t *src[], int src_linesize[],
  246.                         int dst_x, int dst_y, int src_x, int src_y,
  247.                         int w, int h)
  248. {
  249.     int plane, y, wp, hp;
  250.     uint8_t *p, *q;
  251.  
  252.     for (plane = 0; plane < draw->nb_planes; plane++) {
  253.         p = pointer_at(draw, src, src_linesize, plane, src_x, src_y);
  254.         q = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
  255.         wp = FF_CEIL_RSHIFT(w, draw->hsub[plane]) * draw->pixelstep[plane];
  256.         hp = FF_CEIL_RSHIFT(h, draw->vsub[plane]);
  257.         for (y = 0; y < hp; y++) {
  258.             memcpy(q, p, wp);
  259.             p += src_linesize[plane];
  260.             q += dst_linesize[plane];
  261.         }
  262.     }
  263. }
  264.  
  265. void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color,
  266.                        uint8_t *dst[], int dst_linesize[],
  267.                        int dst_x, int dst_y, int w, int h)
  268. {
  269.     int plane, x, y, wp, hp;
  270.     uint8_t *p0, *p;
  271.  
  272.     for (plane = 0; plane < draw->nb_planes; plane++) {
  273.         p0 = pointer_at(draw, dst, dst_linesize, plane, dst_x, dst_y);
  274.         wp = FF_CEIL_RSHIFT(w, draw->hsub[plane]);
  275.         hp = FF_CEIL_RSHIFT(h, draw->vsub[plane]);
  276.         if (!hp)
  277.             return;
  278.         p = p0;
  279.         /* copy first line from color */
  280.         for (x = 0; x < wp; x++) {
  281.             memcpy(p, color->comp[plane].u8, draw->pixelstep[plane]);
  282.             p += draw->pixelstep[plane];
  283.         }
  284.         wp *= draw->pixelstep[plane];
  285.         /* copy next lines from first line */
  286.         p = p0 + dst_linesize[plane];
  287.         for (y = 1; y < hp; y++) {
  288.             memcpy(p, p0, wp);
  289.             p += dst_linesize[plane];
  290.         }
  291.     }
  292. }
  293.  
  294. /**
  295.  * Clip interval [x; x+w[ within [0; wmax[.
  296.  * The resulting w may be negative if the final interval is empty.
  297.  * dx, if not null, return the difference between in and out value of x.
  298.  */
  299. static void clip_interval(int wmax, int *x, int *w, int *dx)
  300. {
  301.     if (dx)
  302.         *dx = 0;
  303.     if (*x < 0) {
  304.         if (dx)
  305.             *dx = -*x;
  306.         *w += *x;
  307.         *x = 0;
  308.     }
  309.     if (*x + *w > wmax)
  310.         *w = wmax - *x;
  311. }
  312.  
  313. /**
  314.  * Decompose w pixels starting at x
  315.  * into start + (w starting at x) + end
  316.  * with x and w aligned on multiples of 1<<sub.
  317.  */
  318. static void subsampling_bounds(int sub, int *x, int *w, int *start, int *end)
  319. {
  320.     int mask = (1 << sub) - 1;
  321.  
  322.     *start = (-*x) & mask;
  323.     *x += *start;
  324.     *start = FFMIN(*start, *w);
  325.     *w -= *start;
  326.     *end = *w & mask;
  327.     *w >>= sub;
  328. }
  329.  
  330. static int component_used(FFDrawContext *draw, int plane, int comp)
  331. {
  332.     return (draw->comp_mask[plane] >> comp) & 1;
  333. }
  334.  
  335. /* If alpha is in the [ 0 ; 0x1010101 ] range,
  336.    then alpha * value is in the [ 0 ; 0xFFFFFFFF ] range,
  337.    and >> 24 gives a correct rounding. */
  338. static void blend_line(uint8_t *dst, unsigned src, unsigned alpha,
  339.                        int dx, int w, unsigned hsub, int left, int right)
  340. {
  341.     unsigned asrc = alpha * src;
  342.     unsigned tau = 0x1010101 - alpha;
  343.     int x;
  344.  
  345.     if (left) {
  346.         unsigned suba = (left * alpha) >> hsub;
  347.         *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
  348.         dst += dx;
  349.     }
  350.     for (x = 0; x < w; x++) {
  351.         *dst = (*dst * tau + asrc) >> 24;
  352.         dst += dx;
  353.     }
  354.     if (right) {
  355.         unsigned suba = (right * alpha) >> hsub;
  356.         *dst = (*dst * (0x1010101 - suba) + src * suba) >> 24;
  357.     }
  358. }
  359.  
  360. void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
  361.                         uint8_t *dst[], int dst_linesize[],
  362.                         int dst_w, int dst_h,
  363.                         int x0, int y0, int w, int h)
  364. {
  365.     unsigned alpha, nb_planes, nb_comp, plane, comp;
  366.     int w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y;
  367.     uint8_t *p0, *p;
  368.  
  369.     /* TODO optimize if alpha = 0xFF */
  370.     clip_interval(dst_w, &x0, &w, NULL);
  371.     clip_interval(dst_h, &y0, &h, NULL);
  372.     if (w <= 0 || h <= 0 || !color->rgba[3])
  373.         return;
  374.     /* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */
  375.     alpha = 0x10203 * color->rgba[3] + 0x2;
  376.     nb_planes = (draw->nb_planes - 1) | 1; /* eliminate alpha */
  377.     for (plane = 0; plane < nb_planes; plane++) {
  378.         nb_comp = draw->pixelstep[plane];
  379.         p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
  380.         w_sub = w;
  381.         h_sub = h;
  382.         x_sub = x0;
  383.         y_sub = y0;
  384.         subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
  385.         subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
  386.         for (comp = 0; comp < nb_comp; comp++) {
  387.             if (!component_used(draw, plane, comp))
  388.                 continue;
  389.             p = p0 + comp;
  390.             if (top) {
  391.                 blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
  392.                            draw->pixelstep[plane], w_sub,
  393.                            draw->hsub[plane], left, right);
  394.                 p += dst_linesize[plane];
  395.             }
  396.             for (y = 0; y < h_sub; y++) {
  397.                 blend_line(p, color->comp[plane].u8[comp], alpha,
  398.                            draw->pixelstep[plane], w_sub,
  399.                            draw->hsub[plane], left, right);
  400.                 p += dst_linesize[plane];
  401.             }
  402.             if (bottom)
  403.                 blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
  404.                            draw->pixelstep[plane], w_sub,
  405.                            draw->hsub[plane], left, right);
  406.         }
  407.     }
  408. }
  409.  
  410. static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha,
  411.                         uint8_t *mask, int mask_linesize, int l2depth,
  412.                         unsigned w, unsigned h, unsigned shift, unsigned xm0)
  413. {
  414.     unsigned xm, x, y, t = 0;
  415.     unsigned xmshf = 3 - l2depth;
  416.     unsigned xmmod = 7 >> l2depth;
  417.     unsigned mbits = (1 << (1 << l2depth)) - 1;
  418.     unsigned mmult = 255 / mbits;
  419.  
  420.     for (y = 0; y < h; y++) {
  421.         xm = xm0;
  422.         for (x = 0; x < w; x++) {
  423.             t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
  424.                  * mmult;
  425.             xm++;
  426.         }
  427.         mask += mask_linesize;
  428.     }
  429.     alpha = (t >> shift) * alpha;
  430.     *dst = ((0x1010101 - alpha) * *dst + alpha * src) >> 24;
  431. }
  432.  
  433. static void blend_line_hv(uint8_t *dst, int dst_delta,
  434.                           unsigned src, unsigned alpha,
  435.                           uint8_t *mask, int mask_linesize, int l2depth, int w,
  436.                           unsigned hsub, unsigned vsub,
  437.                           int xm, int left, int right, int hband)
  438. {
  439.     int x;
  440.  
  441.     if (left) {
  442.         blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
  443.                     left, hband, hsub + vsub, xm);
  444.         dst += dst_delta;
  445.         xm += left;
  446.     }
  447.     for (x = 0; x < w; x++) {
  448.         blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
  449.                     1 << hsub, hband, hsub + vsub, xm);
  450.         dst += dst_delta;
  451.         xm += 1 << hsub;
  452.     }
  453.     if (right)
  454.         blend_pixel(dst, src, alpha, mask, mask_linesize, l2depth,
  455.                     right, hband, hsub + vsub, xm);
  456. }
  457.  
  458. void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color,
  459.                    uint8_t *dst[], int dst_linesize[], int dst_w, int dst_h,
  460.                    uint8_t *mask,  int mask_linesize, int mask_w, int mask_h,
  461.                    int l2depth, unsigned endianness, int x0, int y0)
  462. {
  463.     unsigned alpha, nb_planes, nb_comp, plane, comp;
  464.     int xm0, ym0, w_sub, h_sub, x_sub, y_sub, left, right, top, bottom, y;
  465.     uint8_t *p0, *p, *m;
  466.  
  467.     clip_interval(dst_w, &x0, &mask_w, &xm0);
  468.     clip_interval(dst_h, &y0, &mask_h, &ym0);
  469.     mask += ym0 * mask_linesize;
  470.     if (mask_w <= 0 || mask_h <= 0 || !color->rgba[3])
  471.         return;
  472.     /* alpha is in the [ 0 ; 0x10203 ] range,
  473.        alpha * mask is in the [ 0 ; 0x1010101 - 4 ] range */
  474.     alpha = (0x10307 * color->rgba[3] + 0x3) >> 8;
  475.     nb_planes = (draw->nb_planes - 1) | 1; /* eliminate alpha */
  476.     for (plane = 0; plane < nb_planes; plane++) {
  477.         nb_comp = draw->pixelstep[plane];
  478.         p0 = pointer_at(draw, dst, dst_linesize, plane, x0, y0);
  479.         w_sub = mask_w;
  480.         h_sub = mask_h;
  481.         x_sub = x0;
  482.         y_sub = y0;
  483.         subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
  484.         subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
  485.         for (comp = 0; comp < nb_comp; comp++) {
  486.             if (!component_used(draw, plane, comp))
  487.                 continue;
  488.             p = p0 + comp;
  489.             m = mask;
  490.             if (top) {
  491.                 blend_line_hv(p, draw->pixelstep[plane],
  492.                               color->comp[plane].u8[comp], alpha,
  493.                               m, mask_linesize, l2depth, w_sub,
  494.                               draw->hsub[plane], draw->vsub[plane],
  495.                               xm0, left, right, top);
  496.                 p += dst_linesize[plane];
  497.                 m += top * mask_linesize;
  498.             }
  499.             for (y = 0; y < h_sub; y++) {
  500.                 blend_line_hv(p, draw->pixelstep[plane],
  501.                               color->comp[plane].u8[comp], alpha,
  502.                               m, mask_linesize, l2depth, w_sub,
  503.                               draw->hsub[plane], draw->vsub[plane],
  504.                               xm0, left, right, 1 << draw->vsub[plane]);
  505.                 p += dst_linesize[plane];
  506.                 m += mask_linesize << draw->vsub[plane];
  507.             }
  508.             if (bottom)
  509.                 blend_line_hv(p, draw->pixelstep[plane],
  510.                               color->comp[plane].u8[comp], alpha,
  511.                               m, mask_linesize, l2depth, w_sub,
  512.                               draw->hsub[plane], draw->vsub[plane],
  513.                               xm0, left, right, bottom);
  514.         }
  515.     }
  516. }
  517.  
  518. int ff_draw_round_to_sub(FFDrawContext *draw, int sub_dir, int round_dir,
  519.                          int value)
  520. {
  521.     unsigned shift = sub_dir ? draw->vsub_max : draw->hsub_max;
  522.  
  523.     if (!shift)
  524.         return value;
  525.     if (round_dir >= 0)
  526.         value += round_dir ? (1 << shift) - 1 : 1 << (shift - 1);
  527.     return (value >> shift) << shift;
  528. }
  529.  
  530. AVFilterFormats *ff_draw_supported_pixel_formats(unsigned flags)
  531. {
  532.     enum AVPixelFormat i;
  533.     FFDrawContext draw;
  534.     AVFilterFormats *fmts = NULL;
  535.  
  536.     for (i = 0; av_pix_fmt_desc_get(i); i++)
  537.         if (ff_draw_init(&draw, i, flags) >= 0)
  538.             ff_add_format(&fmts, i);
  539.     return fmts;
  540. }
  541.  
  542. #ifdef TEST
  543.  
  544. #undef printf
  545.  
  546. int main(void)
  547. {
  548.     enum AVPixelFormat f;
  549.     const AVPixFmtDescriptor *desc;
  550.     FFDrawContext draw;
  551.     FFDrawColor color;
  552.     int r, i;
  553.  
  554.     for (f = 0; av_pix_fmt_desc_get(f); f++) {
  555.         desc = av_pix_fmt_desc_get(f);
  556.         if (!desc->name)
  557.             continue;
  558.         printf("Testing %s...%*s", desc->name,
  559.                (int)(16 - strlen(desc->name)), "");
  560.         r = ff_draw_init(&draw, f, 0);
  561.         if (r < 0) {
  562.             char buf[128];
  563.             av_strerror(r, buf, sizeof(buf));
  564.             printf("no: %s\n", buf);
  565.             continue;
  566.         }
  567.         ff_draw_color(&draw, &color, (uint8_t[]) { 1, 0, 0, 1 });
  568.         for (i = 0; i < sizeof(color); i++)
  569.             if (((uint8_t *)&color)[i] != 128)
  570.                 break;
  571.         if (i == sizeof(color)) {
  572.             printf("fallback color\n");
  573.             continue;
  574.         }
  575.         printf("ok\n");
  576.     }
  577.     return 0;
  578. }
  579.  
  580. #endif
  581.