libswscale/alphablend.c
d0e0757e
 /*
  * Copyright (C) 2015 Michael Niedermayer <michaelni@gmx.at>
  *
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include "swscale_internal.h"
 
 int ff_sws_alphablendaway(SwsContext *c, const uint8_t *src[],
                           int srcStride[], int srcSliceY, int srcSliceH,
                           uint8_t *dst[], int dstStride[])
 {
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->srcFormat);
     int nb_components = desc->nb_components;
     int plane, x, y;
     int plane_count = isGray(c->srcFormat) ? 1 : 3;
5d8e836d
     int sixteen_bits = desc->comp[0].depth >= 9;
     unsigned off    = 1<<(desc->comp[0].depth - 1);
     unsigned shift  = desc->comp[0].depth;
d0e0757e
     unsigned max    = (1<<shift) - 1;
c5ebeaa3
     int target_table[2][3];
87100e82
 
c5ebeaa3
     for (plane = 0; plane < plane_count; plane++) {
         int a = 0, b = 0;
         if (c->alphablend == SWS_ALPHA_BLEND_CHECKERBOARD) {
5d8e836d
             a = (1<<(desc->comp[0].depth - 1))/2;
             b = 3*(1<<(desc->comp[0].depth-1))/2;
c5ebeaa3
         }
5d8e836d
         target_table[0][plane] = plane && !(desc->flags & AV_PIX_FMT_FLAG_RGB) ? 1<<(desc->comp[0].depth - 1) : a;
         target_table[1][plane] = plane && !(desc->flags & AV_PIX_FMT_FLAG_RGB) ? 1<<(desc->comp[0].depth - 1) : b;
c5ebeaa3
     }
d0e0757e
 
     av_assert0(plane_count == nb_components - 1);
     if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) {
         for (plane = 0; plane < plane_count; plane++) {
             int w = plane ? c->chrSrcW : c->srcW;
0f9d46b7
             int x_subsample = plane ? desc->log2_chroma_w: 0;
d0e0757e
             int y_subsample = plane ? desc->log2_chroma_h: 0;
21f94684
             for (y = srcSliceY >> y_subsample; y < AV_CEIL_RSHIFT(srcSliceH, y_subsample); y++) {
0f9d46b7
                 if (x_subsample || y_subsample) {
                     int alpha;
                     unsigned u;
                     if (sixteen_bits) {
                         ptrdiff_t alpha_step = srcStride[plane_count] >> 1;
7c72a4bb
                         const uint16_t *s = (const uint16_t *)(src[plane      ] +  srcStride[plane      ] * y);
                         const uint16_t *a = (const uint16_t *)(src[plane_count] + (srcStride[plane_count] * y << y_subsample));
                               uint16_t *d = (      uint16_t *)(dst[plane      ] +  dstStride[plane      ] * y);
0f9d46b7
                         if ((!isBE(c->srcFormat)) == !HAVE_BIGENDIAN) {
                             for (x = 0; x < w; x++) {
                                 if (y_subsample) {
                                     alpha = (a[2*x]              + a[2*x + 1] + 2 +
                                              a[2*x + alpha_step] + a[2*x + alpha_step + 1]) >> 2;
                                 } else
                                     alpha = (a[2*x] + a[2*x + 1]) >> 1;
                                 u = s[x]*alpha + target_table[((x^y)>>5)&1][plane]*(max-alpha) + off;
                                 d[x] = av_clip((u + (u >> shift)) >> shift, 0, max);
                             }
                         } else {
                             for (x = 0; x < w; x++) {
                                 if (y_subsample) {
                                     alpha = (av_bswap16(a[2*x])              + av_bswap16(a[2*x + 1]) + 2 +
                                              av_bswap16(a[2*x + alpha_step]) + av_bswap16(a[2*x + alpha_step + 1])) >> 2;
                                 } else
                                     alpha = (av_bswap16(a[2*x]) + av_bswap16(a[2*x + 1])) >> 1;
                                 u = av_bswap16(s[x])*alpha + target_table[((x^y)>>5)&1][plane]*(max-alpha) + off;
                                 d[x] = av_clip((u + (u >> shift)) >> shift, 0, max);
                             }
                         }
                     } else {
                         ptrdiff_t alpha_step = srcStride[plane_count];
                         const uint8_t *s = src[plane      ] + srcStride[plane] * y;
                         const uint8_t *a = src[plane_count] + (srcStride[plane_count] * y << y_subsample);
                               uint8_t *d = dst[plane      ] + dstStride[plane] * y;
                         for (x = 0; x < w; x++) {
                             if (y_subsample) {
                                 alpha = (a[2*x]              + a[2*x + 1] + 2 +
                                          a[2*x + alpha_step] + a[2*x + alpha_step + 1]) >> 2;
                             } else
                                 alpha = (a[2*x] + a[2*x + 1]) >> 1;
                             u = s[x]*alpha + target_table[((x^y)>>5)&1][plane]*(255-alpha) + 128;
                             d[x] = (257*u) >> 16;
                         }
                     }
                 } else {
d0e0757e
                 if (sixteen_bits) {
7c72a4bb
                     const uint16_t *s = (const uint16_t *)(src[plane      ] + srcStride[plane      ] * y);
                     const uint16_t *a = (const uint16_t *)(src[plane_count] + srcStride[plane_count] * y);
                           uint16_t *d = (      uint16_t *)(dst[plane      ] + dstStride[plane      ] * y);
f28ba31b
                     if ((!isBE(c->srcFormat)) == !HAVE_BIGENDIAN) {
d0e0757e
                         for (x = 0; x < w; x++) {
c5ebeaa3
                             unsigned u = s[x]*a[x] + target_table[((x^y)>>5)&1][plane]*(max-a[x]) + off;
d0e0757e
                             d[x] = av_clip((u + (u >> shift)) >> shift, 0, max);
                         }
                     } else {
                         for (x = 0; x < w; x++) {
                             unsigned aswap =av_bswap16(a[x]);
c5ebeaa3
                             unsigned u = av_bswap16(s[x])*aswap + target_table[((x^y)>>5)&1][plane]*(max-aswap) + off;
d0e0757e
                             d[x] = av_clip((u + (u >> shift)) >> shift, 0, max);
                         }
                     }
                 } else {
                     const uint8_t *s = src[plane      ] + srcStride[plane] * y;
                     const uint8_t *a = src[plane_count] + srcStride[plane_count] * y;
                           uint8_t *d = dst[plane      ] + dstStride[plane] * y;
                     for (x = 0; x < w; x++) {
c5ebeaa3
                         unsigned u = s[x]*a[x] + target_table[((x^y)>>5)&1][plane]*(255-a[x]) + 128;
d0e0757e
                         d[x] = (257*u) >> 16;
                     }
                 }
0f9d46b7
                 }
d0e0757e
             }
         }
b7faa9d3
     } else {
5d8e836d
         int alpha_pos = desc->comp[plane_count].offset;
b7faa9d3
         int w = c->srcW;
         for (y = srcSliceY; y < srcSliceH; y++) {
             if (sixteen_bits) {
7c72a4bb
                 const uint16_t *s = (const uint16_t *)(src[0] + srcStride[0] * y + 2*!alpha_pos);
                 const uint16_t *a = (const uint16_t *)(src[0] + srcStride[0] * y +    alpha_pos);
eb3cfa7d
                       uint16_t *d = (      uint16_t *)(dst[0] + dstStride[0] * y);
b7faa9d3
                 if ((!isBE(c->srcFormat)) == !HAVE_BIGENDIAN) {
                     for (x = 0; x < w; x++) {
                         for (plane = 0; plane < plane_count; plane++) {
                             int x_index = (plane_count + 1) * x;
c5ebeaa3
                             unsigned u = s[x_index + plane]*a[x_index] + target_table[((x^y)>>5)&1][plane]*(max-a[x_index]) + off;
b7faa9d3
                             d[plane_count*x + plane] = av_clip((u + (u >> shift)) >> shift, 0, max);
                         }
                     }
                 } else {
                     for (x = 0; x < w; x++) {
                         for (plane = 0; plane < plane_count; plane++) {
                             int x_index = (plane_count + 1) * x;
                             unsigned aswap =av_bswap16(a[x_index]);
c5ebeaa3
                             unsigned u = av_bswap16(s[x_index + plane])*aswap + target_table[((x^y)>>5)&1][plane]*(max-aswap) + off;
b7faa9d3
                             d[plane_count*x + plane] = av_clip((u + (u >> shift)) >> shift, 0, max);
                         }
                     }
                 }
             } else {
                 const uint8_t *s = src[0] + srcStride[0] * y + !alpha_pos;
                 const uint8_t *a = src[0] + srcStride[0] * y + alpha_pos;
                       uint8_t *d = dst[0] + dstStride[0] * y;
                 for (x = 0; x < w; x++) {
                     for (plane = 0; plane < plane_count; plane++) {
                         int x_index = (plane_count + 1) * x;
c5ebeaa3
                         unsigned u = s[x_index + plane]*a[x_index] + target_table[((x^y)>>5)&1][plane]*(255-a[x_index]) + 128;
b7faa9d3
                         d[plane_count*x + plane] = (257*u) >> 16;
                     }
                 }
             }
         }
d0e0757e
     }
 
     return 0;
 }