Blame src/enc/picture_csp_enc.c

Packit 9c6abc
// Copyright 2014 Google Inc. All Rights Reserved.
Packit 9c6abc
//
Packit 9c6abc
// Use of this source code is governed by a BSD-style license
Packit 9c6abc
// that can be found in the COPYING file in the root of the source
Packit 9c6abc
// tree. An additional intellectual property rights grant can be found
Packit 9c6abc
// in the file PATENTS. All contributing project authors may
Packit 9c6abc
// be found in the AUTHORS file in the root of the source tree.
Packit 9c6abc
// -----------------------------------------------------------------------------
Packit 9c6abc
//
Packit 9c6abc
// WebPPicture utils for colorspace conversion
Packit 9c6abc
//
Packit 9c6abc
// Author: Skal (pascal.massimino@gmail.com)
Packit 9c6abc
Packit 9c6abc
#include <assert.h>
Packit 9c6abc
#include <stdlib.h>
Packit 9c6abc
#include <math.h>
Packit 9c6abc
Packit 9c6abc
#include "src/enc/vp8i_enc.h"
Packit 9c6abc
#include "src/utils/random_utils.h"
Packit 9c6abc
#include "src/utils/utils.h"
Packit 9c6abc
#include "src/dsp/dsp.h"
Packit 9c6abc
#include "src/dsp/lossless.h"
Packit 9c6abc
#include "src/dsp/yuv.h"
Packit 9c6abc
Packit 9c6abc
// Uncomment to disable gamma-compression during RGB->U/V averaging
Packit 9c6abc
#define USE_GAMMA_COMPRESSION
Packit 9c6abc
Packit 9c6abc
// If defined, use table to compute x / alpha.
Packit 9c6abc
#define USE_INVERSE_ALPHA_TABLE
Packit 9c6abc
Packit 9c6abc
#ifdef WORDS_BIGENDIAN
Packit 9c6abc
#define ALPHA_OFFSET 0   // uint32_t 0xff000000 is 0xff,00,00,00 in memory
Packit 9c6abc
#else
Packit 9c6abc
#define ALPHA_OFFSET 3   // uint32_t 0xff000000 is 0x00,00,00,ff in memory
Packit 9c6abc
#endif
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Detection of non-trivial transparency
Packit 9c6abc
Packit 9c6abc
// Returns true if alpha[] has non-0xff values.
Packit 9c6abc
static int CheckNonOpaque(const uint8_t* alpha, int width, int height,
Packit 9c6abc
                          int x_step, int y_step) {
Packit 9c6abc
  if (alpha == NULL) return 0;
Packit 9c6abc
  WebPInitAlphaProcessing();
Packit 9c6abc
  if (x_step == 1) {
Packit 9c6abc
    for (; height-- > 0; alpha += y_step) {
Packit 9c6abc
      if (WebPHasAlpha8b(alpha, width)) return 1;
Packit 9c6abc
    }
Packit 9c6abc
  } else {
Packit 9c6abc
    for (; height-- > 0; alpha += y_step) {
Packit 9c6abc
      if (WebPHasAlpha32b(alpha, width)) return 1;
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
  return 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// Checking for the presence of non-opaque alpha.
Packit 9c6abc
int WebPPictureHasTransparency(const WebPPicture* picture) {
Packit 9c6abc
  if (picture == NULL) return 0;
Packit 9c6abc
  if (!picture->use_argb) {
Packit 9c6abc
    return CheckNonOpaque(picture->a, picture->width, picture->height,
Packit 9c6abc
                          1, picture->a_stride);
Packit 9c6abc
  } else {
Packit 9c6abc
    const int alpha_offset = ALPHA_OFFSET;
Packit 9c6abc
    return CheckNonOpaque((const uint8_t*)picture->argb + alpha_offset,
Packit 9c6abc
                          picture->width, picture->height,
Packit 9c6abc
                          4, picture->argb_stride * sizeof(*picture->argb));
Packit 9c6abc
  }
Packit 9c6abc
  return 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Code for gamma correction
Packit 9c6abc
Packit 9c6abc
#if defined(USE_GAMMA_COMPRESSION)
Packit 9c6abc
Packit 9c6abc
// gamma-compensates loss of resolution during chroma subsampling
Packit 9c6abc
#define kGamma 0.80      // for now we use a different gamma value than kGammaF
Packit 9c6abc
#define kGammaFix 12     // fixed-point precision for linear values
Packit 9c6abc
#define kGammaScale ((1 << kGammaFix) - 1)
Packit 9c6abc
#define kGammaTabFix 7   // fixed-point fractional bits precision
Packit 9c6abc
#define kGammaTabScale (1 << kGammaTabFix)
Packit 9c6abc
#define kGammaTabRounder (kGammaTabScale >> 1)
Packit 9c6abc
#define kGammaTabSize (1 << (kGammaFix - kGammaTabFix))
Packit 9c6abc
Packit 9c6abc
static int kLinearToGammaTab[kGammaTabSize + 1];
Packit 9c6abc
static uint16_t kGammaToLinearTab[256];
Packit 9c6abc
static volatile int kGammaTablesOk = 0;
Packit 9c6abc
Packit 9c6abc
static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {
Packit 9c6abc
  if (!kGammaTablesOk) {
Packit 9c6abc
    int v;
Packit 9c6abc
    const double scale = (double)(1 << kGammaTabFix) / kGammaScale;
Packit 9c6abc
    const double norm = 1. / 255.;
Packit 9c6abc
    for (v = 0; v <= 255; ++v) {
Packit 9c6abc
      kGammaToLinearTab[v] =
Packit 9c6abc
          (uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5);
Packit 9c6abc
    }
Packit 9c6abc
    for (v = 0; v <= kGammaTabSize; ++v) {
Packit 9c6abc
      kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5);
Packit 9c6abc
    }
Packit 9c6abc
    kGammaTablesOk = 1;
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) {
Packit 9c6abc
  return kGammaToLinearTab[v];
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE int Interpolate(int v) {
Packit 9c6abc
  const int tab_pos = v >> (kGammaTabFix + 2);    // integer part
Packit 9c6abc
  const int x = v & ((kGammaTabScale << 2) - 1);  // fractional part
Packit 9c6abc
  const int v0 = kLinearToGammaTab[tab_pos];
Packit 9c6abc
  const int v1 = kLinearToGammaTab[tab_pos + 1];
Packit 9c6abc
  const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x);   // interpolate
Packit 9c6abc
  assert(tab_pos + 1 < kGammaTabSize + 1);
Packit 9c6abc
  return y;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// Convert a linear value 'v' to YUV_FIX+2 fixed-point precision
Packit 9c6abc
// U/V value, suitable for RGBToU/V calls.
Packit 9c6abc
static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
Packit 9c6abc
  const int y = Interpolate(base_value << shift);   // final uplifted value
Packit 9c6abc
  return (y + kGammaTabRounder) >> kGammaTabFix;    // descale
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
#else
Packit 9c6abc
Packit 9c6abc
static void InitGammaTables(void) {}
Packit 9c6abc
static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; }
Packit 9c6abc
static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
Packit 9c6abc
  return (int)(base_value << shift);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
#endif    // USE_GAMMA_COMPRESSION
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// RGB -> YUV conversion
Packit 9c6abc
Packit 9c6abc
static int RGBToY(int r, int g, int b, VP8Random* const rg) {
Packit 9c6abc
  return (rg == NULL) ? VP8RGBToY(r, g, b, YUV_HALF)
Packit 9c6abc
                      : VP8RGBToY(r, g, b, VP8RandomBits(rg, YUV_FIX));
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int RGBToU(int r, int g, int b, VP8Random* const rg) {
Packit 9c6abc
  return (rg == NULL) ? VP8RGBToU(r, g, b, YUV_HALF << 2)
Packit 9c6abc
                      : VP8RGBToU(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int RGBToV(int r, int g, int b, VP8Random* const rg) {
Packit 9c6abc
  return (rg == NULL) ? VP8RGBToV(r, g, b, YUV_HALF << 2)
Packit 9c6abc
                      : VP8RGBToV(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Sharp RGB->YUV conversion
Packit 9c6abc
Packit 9c6abc
static const int kNumIterations = 4;
Packit 9c6abc
static const int kMinDimensionIterativeConversion = 4;
Packit 9c6abc
Packit 9c6abc
// We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some
Packit 9c6abc
// banding sometimes. Better use extra precision.
Packit 9c6abc
#define SFIX 2                // fixed-point precision of RGB and Y/W
Packit 9c6abc
typedef int16_t fixed_t;      // signed type with extra SFIX precision for UV
Packit 9c6abc
typedef uint16_t fixed_y_t;   // unsigned type with extra SFIX precision for W
Packit 9c6abc
Packit 9c6abc
#define SHALF (1 << SFIX >> 1)
Packit 9c6abc
#define MAX_Y_T ((256 << SFIX) - 1)
Packit 9c6abc
#define SROUNDER (1 << (YUV_FIX + SFIX - 1))
Packit 9c6abc
Packit 9c6abc
#if defined(USE_GAMMA_COMPRESSION)
Packit 9c6abc
Packit 9c6abc
// We use tables of different size and precision for the Rec709 / BT2020
Packit 9c6abc
// transfer function.
Packit 9c6abc
#define kGammaF (1./0.45)
Packit 9c6abc
static uint32_t kLinearToGammaTabS[kGammaTabSize + 2];
Packit 9c6abc
#define GAMMA_TO_LINEAR_BITS 14
Packit 9c6abc
static uint32_t kGammaToLinearTabS[MAX_Y_T + 1];   // size scales with Y_FIX
Packit 9c6abc
static volatile int kGammaTablesSOk = 0;
Packit 9c6abc
Packit 9c6abc
static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesS(void) {
Packit 9c6abc
  assert(2 * GAMMA_TO_LINEAR_BITS < 32);  // we use uint32_t intermediate values
Packit 9c6abc
  if (!kGammaTablesSOk) {
Packit 9c6abc
    int v;
Packit 9c6abc
    const double norm = 1. / MAX_Y_T;
Packit 9c6abc
    const double scale = 1. / kGammaTabSize;
Packit 9c6abc
    const double a = 0.09929682680944;
Packit 9c6abc
    const double thresh = 0.018053968510807;
Packit 9c6abc
    const double final_scale = 1 << GAMMA_TO_LINEAR_BITS;
Packit 9c6abc
    for (v = 0; v <= MAX_Y_T; ++v) {
Packit 9c6abc
      const double g = norm * v;
Packit 9c6abc
      double value;
Packit 9c6abc
      if (g <= thresh * 4.5) {
Packit 9c6abc
        value = g / 4.5;
Packit 9c6abc
      } else {
Packit 9c6abc
        const double a_rec = 1. / (1. + a);
Packit 9c6abc
        value = pow(a_rec * (g + a), kGammaF);
Packit 9c6abc
      }
Packit 9c6abc
      kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5);
Packit 9c6abc
    }
Packit 9c6abc
    for (v = 0; v <= kGammaTabSize; ++v) {
Packit 9c6abc
      const double g = scale * v;
Packit 9c6abc
      double value;
Packit 9c6abc
      if (g <= thresh) {
Packit 9c6abc
        value = 4.5 * g;
Packit 9c6abc
      } else {
Packit 9c6abc
        value = (1. + a) * pow(g, 1. / kGammaF) - a;
Packit 9c6abc
      }
Packit 9c6abc
      // we already incorporate the 1/2 rounding constant here
Packit 9c6abc
      kLinearToGammaTabS[v] =
Packit 9c6abc
          (uint32_t)(MAX_Y_T * value) + (1 << GAMMA_TO_LINEAR_BITS >> 1);
Packit 9c6abc
    }
Packit 9c6abc
    // to prevent small rounding errors to cause read-overflow:
Packit 9c6abc
    kLinearToGammaTabS[kGammaTabSize + 1] = kLinearToGammaTabS[kGammaTabSize];
Packit 9c6abc
    kGammaTablesSOk = 1;
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// return value has a fixed-point precision of GAMMA_TO_LINEAR_BITS
Packit 9c6abc
static WEBP_INLINE uint32_t GammaToLinearS(int v) {
Packit 9c6abc
  return kGammaToLinearTabS[v];
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) {
Packit 9c6abc
  // 'value' is in GAMMA_TO_LINEAR_BITS fractional precision
Packit 9c6abc
  const uint32_t v = value * kGammaTabSize;
Packit 9c6abc
  const uint32_t tab_pos = v >> GAMMA_TO_LINEAR_BITS;
Packit 9c6abc
  // fractional part, in GAMMA_TO_LINEAR_BITS fixed-point precision
Packit 9c6abc
  const uint32_t x = v - (tab_pos << GAMMA_TO_LINEAR_BITS);  // fractional part
Packit 9c6abc
  // v0 / v1 are in GAMMA_TO_LINEAR_BITS fixed-point precision (range [0..1])
Packit 9c6abc
  const uint32_t v0 = kLinearToGammaTabS[tab_pos + 0];
Packit 9c6abc
  const uint32_t v1 = kLinearToGammaTabS[tab_pos + 1];
Packit 9c6abc
  // Final interpolation. Note that rounding is already included.
Packit 9c6abc
  const uint32_t v2 = (v1 - v0) * x;    // note: v1 >= v0.
Packit 9c6abc
  const uint32_t result = v0 + (v2 >> GAMMA_TO_LINEAR_BITS);
Packit 9c6abc
  return result;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
#else
Packit 9c6abc
Packit 9c6abc
static void InitGammaTablesS(void) {}
Packit 9c6abc
static WEBP_INLINE uint32_t GammaToLinearS(int v) {
Packit 9c6abc
  return (v << GAMMA_TO_LINEAR_BITS) / MAX_Y_T;
Packit 9c6abc
}
Packit 9c6abc
static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) {
Packit 9c6abc
  return (MAX_Y_T * value) >> GAMMA_TO_LINEAR_BITS;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
#endif    // USE_GAMMA_COMPRESSION
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
Packit 9c6abc
static uint8_t clip_8b(fixed_t v) {
Packit 9c6abc
  return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static fixed_y_t clip_y(int y) {
Packit 9c6abc
  return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
Packit 9c6abc
static int RGBToGray(int r, int g, int b) {
Packit 9c6abc
  const int luma = 13933 * r + 46871 * g + 4732 * b + YUV_HALF;
Packit 9c6abc
  return (luma >> YUV_FIX);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static uint32_t ScaleDown(int a, int b, int c, int d) {
Packit 9c6abc
  const uint32_t A = GammaToLinearS(a);
Packit 9c6abc
  const uint32_t B = GammaToLinearS(b);
Packit 9c6abc
  const uint32_t C = GammaToLinearS(c);
Packit 9c6abc
  const uint32_t D = GammaToLinearS(d);
Packit 9c6abc
  return LinearToGammaS((A + B + C + D + 2) >> 2);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w) {
Packit 9c6abc
  int i;
Packit 9c6abc
  for (i = 0; i < w; ++i) {
Packit 9c6abc
    const uint32_t R = GammaToLinearS(src[0 * w + i]);
Packit 9c6abc
    const uint32_t G = GammaToLinearS(src[1 * w + i]);
Packit 9c6abc
    const uint32_t B = GammaToLinearS(src[2 * w + i]);
Packit 9c6abc
    const uint32_t Y = RGBToGray(R, G, B);
Packit 9c6abc
    dst[i] = (fixed_y_t)LinearToGammaS(Y);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
Packit 9c6abc
                         fixed_t* dst, int uv_w) {
Packit 9c6abc
  int i;
Packit 9c6abc
  for (i = 0; i < uv_w; ++i) {
Packit 9c6abc
    const int r = ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1],
Packit 9c6abc
                            src2[0 * uv_w + 0], src2[0 * uv_w + 1]);
Packit 9c6abc
    const int g = ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1],
Packit 9c6abc
                            src2[2 * uv_w + 0], src2[2 * uv_w + 1]);
Packit 9c6abc
    const int b = ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1],
Packit 9c6abc
                            src2[4 * uv_w + 0], src2[4 * uv_w + 1]);
Packit 9c6abc
    const int W = RGBToGray(r, g, b);
Packit 9c6abc
    dst[0 * uv_w] = (fixed_t)(r - W);
Packit 9c6abc
    dst[1 * uv_w] = (fixed_t)(g - W);
Packit 9c6abc
    dst[2 * uv_w] = (fixed_t)(b - W);
Packit 9c6abc
    dst  += 1;
Packit 9c6abc
    src1 += 2;
Packit 9c6abc
    src2 += 2;
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
Packit 9c6abc
  int i;
Packit 9c6abc
  for (i = 0; i < w; ++i) {
Packit 9c6abc
    y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0) {
Packit 9c6abc
  const int v0 = (A * 3 + B + 2) >> 2;
Packit 9c6abc
  return clip_y(v0 + W0);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE fixed_y_t UpLift(uint8_t a) {  // 8bit -> SFIX
Packit 9c6abc
  return ((fixed_y_t)a << SFIX) | SHALF;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static void ImportOneRow(const uint8_t* const r_ptr,
Packit 9c6abc
                         const uint8_t* const g_ptr,
Packit 9c6abc
                         const uint8_t* const b_ptr,
Packit 9c6abc
                         int step,
Packit 9c6abc
                         int pic_width,
Packit 9c6abc
                         fixed_y_t* const dst) {
Packit 9c6abc
  int i;
Packit 9c6abc
  const int w = (pic_width + 1) & ~1;
Packit 9c6abc
  for (i = 0; i < pic_width; ++i) {
Packit 9c6abc
    const int off = i * step;
Packit 9c6abc
    dst[i + 0 * w] = UpLift(r_ptr[off]);
Packit 9c6abc
    dst[i + 1 * w] = UpLift(g_ptr[off]);
Packit 9c6abc
    dst[i + 2 * w] = UpLift(b_ptr[off]);
Packit 9c6abc
  }
Packit 9c6abc
  if (pic_width & 1) {  // replicate rightmost pixel
Packit 9c6abc
    dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
Packit 9c6abc
    dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
Packit 9c6abc
    dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1];
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static void InterpolateTwoRows(const fixed_y_t* const best_y,
Packit 9c6abc
                               const fixed_t* prev_uv,
Packit 9c6abc
                               const fixed_t* cur_uv,
Packit 9c6abc
                               const fixed_t* next_uv,
Packit 9c6abc
                               int w,
Packit 9c6abc
                               fixed_y_t* out1,
Packit 9c6abc
                               fixed_y_t* out2) {
Packit 9c6abc
  const int uv_w = w >> 1;
Packit 9c6abc
  const int len = (w - 1) >> 1;   // length to filter
Packit 9c6abc
  int k = 3;
Packit 9c6abc
  while (k-- > 0) {   // process each R/G/B segments in turn
Packit 9c6abc
    // special boundary case for i==0
Packit 9c6abc
    out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0]);
Packit 9c6abc
    out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w]);
Packit 9c6abc
Packit 9c6abc
    WebPSharpYUVFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1);
Packit 9c6abc
    WebPSharpYUVFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1);
Packit 9c6abc
Packit 9c6abc
    // special boundary case for i == w - 1 when w is even
Packit 9c6abc
    if (!(w & 1)) {
Packit 9c6abc
      out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1],
Packit 9c6abc
                            best_y[w - 1 + 0]);
Packit 9c6abc
      out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1],
Packit 9c6abc
                            best_y[w - 1 + w]);
Packit 9c6abc
    }
Packit 9c6abc
    out1 += w;
Packit 9c6abc
    out2 += w;
Packit 9c6abc
    prev_uv += uv_w;
Packit 9c6abc
    cur_uv  += uv_w;
Packit 9c6abc
    next_uv += uv_w;
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) {
Packit 9c6abc
  const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER;
Packit 9c6abc
  return clip_8b(16 + (luma >> (YUV_FIX + SFIX)));
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) {
Packit 9c6abc
  const int u =  -9719 * r - 19081 * g + 28800 * b + SROUNDER;
Packit 9c6abc
  return clip_8b(128 + (u >> (YUV_FIX + SFIX)));
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) {
Packit 9c6abc
  const int v = +28800 * r - 24116 * g -  4684 * b + SROUNDER;
Packit 9c6abc
  return clip_8b(128 + (v >> (YUV_FIX + SFIX)));
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
Packit 9c6abc
                            WebPPicture* const picture) {
Packit 9c6abc
  int i, j;
Packit 9c6abc
  uint8_t* dst_y = picture->y;
Packit 9c6abc
  uint8_t* dst_u = picture->u;
Packit 9c6abc
  uint8_t* dst_v = picture->v;
Packit 9c6abc
  const fixed_t* const best_uv_base = best_uv;
Packit 9c6abc
  const int w = (picture->width + 1) & ~1;
Packit 9c6abc
  const int h = (picture->height + 1) & ~1;
Packit 9c6abc
  const int uv_w = w >> 1;
Packit 9c6abc
  const int uv_h = h >> 1;
Packit 9c6abc
  for (best_uv = best_uv_base, j = 0; j < picture->height; ++j) {
Packit 9c6abc
    for (i = 0; i < picture->width; ++i) {
Packit 9c6abc
      const int off = (i >> 1);
Packit 9c6abc
      const int W = best_y[i];
Packit 9c6abc
      const int r = best_uv[off + 0 * uv_w] + W;
Packit 9c6abc
      const int g = best_uv[off + 1 * uv_w] + W;
Packit 9c6abc
      const int b = best_uv[off + 2 * uv_w] + W;
Packit 9c6abc
      dst_y[i] = ConvertRGBToY(r, g, b);
Packit 9c6abc
    }
Packit 9c6abc
    best_y += w;
Packit 9c6abc
    best_uv += (j & 1) * 3 * uv_w;
Packit 9c6abc
    dst_y += picture->y_stride;
Packit 9c6abc
  }
Packit 9c6abc
  for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
Packit 9c6abc
    for (i = 0; i < uv_w; ++i) {
Packit 9c6abc
      const int off = i;
Packit 9c6abc
      const int r = best_uv[off + 0 * uv_w];
Packit 9c6abc
      const int g = best_uv[off + 1 * uv_w];
Packit 9c6abc
      const int b = best_uv[off + 2 * uv_w];
Packit 9c6abc
      dst_u[i] = ConvertRGBToU(r, g, b);
Packit 9c6abc
      dst_v[i] = ConvertRGBToV(r, g, b);
Packit 9c6abc
    }
Packit 9c6abc
    best_uv += 3 * uv_w;
Packit 9c6abc
    dst_u += picture->uv_stride;
Packit 9c6abc
    dst_v += picture->uv_stride;
Packit 9c6abc
  }
Packit 9c6abc
  return 1;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// Main function
Packit 9c6abc
Packit 9c6abc
#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T)))
Packit 9c6abc
Packit 9c6abc
static int PreprocessARGB(const uint8_t* r_ptr,
Packit 9c6abc
                          const uint8_t* g_ptr,
Packit 9c6abc
                          const uint8_t* b_ptr,
Packit 9c6abc
                          int step, int rgb_stride,
Packit 9c6abc
                          WebPPicture* const picture) {
Packit 9c6abc
  // we expand the right/bottom border if needed
Packit 9c6abc
  const int w = (picture->width + 1) & ~1;
Packit 9c6abc
  const int h = (picture->height + 1) & ~1;
Packit 9c6abc
  const int uv_w = w >> 1;
Packit 9c6abc
  const int uv_h = h >> 1;
Packit 9c6abc
  uint64_t prev_diff_y_sum = ~0;
Packit 9c6abc
  int j, iter;
Packit 9c6abc
Packit 9c6abc
  // TODO(skal): allocate one big memory chunk. But for now, it's easier
Packit 9c6abc
  // for valgrind debugging to have several chunks.
Packit 9c6abc
  fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t);   // scratch
Packit 9c6abc
  fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t);
Packit 9c6abc
  fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t);
Packit 9c6abc
  fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
Packit 9c6abc
  fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
Packit 9c6abc
  fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
Packit 9c6abc
  fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
Packit 9c6abc
  fixed_y_t* best_y = best_y_base;
Packit 9c6abc
  fixed_y_t* target_y = target_y_base;
Packit 9c6abc
  fixed_t* best_uv = best_uv_base;
Packit 9c6abc
  fixed_t* target_uv = target_uv_base;
Packit 9c6abc
  const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h);
Packit 9c6abc
  int ok;
Packit 9c6abc
Packit 9c6abc
  if (best_y_base == NULL || best_uv_base == NULL ||
Packit 9c6abc
      target_y_base == NULL || target_uv_base == NULL ||
Packit 9c6abc
      best_rgb_y == NULL || best_rgb_uv == NULL ||
Packit 9c6abc
      tmp_buffer == NULL) {
Packit 9c6abc
    ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
Packit 9c6abc
    goto End;
Packit 9c6abc
  }
Packit 9c6abc
  assert(picture->width >= kMinDimensionIterativeConversion);
Packit 9c6abc
  assert(picture->height >= kMinDimensionIterativeConversion);
Packit 9c6abc
Packit 9c6abc
  WebPInitConvertARGBToYUV();
Packit 9c6abc
Packit 9c6abc
  // Import RGB samples to W/RGB representation.
Packit 9c6abc
  for (j = 0; j < picture->height; j += 2) {
Packit 9c6abc
    const int is_last_row = (j == picture->height - 1);
Packit 9c6abc
    fixed_y_t* const src1 = tmp_buffer + 0 * w;
Packit 9c6abc
    fixed_y_t* const src2 = tmp_buffer + 3 * w;
Packit 9c6abc
Packit 9c6abc
    // prepare two rows of input
Packit 9c6abc
    ImportOneRow(r_ptr, g_ptr, b_ptr, step, picture->width, src1);
Packit 9c6abc
    if (!is_last_row) {
Packit 9c6abc
      ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride,
Packit 9c6abc
                   step, picture->width, src2);
Packit 9c6abc
    } else {
Packit 9c6abc
      memcpy(src2, src1, 3 * w * sizeof(*src2));
Packit 9c6abc
    }
Packit 9c6abc
    StoreGray(src1, best_y + 0, w);
Packit 9c6abc
    StoreGray(src2, best_y + w, w);
Packit 9c6abc
Packit 9c6abc
    UpdateW(src1, target_y, w);
Packit 9c6abc
    UpdateW(src2, target_y + w, w);
Packit 9c6abc
    UpdateChroma(src1, src2, target_uv, uv_w);
Packit 9c6abc
    memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
Packit 9c6abc
    best_y += 2 * w;
Packit 9c6abc
    best_uv += 3 * uv_w;
Packit 9c6abc
    target_y += 2 * w;
Packit 9c6abc
    target_uv += 3 * uv_w;
Packit 9c6abc
    r_ptr += 2 * rgb_stride;
Packit 9c6abc
    g_ptr += 2 * rgb_stride;
Packit 9c6abc
    b_ptr += 2 * rgb_stride;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  // Iterate and resolve clipping conflicts.
Packit 9c6abc
  for (iter = 0; iter < kNumIterations; ++iter) {
Packit 9c6abc
    const fixed_t* cur_uv = best_uv_base;
Packit 9c6abc
    const fixed_t* prev_uv = best_uv_base;
Packit 9c6abc
    uint64_t diff_y_sum = 0;
Packit 9c6abc
Packit 9c6abc
    best_y = best_y_base;
Packit 9c6abc
    best_uv = best_uv_base;
Packit 9c6abc
    target_y = target_y_base;
Packit 9c6abc
    target_uv = target_uv_base;
Packit 9c6abc
    for (j = 0; j < h; j += 2) {
Packit 9c6abc
      fixed_y_t* const src1 = tmp_buffer + 0 * w;
Packit 9c6abc
      fixed_y_t* const src2 = tmp_buffer + 3 * w;
Packit 9c6abc
      {
Packit 9c6abc
        const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
Packit 9c6abc
        InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, src1, src2);
Packit 9c6abc
        prev_uv = cur_uv;
Packit 9c6abc
        cur_uv = next_uv;
Packit 9c6abc
      }
Packit 9c6abc
Packit 9c6abc
      UpdateW(src1, best_rgb_y + 0 * w, w);
Packit 9c6abc
      UpdateW(src2, best_rgb_y + 1 * w, w);
Packit 9c6abc
      UpdateChroma(src1, src2, best_rgb_uv, uv_w);
Packit 9c6abc
Packit 9c6abc
      // update two rows of Y and one row of RGB
Packit 9c6abc
      diff_y_sum += WebPSharpYUVUpdateY(target_y, best_rgb_y, best_y, 2 * w);
Packit 9c6abc
      WebPSharpYUVUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
Packit 9c6abc
Packit 9c6abc
      best_y += 2 * w;
Packit 9c6abc
      best_uv += 3 * uv_w;
Packit 9c6abc
      target_y += 2 * w;
Packit 9c6abc
      target_uv += 3 * uv_w;
Packit 9c6abc
    }
Packit 9c6abc
    // test exit condition
Packit 9c6abc
    if (iter > 0) {
Packit 9c6abc
      if (diff_y_sum < diff_y_threshold) break;
Packit 9c6abc
      if (diff_y_sum > prev_diff_y_sum) break;
Packit 9c6abc
    }
Packit 9c6abc
    prev_diff_y_sum = diff_y_sum;
Packit 9c6abc
  }
Packit 9c6abc
  // final reconstruction
Packit 9c6abc
  ok = ConvertWRGBToYUV(best_y_base, best_uv_base, picture);
Packit 9c6abc
Packit 9c6abc
 End:
Packit 9c6abc
  WebPSafeFree(best_y_base);
Packit 9c6abc
  WebPSafeFree(best_uv_base);
Packit 9c6abc
  WebPSafeFree(target_y_base);
Packit 9c6abc
  WebPSafeFree(target_uv_base);
Packit 9c6abc
  WebPSafeFree(best_rgb_y);
Packit 9c6abc
  WebPSafeFree(best_rgb_uv);
Packit 9c6abc
  WebPSafeFree(tmp_buffer);
Packit 9c6abc
  return ok;
Packit 9c6abc
}
Packit 9c6abc
#undef SAFE_ALLOC
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// "Fast" regular RGB->YUV
Packit 9c6abc
Packit 9c6abc
#define SUM4(ptr, step) LinearToGamma(                     \
Packit 9c6abc
    GammaToLinear((ptr)[0]) +                              \
Packit 9c6abc
    GammaToLinear((ptr)[(step)]) +                         \
Packit 9c6abc
    GammaToLinear((ptr)[rgb_stride]) +                     \
Packit 9c6abc
    GammaToLinear((ptr)[rgb_stride + (step)]), 0)          \
Packit 9c6abc
Packit 9c6abc
#define SUM2(ptr) \
Packit 9c6abc
    LinearToGamma(GammaToLinear((ptr)[0]) + GammaToLinear((ptr)[rgb_stride]), 1)
Packit 9c6abc
Packit 9c6abc
#define SUM2ALPHA(ptr) ((ptr)[0] + (ptr)[rgb_stride])
Packit 9c6abc
#define SUM4ALPHA(ptr) (SUM2ALPHA(ptr) + SUM2ALPHA((ptr) + 4))
Packit 9c6abc
Packit 9c6abc
#if defined(USE_INVERSE_ALPHA_TABLE)
Packit 9c6abc
Packit 9c6abc
static const int kAlphaFix = 19;
Packit 9c6abc
// Following table is (1 << kAlphaFix) / a. The (v * kInvAlpha[a]) >> kAlphaFix
Packit 9c6abc
// formula is then equal to v / a in most (99.6%) cases. Note that this table
Packit 9c6abc
// and constant are adjusted very tightly to fit 32b arithmetic.
Packit 9c6abc
// In particular, they use the fact that the operands for 'v / a' are actually
Packit 9c6abc
// derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3
Packit 9c6abc
// with ai in [0..255] and pi in [0..1<
Packit 9c6abc
// overflow is: kGammaFix + kAlphaFix <= 31.
Packit 9c6abc
static const uint32_t kInvAlpha[4 * 0xff + 1] = {
Packit 9c6abc
  0,  /* alpha = 0 */
Packit 9c6abc
  524288, 262144, 174762, 131072, 104857, 87381, 74898, 65536,
Packit 9c6abc
  58254, 52428, 47662, 43690, 40329, 37449, 34952, 32768,
Packit 9c6abc
  30840, 29127, 27594, 26214, 24966, 23831, 22795, 21845,
Packit 9c6abc
  20971, 20164, 19418, 18724, 18078, 17476, 16912, 16384,
Packit 9c6abc
  15887, 15420, 14979, 14563, 14169, 13797, 13443, 13107,
Packit 9c6abc
  12787, 12483, 12192, 11915, 11650, 11397, 11155, 10922,
Packit 9c6abc
  10699, 10485, 10280, 10082, 9892, 9709, 9532, 9362,
Packit 9c6abc
  9198, 9039, 8886, 8738, 8594, 8456, 8322, 8192,
Packit 9c6abc
  8065, 7943, 7825, 7710, 7598, 7489, 7384, 7281,
Packit 9c6abc
  7182, 7084, 6990, 6898, 6808, 6721, 6636, 6553,
Packit 9c6abc
  6472, 6393, 6316, 6241, 6168, 6096, 6026, 5957,
Packit 9c6abc
  5890, 5825, 5761, 5698, 5637, 5577, 5518, 5461,
Packit 9c6abc
  5405, 5349, 5295, 5242, 5190, 5140, 5090, 5041,
Packit 9c6abc
  4993, 4946, 4899, 4854, 4809, 4766, 4723, 4681,
Packit 9c6abc
  4639, 4599, 4559, 4519, 4481, 4443, 4405, 4369,
Packit 9c6abc
  4332, 4297, 4262, 4228, 4194, 4161, 4128, 4096,
Packit 9c6abc
  4064, 4032, 4002, 3971, 3942, 3912, 3883, 3855,
Packit 9c6abc
  3826, 3799, 3771, 3744, 3718, 3692, 3666, 3640,
Packit 9c6abc
  3615, 3591, 3566, 3542, 3518, 3495, 3472, 3449,
Packit 9c6abc
  3426, 3404, 3382, 3360, 3339, 3318, 3297, 3276,
Packit 9c6abc
  3256, 3236, 3216, 3196, 3177, 3158, 3139, 3120,
Packit 9c6abc
  3102, 3084, 3066, 3048, 3030, 3013, 2995, 2978,
Packit 9c6abc
  2962, 2945, 2928, 2912, 2896, 2880, 2864, 2849,
Packit 9c6abc
  2833, 2818, 2803, 2788, 2774, 2759, 2744, 2730,
Packit 9c6abc
  2716, 2702, 2688, 2674, 2661, 2647, 2634, 2621,
Packit 9c6abc
  2608, 2595, 2582, 2570, 2557, 2545, 2532, 2520,
Packit 9c6abc
  2508, 2496, 2484, 2473, 2461, 2449, 2438, 2427,
Packit 9c6abc
  2416, 2404, 2394, 2383, 2372, 2361, 2351, 2340,
Packit 9c6abc
  2330, 2319, 2309, 2299, 2289, 2279, 2269, 2259,
Packit 9c6abc
  2250, 2240, 2231, 2221, 2212, 2202, 2193, 2184,
Packit 9c6abc
  2175, 2166, 2157, 2148, 2139, 2131, 2122, 2114,
Packit 9c6abc
  2105, 2097, 2088, 2080, 2072, 2064, 2056, 2048,
Packit 9c6abc
  2040, 2032, 2024, 2016, 2008, 2001, 1993, 1985,
Packit 9c6abc
  1978, 1971, 1963, 1956, 1949, 1941, 1934, 1927,
Packit 9c6abc
  1920, 1913, 1906, 1899, 1892, 1885, 1879, 1872,
Packit 9c6abc
  1865, 1859, 1852, 1846, 1839, 1833, 1826, 1820,
Packit 9c6abc
  1814, 1807, 1801, 1795, 1789, 1783, 1777, 1771,
Packit 9c6abc
  1765, 1759, 1753, 1747, 1741, 1736, 1730, 1724,
Packit 9c6abc
  1718, 1713, 1707, 1702, 1696, 1691, 1685, 1680,
Packit 9c6abc
  1675, 1669, 1664, 1659, 1653, 1648, 1643, 1638,
Packit 9c6abc
  1633, 1628, 1623, 1618, 1613, 1608, 1603, 1598,
Packit 9c6abc
  1593, 1588, 1583, 1579, 1574, 1569, 1565, 1560,
Packit 9c6abc
  1555, 1551, 1546, 1542, 1537, 1533, 1528, 1524,
Packit 9c6abc
  1519, 1515, 1510, 1506, 1502, 1497, 1493, 1489,
Packit 9c6abc
  1485, 1481, 1476, 1472, 1468, 1464, 1460, 1456,
Packit 9c6abc
  1452, 1448, 1444, 1440, 1436, 1432, 1428, 1424,
Packit 9c6abc
  1420, 1416, 1413, 1409, 1405, 1401, 1398, 1394,
Packit 9c6abc
  1390, 1387, 1383, 1379, 1376, 1372, 1368, 1365,
Packit 9c6abc
  1361, 1358, 1354, 1351, 1347, 1344, 1340, 1337,
Packit 9c6abc
  1334, 1330, 1327, 1323, 1320, 1317, 1314, 1310,
Packit 9c6abc
  1307, 1304, 1300, 1297, 1294, 1291, 1288, 1285,
Packit 9c6abc
  1281, 1278, 1275, 1272, 1269, 1266, 1263, 1260,
Packit 9c6abc
  1257, 1254, 1251, 1248, 1245, 1242, 1239, 1236,
Packit 9c6abc
  1233, 1230, 1227, 1224, 1222, 1219, 1216, 1213,
Packit 9c6abc
  1210, 1208, 1205, 1202, 1199, 1197, 1194, 1191,
Packit 9c6abc
  1188, 1186, 1183, 1180, 1178, 1175, 1172, 1170,
Packit 9c6abc
  1167, 1165, 1162, 1159, 1157, 1154, 1152, 1149,
Packit 9c6abc
  1147, 1144, 1142, 1139, 1137, 1134, 1132, 1129,
Packit 9c6abc
  1127, 1125, 1122, 1120, 1117, 1115, 1113, 1110,
Packit 9c6abc
  1108, 1106, 1103, 1101, 1099, 1096, 1094, 1092,
Packit 9c6abc
  1089, 1087, 1085, 1083, 1081, 1078, 1076, 1074,
Packit 9c6abc
  1072, 1069, 1067, 1065, 1063, 1061, 1059, 1057,
Packit 9c6abc
  1054, 1052, 1050, 1048, 1046, 1044, 1042, 1040,
Packit 9c6abc
  1038, 1036, 1034, 1032, 1030, 1028, 1026, 1024,
Packit 9c6abc
  1022, 1020, 1018, 1016, 1014, 1012, 1010, 1008,
Packit 9c6abc
  1006, 1004, 1002, 1000, 998, 996, 994, 992,
Packit 9c6abc
  991, 989, 987, 985, 983, 981, 979, 978,
Packit 9c6abc
  976, 974, 972, 970, 969, 967, 965, 963,
Packit 9c6abc
  961, 960, 958, 956, 954, 953, 951, 949,
Packit 9c6abc
  948, 946, 944, 942, 941, 939, 937, 936,
Packit 9c6abc
  934, 932, 931, 929, 927, 926, 924, 923,
Packit 9c6abc
  921, 919, 918, 916, 914, 913, 911, 910,
Packit 9c6abc
  908, 907, 905, 903, 902, 900, 899, 897,
Packit 9c6abc
  896, 894, 893, 891, 890, 888, 887, 885,
Packit 9c6abc
  884, 882, 881, 879, 878, 876, 875, 873,
Packit 9c6abc
  872, 870, 869, 868, 866, 865, 863, 862,
Packit 9c6abc
  860, 859, 858, 856, 855, 853, 852, 851,
Packit 9c6abc
  849, 848, 846, 845, 844, 842, 841, 840,
Packit 9c6abc
  838, 837, 836, 834, 833, 832, 830, 829,
Packit 9c6abc
  828, 826, 825, 824, 823, 821, 820, 819,
Packit 9c6abc
  817, 816, 815, 814, 812, 811, 810, 809,
Packit 9c6abc
  807, 806, 805, 804, 802, 801, 800, 799,
Packit 9c6abc
  798, 796, 795, 794, 793, 791, 790, 789,
Packit 9c6abc
  788, 787, 786, 784, 783, 782, 781, 780,
Packit 9c6abc
  779, 777, 776, 775, 774, 773, 772, 771,
Packit 9c6abc
  769, 768, 767, 766, 765, 764, 763, 762,
Packit 9c6abc
  760, 759, 758, 757, 756, 755, 754, 753,
Packit 9c6abc
  752, 751, 750, 748, 747, 746, 745, 744,
Packit 9c6abc
  743, 742, 741, 740, 739, 738, 737, 736,
Packit 9c6abc
  735, 734, 733, 732, 731, 730, 729, 728,
Packit 9c6abc
  727, 726, 725, 724, 723, 722, 721, 720,
Packit 9c6abc
  719, 718, 717, 716, 715, 714, 713, 712,
Packit 9c6abc
  711, 710, 709, 708, 707, 706, 705, 704,
Packit 9c6abc
  703, 702, 701, 700, 699, 699, 698, 697,
Packit 9c6abc
  696, 695, 694, 693, 692, 691, 690, 689,
Packit 9c6abc
  688, 688, 687, 686, 685, 684, 683, 682,
Packit 9c6abc
  681, 680, 680, 679, 678, 677, 676, 675,
Packit 9c6abc
  674, 673, 673, 672, 671, 670, 669, 668,
Packit 9c6abc
  667, 667, 666, 665, 664, 663, 662, 661,
Packit 9c6abc
  661, 660, 659, 658, 657, 657, 656, 655,
Packit 9c6abc
  654, 653, 652, 652, 651, 650, 649, 648,
Packit 9c6abc
  648, 647, 646, 645, 644, 644, 643, 642,
Packit 9c6abc
  641, 640, 640, 639, 638, 637, 637, 636,
Packit 9c6abc
  635, 634, 633, 633, 632, 631, 630, 630,
Packit 9c6abc
  629, 628, 627, 627, 626, 625, 624, 624,
Packit 9c6abc
  623, 622, 621, 621, 620, 619, 618, 618,
Packit 9c6abc
  617, 616, 616, 615, 614, 613, 613, 612,
Packit 9c6abc
  611, 611, 610, 609, 608, 608, 607, 606,
Packit 9c6abc
  606, 605, 604, 604, 603, 602, 601, 601,
Packit 9c6abc
  600, 599, 599, 598, 597, 597, 596, 595,
Packit 9c6abc
  595, 594, 593, 593, 592, 591, 591, 590,
Packit 9c6abc
  589, 589, 588, 587, 587, 586, 585, 585,
Packit 9c6abc
  584, 583, 583, 582, 581, 581, 580, 579,
Packit 9c6abc
  579, 578, 578, 577, 576, 576, 575, 574,
Packit 9c6abc
  574, 573, 572, 572, 571, 571, 570, 569,
Packit 9c6abc
  569, 568, 568, 567, 566, 566, 565, 564,
Packit 9c6abc
  564, 563, 563, 562, 561, 561, 560, 560,
Packit 9c6abc
  559, 558, 558, 557, 557, 556, 555, 555,
Packit 9c6abc
  554, 554, 553, 553, 552, 551, 551, 550,
Packit 9c6abc
  550, 549, 548, 548, 547, 547, 546, 546,
Packit 9c6abc
  545, 544, 544, 543, 543, 542, 542, 541,
Packit 9c6abc
  541, 540, 539, 539, 538, 538, 537, 537,
Packit 9c6abc
  536, 536, 535, 534, 534, 533, 533, 532,
Packit 9c6abc
  532, 531, 531, 530, 530, 529, 529, 528,
Packit 9c6abc
  527, 527, 526, 526, 525, 525, 524, 524,
Packit 9c6abc
  523, 523, 522, 522, 521, 521, 520, 520,
Packit 9c6abc
  519, 519, 518, 518, 517, 517, 516, 516,
Packit 9c6abc
  515, 515, 514, 514
Packit 9c6abc
};
Packit 9c6abc
Packit 9c6abc
// Note that LinearToGamma() expects the values to be premultiplied by 4,
Packit 9c6abc
// so we incorporate this factor 4 inside the DIVIDE_BY_ALPHA macro directly.
Packit 9c6abc
#define DIVIDE_BY_ALPHA(sum, a)  (((sum) * kInvAlpha[(a)]) >> (kAlphaFix - 2))
Packit 9c6abc
Packit 9c6abc
#else
Packit 9c6abc
Packit 9c6abc
#define DIVIDE_BY_ALPHA(sum, a) (4 * (sum) / (a))
Packit 9c6abc
Packit 9c6abc
#endif  // USE_INVERSE_ALPHA_TABLE
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE int LinearToGammaWeighted(const uint8_t* src,
Packit 9c6abc
                                             const uint8_t* a_ptr,
Packit 9c6abc
                                             uint32_t total_a, int step,
Packit 9c6abc
                                             int rgb_stride) {
Packit 9c6abc
  const uint32_t sum =
Packit 9c6abc
      a_ptr[0] * GammaToLinear(src[0]) +
Packit 9c6abc
      a_ptr[step] * GammaToLinear(src[step]) +
Packit 9c6abc
      a_ptr[rgb_stride] * GammaToLinear(src[rgb_stride]) +
Packit 9c6abc
      a_ptr[rgb_stride + step] * GammaToLinear(src[rgb_stride + step]);
Packit 9c6abc
  assert(total_a > 0 && total_a <= 4 * 0xff);
Packit 9c6abc
#if defined(USE_INVERSE_ALPHA_TABLE)
Packit 9c6abc
  assert((uint64_t)sum * kInvAlpha[total_a] < ((uint64_t)1 << 32));
Packit 9c6abc
#endif
Packit 9c6abc
  return LinearToGamma(DIVIDE_BY_ALPHA(sum, total_a), 0);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE void ConvertRowToY(const uint8_t* const r_ptr,
Packit 9c6abc
                                      const uint8_t* const g_ptr,
Packit 9c6abc
                                      const uint8_t* const b_ptr,
Packit 9c6abc
                                      int step,
Packit 9c6abc
                                      uint8_t* const dst_y,
Packit 9c6abc
                                      int width,
Packit 9c6abc
                                      VP8Random* const rg) {
Packit 9c6abc
  int i, j;
Packit 9c6abc
  for (i = 0, j = 0; i < width; i += 1, j += step) {
Packit 9c6abc
    dst_y[i] = RGBToY(r_ptr[j], g_ptr[j], b_ptr[j], rg);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE void AccumulateRGBA(const uint8_t* const r_ptr,
Packit 9c6abc
                                       const uint8_t* const g_ptr,
Packit 9c6abc
                                       const uint8_t* const b_ptr,
Packit 9c6abc
                                       const uint8_t* const a_ptr,
Packit 9c6abc
                                       int rgb_stride,
Packit 9c6abc
                                       uint16_t* dst, int width) {
Packit 9c6abc
  int i, j;
Packit 9c6abc
  // we loop over 2x2 blocks and produce one R/G/B/A value for each.
Packit 9c6abc
  for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * 4, dst += 4) {
Packit 9c6abc
    const uint32_t a = SUM4ALPHA(a_ptr + j);
Packit 9c6abc
    int r, g, b;
Packit 9c6abc
    if (a == 4 * 0xff || a == 0) {
Packit 9c6abc
      r = SUM4(r_ptr + j, 4);
Packit 9c6abc
      g = SUM4(g_ptr + j, 4);
Packit 9c6abc
      b = SUM4(b_ptr + j, 4);
Packit 9c6abc
    } else {
Packit 9c6abc
      r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 4, rgb_stride);
Packit 9c6abc
      g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 4, rgb_stride);
Packit 9c6abc
      b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 4, rgb_stride);
Packit 9c6abc
    }
Packit 9c6abc
    dst[0] = r;
Packit 9c6abc
    dst[1] = g;
Packit 9c6abc
    dst[2] = b;
Packit 9c6abc
    dst[3] = a;
Packit 9c6abc
  }
Packit 9c6abc
  if (width & 1) {
Packit 9c6abc
    const uint32_t a = 2u * SUM2ALPHA(a_ptr + j);
Packit 9c6abc
    int r, g, b;
Packit 9c6abc
    if (a == 4 * 0xff || a == 0) {
Packit 9c6abc
      r = SUM2(r_ptr + j);
Packit 9c6abc
      g = SUM2(g_ptr + j);
Packit 9c6abc
      b = SUM2(b_ptr + j);
Packit 9c6abc
    } else {
Packit 9c6abc
      r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 0, rgb_stride);
Packit 9c6abc
      g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 0, rgb_stride);
Packit 9c6abc
      b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 0, rgb_stride);
Packit 9c6abc
    }
Packit 9c6abc
    dst[0] = r;
Packit 9c6abc
    dst[1] = g;
Packit 9c6abc
    dst[2] = b;
Packit 9c6abc
    dst[3] = a;
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE void AccumulateRGB(const uint8_t* const r_ptr,
Packit 9c6abc
                                      const uint8_t* const g_ptr,
Packit 9c6abc
                                      const uint8_t* const b_ptr,
Packit 9c6abc
                                      int step, int rgb_stride,
Packit 9c6abc
                                      uint16_t* dst, int width) {
Packit 9c6abc
  int i, j;
Packit 9c6abc
  for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * step, dst += 4) {
Packit 9c6abc
    dst[0] = SUM4(r_ptr + j, step);
Packit 9c6abc
    dst[1] = SUM4(g_ptr + j, step);
Packit 9c6abc
    dst[2] = SUM4(b_ptr + j, step);
Packit 9c6abc
  }
Packit 9c6abc
  if (width & 1) {
Packit 9c6abc
    dst[0] = SUM2(r_ptr + j);
Packit 9c6abc
    dst[1] = SUM2(g_ptr + j);
Packit 9c6abc
    dst[2] = SUM2(b_ptr + j);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static WEBP_INLINE void ConvertRowsToUV(const uint16_t* rgb,
Packit 9c6abc
                                        uint8_t* const dst_u,
Packit 9c6abc
                                        uint8_t* const dst_v,
Packit 9c6abc
                                        int width,
Packit 9c6abc
                                        VP8Random* const rg) {
Packit 9c6abc
  int i;
Packit 9c6abc
  for (i = 0; i < width; i += 1, rgb += 4) {
Packit 9c6abc
    const int r = rgb[0], g = rgb[1], b = rgb[2];
Packit 9c6abc
    dst_u[i] = RGBToU(r, g, b, rg);
Packit 9c6abc
    dst_v[i] = RGBToV(r, g, b, rg);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
static int ImportYUVAFromRGBA(const uint8_t* r_ptr,
Packit 9c6abc
                              const uint8_t* g_ptr,
Packit 9c6abc
                              const uint8_t* b_ptr,
Packit 9c6abc
                              const uint8_t* a_ptr,
Packit 9c6abc
                              int step,         // bytes per pixel
Packit 9c6abc
                              int rgb_stride,   // bytes per scanline
Packit 9c6abc
                              float dithering,
Packit 9c6abc
                              int use_iterative_conversion,
Packit 9c6abc
                              WebPPicture* const picture) {
Packit 9c6abc
  int y;
Packit 9c6abc
  const int width = picture->width;
Packit 9c6abc
  const int height = picture->height;
Packit 9c6abc
  const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride);
Packit 9c6abc
  const int is_rgb = (r_ptr < b_ptr);  // otherwise it's bgr
Packit 9c6abc
Packit 9c6abc
  picture->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
Packit 9c6abc
  picture->use_argb = 0;
Packit 9c6abc
Packit 9c6abc
  // disable smart conversion if source is too small (overkill).
Packit 9c6abc
  if (width < kMinDimensionIterativeConversion ||
Packit 9c6abc
      height < kMinDimensionIterativeConversion) {
Packit 9c6abc
    use_iterative_conversion = 0;
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  if (!WebPPictureAllocYUVA(picture, width, height)) {
Packit 9c6abc
    return 0;
Packit 9c6abc
  }
Packit 9c6abc
  if (has_alpha) {
Packit 9c6abc
    assert(step == 4);
Packit 9c6abc
#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE)
Packit 9c6abc
    assert(kAlphaFix + kGammaFix <= 31);
Packit 9c6abc
#endif
Packit 9c6abc
  }
Packit 9c6abc
Packit 9c6abc
  if (use_iterative_conversion) {
Packit 9c6abc
    InitGammaTablesS();
Packit 9c6abc
    if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) {
Packit 9c6abc
      return 0;
Packit 9c6abc
    }
Packit 9c6abc
    if (has_alpha) {
Packit 9c6abc
      WebPExtractAlpha(a_ptr, rgb_stride, width, height,
Packit 9c6abc
                       picture->a, picture->a_stride);
Packit 9c6abc
    }
Packit 9c6abc
  } else {
Packit 9c6abc
    const int uv_width = (width + 1) >> 1;
Packit 9c6abc
    int use_dsp = (step == 3);  // use special function in this case
Packit 9c6abc
    // temporary storage for accumulated R/G/B values during conversion to U/V
Packit 9c6abc
    uint16_t* const tmp_rgb =
Packit 9c6abc
        (uint16_t*)WebPSafeMalloc(4 * uv_width, sizeof(*tmp_rgb));
Packit 9c6abc
    uint8_t* dst_y = picture->y;
Packit 9c6abc
    uint8_t* dst_u = picture->u;
Packit 9c6abc
    uint8_t* dst_v = picture->v;
Packit 9c6abc
    uint8_t* dst_a = picture->a;
Packit 9c6abc
Packit 9c6abc
    VP8Random base_rg;
Packit 9c6abc
    VP8Random* rg = NULL;
Packit 9c6abc
    if (dithering > 0.) {
Packit 9c6abc
      VP8InitRandom(&base_rg, dithering);
Packit 9c6abc
      rg = &base_rg;
Packit 9c6abc
      use_dsp = 0;   // can't use dsp in this case
Packit 9c6abc
    }
Packit 9c6abc
    WebPInitConvertARGBToYUV();
Packit 9c6abc
    InitGammaTables();
Packit 9c6abc
Packit 9c6abc
    if (tmp_rgb == NULL) return 0;  // malloc error
Packit 9c6abc
Packit 9c6abc
    // Downsample Y/U/V planes, two rows at a time
Packit 9c6abc
    for (y = 0; y < (height >> 1); ++y) {
Packit 9c6abc
      int rows_have_alpha = has_alpha;
Packit 9c6abc
      if (use_dsp) {
Packit 9c6abc
        if (is_rgb) {
Packit 9c6abc
          WebPConvertRGB24ToY(r_ptr, dst_y, width);
Packit 9c6abc
          WebPConvertRGB24ToY(r_ptr + rgb_stride,
Packit 9c6abc
                              dst_y + picture->y_stride, width);
Packit 9c6abc
        } else {
Packit 9c6abc
          WebPConvertBGR24ToY(b_ptr, dst_y, width);
Packit 9c6abc
          WebPConvertBGR24ToY(b_ptr + rgb_stride,
Packit 9c6abc
                              dst_y + picture->y_stride, width);
Packit 9c6abc
        }
Packit 9c6abc
      } else {
Packit 9c6abc
        ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg);
Packit 9c6abc
        ConvertRowToY(r_ptr + rgb_stride,
Packit 9c6abc
                      g_ptr + rgb_stride,
Packit 9c6abc
                      b_ptr + rgb_stride, step,
Packit 9c6abc
                      dst_y + picture->y_stride, width, rg);
Packit 9c6abc
      }
Packit 9c6abc
      dst_y += 2 * picture->y_stride;
Packit 9c6abc
      if (has_alpha) {
Packit 9c6abc
        rows_have_alpha &= !WebPExtractAlpha(a_ptr, rgb_stride, width, 2,
Packit 9c6abc
                                             dst_a, picture->a_stride);
Packit 9c6abc
        dst_a += 2 * picture->a_stride;
Packit 9c6abc
      }
Packit 9c6abc
      // Collect averaged R/G/B(/A)
Packit 9c6abc
      if (!rows_have_alpha) {
Packit 9c6abc
        AccumulateRGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, tmp_rgb, width);
Packit 9c6abc
      } else {
Packit 9c6abc
        AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, rgb_stride, tmp_rgb, width);
Packit 9c6abc
      }
Packit 9c6abc
      // Convert to U/V
Packit 9c6abc
      if (rg == NULL) {
Packit 9c6abc
        WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
Packit 9c6abc
      } else {
Packit 9c6abc
        ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
Packit 9c6abc
      }
Packit 9c6abc
      dst_u += picture->uv_stride;
Packit 9c6abc
      dst_v += picture->uv_stride;
Packit 9c6abc
      r_ptr += 2 * rgb_stride;
Packit 9c6abc
      b_ptr += 2 * rgb_stride;
Packit 9c6abc
      g_ptr += 2 * rgb_stride;
Packit 9c6abc
      if (has_alpha) a_ptr += 2 * rgb_stride;
Packit 9c6abc
    }
Packit 9c6abc
    if (height & 1) {    // extra last row
Packit 9c6abc
      int row_has_alpha = has_alpha;
Packit 9c6abc
      if (use_dsp) {
Packit 9c6abc
        if (r_ptr < b_ptr) {
Packit 9c6abc
          WebPConvertRGB24ToY(r_ptr, dst_y, width);
Packit 9c6abc
        } else {
Packit 9c6abc
          WebPConvertBGR24ToY(b_ptr, dst_y, width);
Packit 9c6abc
        }
Packit 9c6abc
      } else {
Packit 9c6abc
        ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg);
Packit 9c6abc
      }
Packit 9c6abc
      if (row_has_alpha) {
Packit 9c6abc
        row_has_alpha &= !WebPExtractAlpha(a_ptr, 0, width, 1, dst_a, 0);
Packit 9c6abc
      }
Packit 9c6abc
      // Collect averaged R/G/B(/A)
Packit 9c6abc
      if (!row_has_alpha) {
Packit 9c6abc
        // Collect averaged R/G/B
Packit 9c6abc
        AccumulateRGB(r_ptr, g_ptr, b_ptr, step, /* rgb_stride = */ 0,
Packit 9c6abc
                      tmp_rgb, width);
Packit 9c6abc
      } else {
Packit 9c6abc
        AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, /* rgb_stride = */ 0,
Packit 9c6abc
                       tmp_rgb, width);
Packit 9c6abc
      }
Packit 9c6abc
      if (rg == NULL) {
Packit 9c6abc
        WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
Packit 9c6abc
      } else {
Packit 9c6abc
        ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
Packit 9c6abc
      }
Packit 9c6abc
    }
Packit 9c6abc
    WebPSafeFree(tmp_rgb);
Packit 9c6abc
  }
Packit 9c6abc
  return 1;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
#undef SUM4
Packit 9c6abc
#undef SUM2
Packit 9c6abc
#undef SUM4ALPHA
Packit 9c6abc
#undef SUM2ALPHA
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// call for ARGB->YUVA conversion
Packit 9c6abc
Packit 9c6abc
static int PictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace,
Packit 9c6abc
                             float dithering, int use_iterative_conversion) {
Packit 9c6abc
  if (picture == NULL) return 0;
Packit 9c6abc
  if (picture->argb == NULL) {
Packit 9c6abc
    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
Packit 9c6abc
  } else if ((colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
Packit 9c6abc
    return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
Packit 9c6abc
  } else {
Packit 9c6abc
    const uint8_t* const argb = (const uint8_t*)picture->argb;
Packit 9c6abc
    const uint8_t* const a = argb + (0 ^ ALPHA_OFFSET);
Packit 9c6abc
    const uint8_t* const r = argb + (1 ^ ALPHA_OFFSET);
Packit 9c6abc
    const uint8_t* const g = argb + (2 ^ ALPHA_OFFSET);
Packit 9c6abc
    const uint8_t* const b = argb + (3 ^ ALPHA_OFFSET);
Packit 9c6abc
Packit 9c6abc
    picture->colorspace = WEBP_YUV420;
Packit 9c6abc
    return ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride,
Packit 9c6abc
                              dithering, use_iterative_conversion, picture);
Packit 9c6abc
  }
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
int WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace,
Packit 9c6abc
                                  float dithering) {
Packit 9c6abc
  return PictureARGBToYUVA(picture, colorspace, dithering, 0);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) {
Packit 9c6abc
  return PictureARGBToYUVA(picture, colorspace, 0.f, 0);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
int WebPPictureSharpARGBToYUVA(WebPPicture* picture) {
Packit 9c6abc
  return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1);
Packit 9c6abc
}
Packit 9c6abc
// for backward compatibility
Packit 9c6abc
int WebPPictureSmartARGBToYUVA(WebPPicture* picture) {
Packit 9c6abc
  return WebPPictureSharpARGBToYUVA(picture);
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// call for YUVA -> ARGB conversion
Packit 9c6abc
Packit 9c6abc
int WebPPictureYUVAToARGB(WebPPicture* picture) {
Packit 9c6abc
  if (picture == NULL) return 0;
Packit 9c6abc
  if (picture->y == NULL || picture->u == NULL || picture->v == NULL) {
Packit 9c6abc
    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
Packit 9c6abc
  }
Packit 9c6abc
  if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) {
Packit 9c6abc
    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
Packit 9c6abc
  }
Packit 9c6abc
  if ((picture->colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
Packit 9c6abc
    return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
Packit 9c6abc
  }
Packit 9c6abc
  // Allocate a new argb buffer (discarding the previous one).
Packit 9c6abc
  if (!WebPPictureAllocARGB(picture, picture->width, picture->height)) return 0;
Packit 9c6abc
  picture->use_argb = 1;
Packit 9c6abc
Packit 9c6abc
  // Convert
Packit 9c6abc
  {
Packit 9c6abc
    int y;
Packit 9c6abc
    const int width = picture->width;
Packit 9c6abc
    const int height = picture->height;
Packit 9c6abc
    const int argb_stride = 4 * picture->argb_stride;
Packit 9c6abc
    uint8_t* dst = (uint8_t*)picture->argb;
Packit 9c6abc
    const uint8_t *cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y;
Packit 9c6abc
    WebPUpsampleLinePairFunc upsample =
Packit 9c6abc
        WebPGetLinePairConverter(ALPHA_OFFSET > 0);
Packit 9c6abc
Packit 9c6abc
    // First row, with replicated top samples.
Packit 9c6abc
    upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
Packit 9c6abc
    cur_y += picture->y_stride;
Packit 9c6abc
    dst += argb_stride;
Packit 9c6abc
    // Center rows.
Packit 9c6abc
    for (y = 1; y + 1 < height; y += 2) {
Packit 9c6abc
      const uint8_t* const top_u = cur_u;
Packit 9c6abc
      const uint8_t* const top_v = cur_v;
Packit 9c6abc
      cur_u += picture->uv_stride;
Packit 9c6abc
      cur_v += picture->uv_stride;
Packit 9c6abc
      upsample(cur_y, cur_y + picture->y_stride, top_u, top_v, cur_u, cur_v,
Packit 9c6abc
               dst, dst + argb_stride, width);
Packit 9c6abc
      cur_y += 2 * picture->y_stride;
Packit 9c6abc
      dst += 2 * argb_stride;
Packit 9c6abc
    }
Packit 9c6abc
    // Last row (if needed), with replicated bottom samples.
Packit 9c6abc
    if (height > 1 && !(height & 1)) {
Packit 9c6abc
      upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
Packit 9c6abc
    }
Packit 9c6abc
    // Insert alpha values if needed, in replacement for the default 0xff ones.
Packit 9c6abc
    if (picture->colorspace & WEBP_CSP_ALPHA_BIT) {
Packit 9c6abc
      for (y = 0; y < height; ++y) {
Packit 9c6abc
        uint32_t* const argb_dst = picture->argb + y * picture->argb_stride;
Packit 9c6abc
        const uint8_t* const src = picture->a + y * picture->a_stride;
Packit 9c6abc
        int x;
Packit 9c6abc
        for (x = 0; x < width; ++x) {
Packit 9c6abc
          argb_dst[x] = (argb_dst[x] & 0x00ffffffu) | ((uint32_t)src[x] << 24);
Packit 9c6abc
        }
Packit 9c6abc
      }
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
  return 1;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------
Packit 9c6abc
// automatic import / conversion
Packit 9c6abc
Packit 9c6abc
static int Import(WebPPicture* const picture,
Packit 9c6abc
                  const uint8_t* rgb, int rgb_stride,
Packit 9c6abc
                  int step, int swap_rb, int import_alpha) {
Packit 9c6abc
  int y;
Packit 9c6abc
  // swap_rb -> b,g,r,a , !swap_rb -> r,g,b,a
Packit 9c6abc
  const uint8_t* r_ptr = rgb + (swap_rb ? 2 : 0);
Packit 9c6abc
  const uint8_t* g_ptr = rgb + 1;
Packit 9c6abc
  const uint8_t* b_ptr = rgb + (swap_rb ? 0 : 2);
Packit 9c6abc
  const int width = picture->width;
Packit 9c6abc
  const int height = picture->height;
Packit 9c6abc
Packit 9c6abc
  if (!picture->use_argb) {
Packit 9c6abc
    const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL;
Packit 9c6abc
    return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
Packit 9c6abc
                              0.f /* no dithering */, 0, picture);
Packit 9c6abc
  }
Packit 9c6abc
  if (!WebPPictureAlloc(picture)) return 0;
Packit 9c6abc
Packit 9c6abc
  VP8LDspInit();
Packit 9c6abc
  WebPInitAlphaProcessing();
Packit 9c6abc
Packit 9c6abc
  if (import_alpha) {
Packit 9c6abc
    // dst[] byte order is {a,r,g,b} for big-endian, {b,g,r,a} for little endian
Packit 9c6abc
    uint32_t* dst = picture->argb;
Packit 9c6abc
    const int do_copy = (ALPHA_OFFSET == 3) && swap_rb;
Packit 9c6abc
    assert(step == 4);
Packit 9c6abc
    if (do_copy) {
Packit 9c6abc
      for (y = 0; y < height; ++y) {
Packit 9c6abc
        memcpy(dst, rgb, width * 4);
Packit 9c6abc
        rgb += rgb_stride;
Packit 9c6abc
        dst += picture->argb_stride;
Packit 9c6abc
      }
Packit 9c6abc
    } else {
Packit 9c6abc
      for (y = 0; y < height; ++y) {
Packit 9c6abc
#ifdef WORDS_BIGENDIAN
Packit 9c6abc
        // BGRA or RGBA input order.
Packit 9c6abc
        const uint8_t* a_ptr = rgb + 3;
Packit 9c6abc
        WebPPackARGB(a_ptr, r_ptr, g_ptr, b_ptr, width, dst);
Packit 9c6abc
        r_ptr += rgb_stride;
Packit 9c6abc
        g_ptr += rgb_stride;
Packit 9c6abc
        b_ptr += rgb_stride;
Packit 9c6abc
#else
Packit 9c6abc
        // RGBA input order. Need to swap R and B.
Packit 9c6abc
        VP8LConvertBGRAToRGBA((const uint32_t*)rgb, width, (uint8_t*)dst);
Packit 9c6abc
#endif
Packit 9c6abc
        rgb += rgb_stride;
Packit 9c6abc
        dst += picture->argb_stride;
Packit 9c6abc
      }
Packit 9c6abc
    }
Packit 9c6abc
  } else {
Packit 9c6abc
    uint32_t* dst = picture->argb;
Packit 9c6abc
    assert(step >= 3);
Packit 9c6abc
    for (y = 0; y < height; ++y) {
Packit 9c6abc
      WebPPackRGB(r_ptr, g_ptr, b_ptr, width, step, dst);
Packit 9c6abc
      r_ptr += rgb_stride;
Packit 9c6abc
      g_ptr += rgb_stride;
Packit 9c6abc
      b_ptr += rgb_stride;
Packit 9c6abc
      dst += picture->argb_stride;
Packit 9c6abc
    }
Packit 9c6abc
  }
Packit 9c6abc
  return 1;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
// Public API
Packit 9c6abc
Packit 9c6abc
#if !defined(WEBP_REDUCE_CSP)
Packit 9c6abc
Packit 9c6abc
int WebPPictureImportBGR(WebPPicture* picture,
Packit 9c6abc
                         const uint8_t* rgb, int rgb_stride) {
Packit 9c6abc
  return (picture != NULL && rgb != NULL)
Packit 9c6abc
             ? Import(picture, rgb, rgb_stride, 3, 1, 0)
Packit 9c6abc
             : 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
int WebPPictureImportBGRA(WebPPicture* picture,
Packit 9c6abc
                          const uint8_t* rgba, int rgba_stride) {
Packit 9c6abc
  return (picture != NULL && rgba != NULL)
Packit 9c6abc
             ? Import(picture, rgba, rgba_stride, 4, 1, 1)
Packit 9c6abc
             : 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
Packit 9c6abc
int WebPPictureImportBGRX(WebPPicture* picture,
Packit 9c6abc
                          const uint8_t* rgba, int rgba_stride) {
Packit 9c6abc
  return (picture != NULL && rgba != NULL)
Packit 9c6abc
             ? Import(picture, rgba, rgba_stride, 4, 1, 0)
Packit 9c6abc
             : 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
#endif   // WEBP_REDUCE_CSP
Packit 9c6abc
Packit 9c6abc
int WebPPictureImportRGB(WebPPicture* picture,
Packit 9c6abc
                         const uint8_t* rgb, int rgb_stride) {
Packit 9c6abc
  return (picture != NULL && rgb != NULL)
Packit 9c6abc
             ? Import(picture, rgb, rgb_stride, 3, 0, 0)
Packit 9c6abc
             : 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
int WebPPictureImportRGBA(WebPPicture* picture,
Packit 9c6abc
                          const uint8_t* rgba, int rgba_stride) {
Packit 9c6abc
  return (picture != NULL && rgba != NULL)
Packit 9c6abc
             ? Import(picture, rgba, rgba_stride, 4, 0, 1)
Packit 9c6abc
             : 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
int WebPPictureImportRGBX(WebPPicture* picture,
Packit 9c6abc
                          const uint8_t* rgba, int rgba_stride) {
Packit 9c6abc
  return (picture != NULL && rgba != NULL)
Packit 9c6abc
             ? Import(picture, rgba, rgba_stride, 4, 0, 0)
Packit 9c6abc
             : 0;
Packit 9c6abc
}
Packit 9c6abc
Packit 9c6abc
//------------------------------------------------------------------------------