133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Copyright 2014 Google Inc. All Rights Reserved.
233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//
333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Use of this source code is governed by a BSD-style license
433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// that can be found in the COPYING file in the root of the source
533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// tree. An additional intellectual property rights grant can be found
633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// in the file PATENTS. All contributing project authors may
733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// be found in the AUTHORS file in the root of the source tree.
833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// -----------------------------------------------------------------------------
933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//
1033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// WebPPicture utils for colorspace conversion
1133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//
1233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Author: Skal (pascal.massimino@gmail.com)
1333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#include <assert.h>
1533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#include <stdlib.h>
1633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#include <math.h>
1733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
18fa39824bb690c5806358871f46940d0450973d8aJames Zern#include "./vp8i_enc.h"
19fa39824bb690c5806358871f46940d0450973d8aJames Zern#include "../utils/random_utils.h"
208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#include "../utils/utils.h"
2133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#include "../dsp/yuv.h"
2233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Uncomment to disable gamma-compression during RGB->U/V averaging
2433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define USE_GAMMA_COMPRESSION
2533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// If defined, use table to compute x / alpha.
278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define USE_INVERSE_ALPHA_TABLE
288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2933f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic const union {
3033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  uint32_t argb;
3133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  uint8_t  bytes[4];
3233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora} test_endian = { 0xff000000u };
3333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define ALPHA_IS_LAST (test_endian.bytes[3] == 0xff)
3433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
3533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
3633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Detection of non-trivial transparency
3733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
3833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Returns true if alpha[] has non-0xff values.
3933f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int CheckNonOpaque(const uint8_t* alpha, int width, int height,
4033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          int x_step, int y_step) {
4133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (alpha == NULL) return 0;
4233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (height-- > 0) {
4333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int x;
4433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (x = 0; x < width * x_step; x += x_step) {
4533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      if (alpha[x] != 0xff) return 1;  // TODO(skal): check 4/8 bytes at a time.
4633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
4733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    alpha += y_step;
4833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
4933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 0;
5033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
5133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
5233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Checking for the presence of non-opaque alpha.
5333f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureHasTransparency(const WebPPicture* picture) {
5433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
5533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!picture->use_argb) {
5633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return CheckNonOpaque(picture->a, picture->width, picture->height,
5733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          1, picture->a_stride);
5833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {
5933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int x, y;
6033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint32_t* argb = picture->argb;
6133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (argb == NULL) return 0;
6233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (y = 0; y < picture->height; ++y) {
6333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      for (x = 0; x < picture->width; ++x) {
6433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        if (argb[x] < 0xff000000u) return 1;   // test any alpha values != 0xff
6533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
6633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      argb += picture->argb_stride;
6733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
6833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
6933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 0;
7033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
7133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
7233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Code for gamma correction
7433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
7533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if defined(USE_GAMMA_COMPRESSION)
7633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
7733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// gamma-compensates loss of resolution during chroma subsampling
788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define kGamma 0.80      // for now we use a different gamma value than kGammaF
7933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaFix 12     // fixed-point precision for linear values
8033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaScale ((1 << kGammaFix) - 1)
8133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabFix 7   // fixed-point fractional bits precision
8233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabScale (1 << kGammaTabFix)
8333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabRounder (kGammaTabScale >> 1)
8433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabSize (1 << (kGammaFix - kGammaTabFix))
8533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8633f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int kLinearToGammaTab[kGammaTabSize + 1];
8733f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic uint16_t kGammaToLinearTab[256];
887c8da7ce66017295a65ec028084b90800be377f8James Zernstatic volatile int kGammaTablesOk = 0;
8933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
907c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {
9133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!kGammaTablesOk) {
9233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int v;
938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const double scale = (double)(1 << kGammaTabFix) / kGammaScale;
948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const double norm = 1. / 255.;
9533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (v = 0; v <= 255; ++v) {
9633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      kGammaToLinearTab[v] =
978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora          (uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5);
9833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
9933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (v = 0; v <= kGammaTabSize; ++v) {
1008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5);
10133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
10233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    kGammaTablesOk = 1;
10333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
10433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
10533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
10633f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE uint32_t GammaToLinear(uint8_t v) {
10733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return kGammaToLinearTab[v];
10833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
10933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int Interpolate(int v) {
11133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int tab_pos = v >> (kGammaTabFix + 2);    // integer part
11233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int x = v & ((kGammaTabScale << 2) - 1);  // fractional part
11333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int v0 = kLinearToGammaTab[tab_pos];
11433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int v1 = kLinearToGammaTab[tab_pos + 1];
11533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x);   // interpolate
1168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(tab_pos + 1 < kGammaTabSize + 1);
1178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return y;
1188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Convert a linear value 'v' to YUV_FIX+2 fixed-point precision
1218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// U/V value, suitable for RGBToU/V calls.
1228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
1238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int y = Interpolate(base_value << shift);   // final uplifted value
1248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (y + kGammaTabRounder) >> kGammaTabFix;    // descale
12533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
12633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
12733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#else
12833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1297c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {}
13033f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; }
13133f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
13233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (int)(base_value << shift);
13333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
13433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
13533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif    // USE_GAMMA_COMPRESSION
13633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
13733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
1388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// RGB -> YUV conversion
1398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToY(int r, int g, int b, VP8Random* const rg) {
1418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (rg == NULL) ? VP8RGBToY(r, g, b, YUV_HALF)
1428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                      : VP8RGBToY(r, g, b, VP8RandomBits(rg, YUV_FIX));
1438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToU(int r, int g, int b, VP8Random* const rg) {
1468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (rg == NULL) ? VP8RGBToU(r, g, b, YUV_HALF << 2)
1478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                      : VP8RGBToU(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
1488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToV(int r, int g, int b, VP8Random* const rg) {
1518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (rg == NULL) ? VP8RGBToV(r, g, b, YUV_HALF << 2)
1528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                      : VP8RGBToV(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
1538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
156fa39824bb690c5806358871f46940d0450973d8aJames Zern// Sharp RGB->YUV conversion
1578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
158fa39824bb690c5806358871f46940d0450973d8aJames Zernstatic const int kNumIterations = 4;
1598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic const int kMinDimensionIterativeConversion = 4;
1608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1617c8da7ce66017295a65ec028084b90800be377f8James Zern// We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some
1628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// banding sometimes. Better use extra precision.
1637c8da7ce66017295a65ec028084b90800be377f8James Zern#define SFIX 2                // fixed-point precision of RGB and Y/W
1647c8da7ce66017295a65ec028084b90800be377f8James Zerntypedef int16_t fixed_t;      // signed type with extra SFIX precision for UV
1657c8da7ce66017295a65ec028084b90800be377f8James Zerntypedef uint16_t fixed_y_t;   // unsigned type with extra SFIX precision for W
1668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1677c8da7ce66017295a65ec028084b90800be377f8James Zern#define SHALF (1 << SFIX >> 1)
1687c8da7ce66017295a65ec028084b90800be377f8James Zern#define MAX_Y_T ((256 << SFIX) - 1)
1697c8da7ce66017295a65ec028084b90800be377f8James Zern#define SROUNDER (1 << (YUV_FIX + SFIX - 1))
1708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if defined(USE_GAMMA_COMPRESSION)
1728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// float variant of gamma-correction
174fa39824bb690c5806358871f46940d0450973d8aJames Zern// We use tables of different size and precision for the Rec709
175fa39824bb690c5806358871f46940d0450973d8aJames Zern// transfer function.
176fa39824bb690c5806358871f46940d0450973d8aJames Zern#define kGammaF (1./0.45)
1778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic float kGammaToLinearTabF[MAX_Y_T + 1];   // size scales with Y_FIX
1788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic float kLinearToGammaTabF[kGammaTabSize + 2];
1797c8da7ce66017295a65ec028084b90800be377f8James Zernstatic volatile int kGammaTablesFOk = 0;
1808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1817c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) {
1828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (!kGammaTablesFOk) {
1838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    int v;
1848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const double norm = 1. / MAX_Y_T;
1858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const double scale = 1. / kGammaTabSize;
186fa39824bb690c5806358871f46940d0450973d8aJames Zern    const double a = 0.099;
187fa39824bb690c5806358871f46940d0450973d8aJames Zern    const double thresh = 0.018;
1888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (v = 0; v <= MAX_Y_T; ++v) {
189fa39824bb690c5806358871f46940d0450973d8aJames Zern      const double g = norm * v;
190fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (g <= thresh * 4.5) {
191fa39824bb690c5806358871f46940d0450973d8aJames Zern        kGammaToLinearTabF[v] = (float)(g / 4.5);
192fa39824bb690c5806358871f46940d0450973d8aJames Zern      } else {
193fa39824bb690c5806358871f46940d0450973d8aJames Zern        const double a_rec = 1. / (1. + a);
194fa39824bb690c5806358871f46940d0450973d8aJames Zern        kGammaToLinearTabF[v] = (float)pow(a_rec * (g + a), kGammaF);
195fa39824bb690c5806358871f46940d0450973d8aJames Zern      }
1968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
1978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (v = 0; v <= kGammaTabSize; ++v) {
198fa39824bb690c5806358871f46940d0450973d8aJames Zern      const double g = scale * v;
199fa39824bb690c5806358871f46940d0450973d8aJames Zern      double value;
200fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (g <= thresh) {
201fa39824bb690c5806358871f46940d0450973d8aJames Zern        value = 4.5 * g;
202fa39824bb690c5806358871f46940d0450973d8aJames Zern      } else {
203fa39824bb690c5806358871f46940d0450973d8aJames Zern        value = (1. + a) * pow(g, 1. / kGammaF) - a;
204fa39824bb690c5806358871f46940d0450973d8aJames Zern      }
205fa39824bb690c5806358871f46940d0450973d8aJames Zern      kLinearToGammaTabF[v] = (float)(MAX_Y_T * value);
2068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
2078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    // to prevent small rounding errors to cause read-overflow:
2088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    kLinearToGammaTabF[kGammaTabSize + 1] = kLinearToGammaTabF[kGammaTabSize];
2098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    kGammaTablesFOk = 1;
2108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
2118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE float GammaToLinearF(int v) {
2148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return kGammaToLinearTabF[v];
2158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2177c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE int LinearToGammaF(float value) {
2188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float v = value * kGammaTabSize;
2198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int tab_pos = (int)v;
2208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float x = v - (float)tab_pos;      // fractional part
2218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float v0 = kLinearToGammaTabF[tab_pos + 0];
2228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float v1 = kLinearToGammaTabF[tab_pos + 1];
2238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float y = v1 * x + v0 * (1.f - x);  // interpolate
2247c8da7ce66017295a65ec028084b90800be377f8James Zern  return (int)(y + .5);
2258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#else
2288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2297c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) {}
2308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE float GammaToLinearF(int v) {
2318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float norm = 1.f / MAX_Y_T;
2328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return norm * v;
2338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2347c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE int LinearToGammaF(float value) {
2357c8da7ce66017295a65ec028084b90800be377f8James Zern  return (int)(MAX_Y_T * value + .5);
2368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif    // USE_GAMMA_COMPRESSION
2398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
2418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic uint8_t clip_8b(fixed_t v) {
2438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
2448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic fixed_y_t clip_y(int y) {
2478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T;
2488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
25133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToGray(int r, int g, int b) {
253fa39824bb690c5806358871f46940d0450973d8aJames Zern  const int luma = 13933 * r + 46871 * g + 4732 * b + YUV_HALF;
2548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (luma >> YUV_FIX);
2558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic float RGBToGrayF(float r, float g, float b) {
258fa39824bb690c5806358871f46940d0450973d8aJames Zern  return (float)(0.2126 * r + 0.7152 * g + 0.0722 * b);
2598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
26033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2617c8da7ce66017295a65ec028084b90800be377f8James Zernstatic int ScaleDown(int a, int b, int c, int d) {
2628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float A = GammaToLinearF(a);
2638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float B = GammaToLinearF(b);
2648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float C = GammaToLinearF(c);
2658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float D = GammaToLinearF(d);
2668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return LinearToGammaF(0.25f * (A + B + C + D));
2678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
269fa39824bb690c5806358871f46940d0450973d8aJames Zernstatic WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w) {
270fa39824bb690c5806358871f46940d0450973d8aJames Zern  int i;
271fa39824bb690c5806358871f46940d0450973d8aJames Zern  for (i = 0; i < w; ++i) {
272fa39824bb690c5806358871f46940d0450973d8aJames Zern    const float R = GammaToLinearF(src[0 * w + i]);
273fa39824bb690c5806358871f46940d0450973d8aJames Zern    const float G = GammaToLinearF(src[1 * w + i]);
274fa39824bb690c5806358871f46940d0450973d8aJames Zern    const float B = GammaToLinearF(src[2 * w + i]);
2758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float Y = RGBToGrayF(R, G, B);
276fa39824bb690c5806358871f46940d0450973d8aJames Zern    dst[i] = (fixed_y_t)LinearToGammaF(Y);
2778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
2788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
280fa39824bb690c5806358871f46940d0450973d8aJames Zernstatic void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
281fa39824bb690c5806358871f46940d0450973d8aJames Zern                         fixed_t* dst, int uv_w) {
282fa39824bb690c5806358871f46940d0450973d8aJames Zern  int i;
283fa39824bb690c5806358871f46940d0450973d8aJames Zern  for (i = 0; i < uv_w; ++i) {
284fa39824bb690c5806358871f46940d0450973d8aJames Zern    const int r = ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1],
285fa39824bb690c5806358871f46940d0450973d8aJames Zern                            src2[0 * uv_w + 0], src2[0 * uv_w + 1]);
286fa39824bb690c5806358871f46940d0450973d8aJames Zern    const int g = ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1],
287fa39824bb690c5806358871f46940d0450973d8aJames Zern                            src2[2 * uv_w + 0], src2[2 * uv_w + 1]);
288fa39824bb690c5806358871f46940d0450973d8aJames Zern    const int b = ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1],
289fa39824bb690c5806358871f46940d0450973d8aJames Zern                            src2[4 * uv_w + 0], src2[4 * uv_w + 1]);
2907c8da7ce66017295a65ec028084b90800be377f8James Zern    const int W = RGBToGray(r, g, b);
291fa39824bb690c5806358871f46940d0450973d8aJames Zern    dst[0 * uv_w] = (fixed_t)(r - W);
292fa39824bb690c5806358871f46940d0450973d8aJames Zern    dst[1 * uv_w] = (fixed_t)(g - W);
293fa39824bb690c5806358871f46940d0450973d8aJames Zern    dst[2 * uv_w] = (fixed_t)(b - W);
294fa39824bb690c5806358871f46940d0450973d8aJames Zern    dst  += 1;
295fa39824bb690c5806358871f46940d0450973d8aJames Zern    src1 += 2;
296fa39824bb690c5806358871f46940d0450973d8aJames Zern    src2 += 2;
2978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
2988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
300fa39824bb690c5806358871f46940d0450973d8aJames Zernstatic void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
301fa39824bb690c5806358871f46940d0450973d8aJames Zern  int i;
302fa39824bb690c5806358871f46940d0450973d8aJames Zern  for (i = 0; i < w; ++i) {
303fa39824bb690c5806358871f46940d0450973d8aJames Zern    y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
3048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
307fa39824bb690c5806358871f46940d0450973d8aJames Zern//------------------------------------------------------------------------------
308fa39824bb690c5806358871f46940d0450973d8aJames Zern
309fa39824bb690c5806358871f46940d0450973d8aJames Zernstatic WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0) {
310fa39824bb690c5806358871f46940d0450973d8aJames Zern  const int v0 = (A * 3 + B + 2) >> 2;
311fa39824bb690c5806358871f46940d0450973d8aJames Zern  return clip_y(v0 + W0);
312fa39824bb690c5806358871f46940d0450973d8aJames Zern}
3138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
3158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3167c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE fixed_y_t UpLift(uint8_t a) {  // 8bit -> SFIX
3177c8da7ce66017295a65ec028084b90800be377f8James Zern  return ((fixed_y_t)a << SFIX) | SHALF;
3188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic void ImportOneRow(const uint8_t* const r_ptr,
3218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         const uint8_t* const g_ptr,
3228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         const uint8_t* const b_ptr,
3238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         int step,
3248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         int pic_width,
3258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         fixed_y_t* const dst) {
3268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i;
327fa39824bb690c5806358871f46940d0450973d8aJames Zern  const int w = (pic_width + 1) & ~1;
3288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (i = 0; i < pic_width; ++i) {
3298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int off = i * step;
330fa39824bb690c5806358871f46940d0450973d8aJames Zern    dst[i + 0 * w] = UpLift(r_ptr[off]);
331fa39824bb690c5806358871f46940d0450973d8aJames Zern    dst[i + 1 * w] = UpLift(g_ptr[off]);
332fa39824bb690c5806358871f46940d0450973d8aJames Zern    dst[i + 2 * w] = UpLift(b_ptr[off]);
3338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (pic_width & 1) {  // replicate rightmost pixel
335fa39824bb690c5806358871f46940d0450973d8aJames Zern    dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
336fa39824bb690c5806358871f46940d0450973d8aJames Zern    dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
337fa39824bb690c5806358871f46940d0450973d8aJames Zern    dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1];
3388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic void InterpolateTwoRows(const fixed_y_t* const best_y,
342fa39824bb690c5806358871f46940d0450973d8aJames Zern                               const fixed_t* prev_uv,
343fa39824bb690c5806358871f46940d0450973d8aJames Zern                               const fixed_t* cur_uv,
344fa39824bb690c5806358871f46940d0450973d8aJames Zern                               const fixed_t* next_uv,
3458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               int w,
346fa39824bb690c5806358871f46940d0450973d8aJames Zern                               fixed_y_t* out1,
347fa39824bb690c5806358871f46940d0450973d8aJames Zern                               fixed_y_t* out2) {
348fa39824bb690c5806358871f46940d0450973d8aJames Zern  const int uv_w = w >> 1;
349fa39824bb690c5806358871f46940d0450973d8aJames Zern  const int len = (w - 1) >> 1;   // length to filter
350fa39824bb690c5806358871f46940d0450973d8aJames Zern  int k = 3;
351fa39824bb690c5806358871f46940d0450973d8aJames Zern  while (k-- > 0) {   // process each R/G/B segments in turn
352fa39824bb690c5806358871f46940d0450973d8aJames Zern    // special boundary case for i==0
353fa39824bb690c5806358871f46940d0450973d8aJames Zern    out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0]);
354fa39824bb690c5806358871f46940d0450973d8aJames Zern    out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w]);
355fa39824bb690c5806358871f46940d0450973d8aJames Zern
356fa39824bb690c5806358871f46940d0450973d8aJames Zern    WebPSharpYUVFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1);
357fa39824bb690c5806358871f46940d0450973d8aJames Zern    WebPSharpYUVFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1);
358fa39824bb690c5806358871f46940d0450973d8aJames Zern
359fa39824bb690c5806358871f46940d0450973d8aJames Zern    // special boundary case for i == w - 1 when w is even
360fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (!(w & 1)) {
361fa39824bb690c5806358871f46940d0450973d8aJames Zern      out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1],
362fa39824bb690c5806358871f46940d0450973d8aJames Zern                            best_y[w - 1 + 0]);
363fa39824bb690c5806358871f46940d0450973d8aJames Zern      out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1],
364fa39824bb690c5806358871f46940d0450973d8aJames Zern                            best_y[w - 1 + w]);
3658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
366fa39824bb690c5806358871f46940d0450973d8aJames Zern    out1 += w;
367fa39824bb690c5806358871f46940d0450973d8aJames Zern    out2 += w;
368fa39824bb690c5806358871f46940d0450973d8aJames Zern    prev_uv += uv_w;
369fa39824bb690c5806358871f46940d0450973d8aJames Zern    cur_uv  += uv_w;
370fa39824bb690c5806358871f46940d0450973d8aJames Zern    next_uv += uv_w;
3718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) {
3757c8da7ce66017295a65ec028084b90800be377f8James Zern  const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER;
3767c8da7ce66017295a65ec028084b90800be377f8James Zern  return clip_8b(16 + (luma >> (YUV_FIX + SFIX)));
3778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) {
3807c8da7ce66017295a65ec028084b90800be377f8James Zern  const int u =  -9719 * r - 19081 * g + 28800 * b + SROUNDER;
3817c8da7ce66017295a65ec028084b90800be377f8James Zern  return clip_8b(128 + (u >> (YUV_FIX + SFIX)));
3828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) {
3857c8da7ce66017295a65ec028084b90800be377f8James Zern  const int v = +28800 * r - 24116 * g -  4684 * b + SROUNDER;
3867c8da7ce66017295a65ec028084b90800be377f8James Zern  return clip_8b(128 + (v >> (YUV_FIX + SFIX)));
3878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
38998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zernstatic int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
3908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                            WebPPicture* const picture) {
3918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j;
39298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  uint8_t* dst_y = picture->y;
39398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  uint8_t* dst_u = picture->u;
39498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  uint8_t* dst_v = picture->v;
39598a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  const fixed_t* const best_uv_base = best_uv;
3968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int w = (picture->width + 1) & ~1;
3978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int h = (picture->height + 1) & ~1;
3988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_w = w >> 1;
3998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_h = h >> 1;
40098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  for (best_uv = best_uv_base, j = 0; j < picture->height; ++j) {
4018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (i = 0; i < picture->width; ++i) {
402fa39824bb690c5806358871f46940d0450973d8aJames Zern      const int off = (i >> 1);
40398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      const int W = best_y[i];
404fa39824bb690c5806358871f46940d0450973d8aJames Zern      const int r = best_uv[off + 0 * uv_w] + W;
405fa39824bb690c5806358871f46940d0450973d8aJames Zern      const int g = best_uv[off + 1 * uv_w] + W;
406fa39824bb690c5806358871f46940d0450973d8aJames Zern      const int b = best_uv[off + 2 * uv_w] + W;
40798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      dst_y[i] = ConvertRGBToY(r, g, b);
4088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
40998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    best_y += w;
41098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    best_uv += (j & 1) * 3 * uv_w;
41198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    dst_y += picture->y_stride;
4128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
41398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
4148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (i = 0; i < uv_w; ++i) {
415fa39824bb690c5806358871f46940d0450973d8aJames Zern      const int off = i;
416fa39824bb690c5806358871f46940d0450973d8aJames Zern      const int r = best_uv[off + 0 * uv_w];
417fa39824bb690c5806358871f46940d0450973d8aJames Zern      const int g = best_uv[off + 1 * uv_w];
418fa39824bb690c5806358871f46940d0450973d8aJames Zern      const int b = best_uv[off + 2 * uv_w];
4198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_u[i] = ConvertRGBToU(r, g, b);
4208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_v[i] = ConvertRGBToV(r, g, b);
4218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
42298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    best_uv += 3 * uv_w;
42398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    dst_u += picture->uv_stride;
42498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    dst_v += picture->uv_stride;
4258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
4268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return 1;
4278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
4288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
4308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Main function
4318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T)))
4338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
43498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zernstatic int PreprocessARGB(const uint8_t* r_ptr,
43598a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                          const uint8_t* g_ptr,
43698a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                          const uint8_t* b_ptr,
4378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                          int step, int rgb_stride,
4388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                          WebPPicture* const picture) {
4398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // we expand the right/bottom border if needed
4408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int w = (picture->width + 1) & ~1;
4418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int h = (picture->height + 1) & ~1;
4428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_w = w >> 1;
4438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_h = h >> 1;
444fa39824bb690c5806358871f46940d0450973d8aJames Zern  uint64_t prev_diff_y_sum = ~0;
445fa39824bb690c5806358871f46940d0450973d8aJames Zern  int j, iter;
4468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // TODO(skal): allocate one big memory chunk. But for now, it's easier
4488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // for valgrind debugging to have several chunks.
4498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t);   // scratch
45098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t);
45198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t);
4528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
45398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
45498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
4558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
45698a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  fixed_y_t* best_y = best_y_base;
45798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  fixed_y_t* target_y = target_y_base;
45898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  fixed_t* best_uv = best_uv_base;
45998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  fixed_t* target_uv = target_uv_base;
460fa39824bb690c5806358871f46940d0450973d8aJames Zern  const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h);
4618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int ok;
4628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
46398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  if (best_y_base == NULL || best_uv_base == NULL ||
46498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      target_y_base == NULL || target_uv_base == NULL ||
4658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      best_rgb_y == NULL || best_rgb_uv == NULL ||
4668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      tmp_buffer == NULL) {
4678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
4688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    goto End;
4698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
4708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(picture->width >= kMinDimensionIterativeConversion);
4718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(picture->height >= kMinDimensionIterativeConversion);
4728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
473fa39824bb690c5806358871f46940d0450973d8aJames Zern  WebPInitConvertARGBToYUV();
474fa39824bb690c5806358871f46940d0450973d8aJames Zern
4758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // Import RGB samples to W/RGB representation.
4768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (j = 0; j < picture->height; j += 2) {
4778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int is_last_row = (j == picture->height - 1);
478fa39824bb690c5806358871f46940d0450973d8aJames Zern    fixed_y_t* const src1 = tmp_buffer + 0 * w;
4798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    fixed_y_t* const src2 = tmp_buffer + 3 * w;
4808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    // prepare two rows of input
48298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    ImportOneRow(r_ptr, g_ptr, b_ptr, step, picture->width, src1);
4838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (!is_last_row) {
48498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride,
4858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                   step, picture->width, src2);
4868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    } else {
4878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      memcpy(src2, src1, 3 * w * sizeof(*src2));
4888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
489fa39824bb690c5806358871f46940d0450973d8aJames Zern    StoreGray(src1, best_y + 0, w);
490fa39824bb690c5806358871f46940d0450973d8aJames Zern    StoreGray(src2, best_y + w, w);
491fa39824bb690c5806358871f46940d0450973d8aJames Zern
49298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    UpdateW(src1, target_y, w);
49398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    UpdateW(src2, target_y + w, w);
494fa39824bb690c5806358871f46940d0450973d8aJames Zern    UpdateChroma(src1, src2, target_uv, uv_w);
49598a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
49698a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    best_y += 2 * w;
49798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    best_uv += 3 * uv_w;
49898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    target_y += 2 * w;
49998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    target_uv += 3 * uv_w;
50098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    r_ptr += 2 * rgb_stride;
50198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    g_ptr += 2 * rgb_stride;
50298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    b_ptr += 2 * rgb_stride;
5038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
5048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // Iterate and resolve clipping conflicts.
5068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (iter = 0; iter < kNumIterations; ++iter) {
50798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    const fixed_t* cur_uv = best_uv_base;
50898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    const fixed_t* prev_uv = best_uv_base;
509fa39824bb690c5806358871f46940d0450973d8aJames Zern    uint64_t diff_y_sum = 0;
51098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern
51198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    best_y = best_y_base;
51298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    best_uv = best_uv_base;
51398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    target_y = target_y_base;
51498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    target_uv = target_uv_base;
5158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (j = 0; j < h; j += 2) {
516fa39824bb690c5806358871f46940d0450973d8aJames Zern      fixed_y_t* const src1 = tmp_buffer + 0 * w;
5178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      fixed_y_t* const src2 = tmp_buffer + 3 * w;
5188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      {
5198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
52098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, src1, src2);
5218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        prev_uv = cur_uv;
5228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        cur_uv = next_uv;
5238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
5248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      UpdateW(src1, best_rgb_y + 0 * w, w);
5268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      UpdateW(src2, best_rgb_y + 1 * w, w);
527fa39824bb690c5806358871f46940d0450973d8aJames Zern      UpdateChroma(src1, src2, best_rgb_uv, uv_w);
5288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      // update two rows of Y and one row of RGB
530fa39824bb690c5806358871f46940d0450973d8aJames Zern      diff_y_sum += WebPSharpYUVUpdateY(target_y, best_rgb_y, best_y, 2 * w);
531fa39824bb690c5806358871f46940d0450973d8aJames Zern      WebPSharpYUVUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
532fa39824bb690c5806358871f46940d0450973d8aJames Zern
53398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      best_y += 2 * w;
53498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      best_uv += 3 * uv_w;
53598a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      target_y += 2 * w;
53698a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      target_uv += 3 * uv_w;
5378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
5387c8da7ce66017295a65ec028084b90800be377f8James Zern    // test exit condition
539fa39824bb690c5806358871f46940d0450973d8aJames Zern    if (iter > 0) {
540fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (diff_y_sum < diff_y_threshold) break;
541fa39824bb690c5806358871f46940d0450973d8aJames Zern      if (diff_y_sum > prev_diff_y_sum) break;
5427c8da7ce66017295a65ec028084b90800be377f8James Zern    }
543fa39824bb690c5806358871f46940d0450973d8aJames Zern    prev_diff_y_sum = diff_y_sum;
5448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
5458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // final reconstruction
54698a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  ok = ConvertWRGBToYUV(best_y_base, best_uv_base, picture);
5478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora End:
54998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  WebPSafeFree(best_y_base);
55098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  WebPSafeFree(best_uv_base);
55198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  WebPSafeFree(target_y_base);
55298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  WebPSafeFree(target_uv_base);
5538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(best_rgb_y);
5548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(best_rgb_uv);
5558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(tmp_buffer);
5568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return ok;
5578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
5588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SAFE_ALLOC
5598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
5618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// "Fast" regular RGB->YUV
5628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM4(ptr, step) LinearToGamma(                     \
5648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[0]) +                              \
5658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[(step)]) +                         \
5668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[rgb_stride]) +                     \
5678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[rgb_stride + (step)]), 0)          \
5688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM2(ptr) \
57033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    LinearToGamma(GammaToLinear((ptr)[0]) + GammaToLinear((ptr)[rgb_stride]), 1)
57133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
5728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM2ALPHA(ptr) ((ptr)[0] + (ptr)[rgb_stride])
5738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM4ALPHA(ptr) (SUM2ALPHA(ptr) + SUM2ALPHA((ptr) + 4))
5748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if defined(USE_INVERSE_ALPHA_TABLE)
5768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic const int kAlphaFix = 19;
5788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Following table is (1 << kAlphaFix) / a. The (v * kInvAlpha[a]) >> kAlphaFix
5798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// formula is then equal to v / a in most (99.6%) cases. Note that this table
5808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// and constant are adjusted very tightly to fit 32b arithmetic.
5818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// In particular, they use the fact that the operands for 'v / a' are actually
5828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3
5838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// with ai in [0..255] and pi in [0..1<<kGammaFix). The constraint to avoid
5848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// overflow is: kGammaFix + kAlphaFix <= 31.
5858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic const uint32_t kInvAlpha[4 * 0xff + 1] = {
5868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  0,  /* alpha = 0 */
5878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  524288, 262144, 174762, 131072, 104857, 87381, 74898, 65536,
5888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  58254, 52428, 47662, 43690, 40329, 37449, 34952, 32768,
5898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  30840, 29127, 27594, 26214, 24966, 23831, 22795, 21845,
5908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  20971, 20164, 19418, 18724, 18078, 17476, 16912, 16384,
5918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  15887, 15420, 14979, 14563, 14169, 13797, 13443, 13107,
5928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  12787, 12483, 12192, 11915, 11650, 11397, 11155, 10922,
5938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  10699, 10485, 10280, 10082, 9892, 9709, 9532, 9362,
5948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  9198, 9039, 8886, 8738, 8594, 8456, 8322, 8192,
5958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  8065, 7943, 7825, 7710, 7598, 7489, 7384, 7281,
5968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  7182, 7084, 6990, 6898, 6808, 6721, 6636, 6553,
5978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  6472, 6393, 6316, 6241, 6168, 6096, 6026, 5957,
5988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  5890, 5825, 5761, 5698, 5637, 5577, 5518, 5461,
5998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  5405, 5349, 5295, 5242, 5190, 5140, 5090, 5041,
6008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4993, 4946, 4899, 4854, 4809, 4766, 4723, 4681,
6018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4639, 4599, 4559, 4519, 4481, 4443, 4405, 4369,
6028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4332, 4297, 4262, 4228, 4194, 4161, 4128, 4096,
6038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4064, 4032, 4002, 3971, 3942, 3912, 3883, 3855,
6048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3826, 3799, 3771, 3744, 3718, 3692, 3666, 3640,
6058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3615, 3591, 3566, 3542, 3518, 3495, 3472, 3449,
6068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3426, 3404, 3382, 3360, 3339, 3318, 3297, 3276,
6078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3256, 3236, 3216, 3196, 3177, 3158, 3139, 3120,
6088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3102, 3084, 3066, 3048, 3030, 3013, 2995, 2978,
6098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2962, 2945, 2928, 2912, 2896, 2880, 2864, 2849,
6108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2833, 2818, 2803, 2788, 2774, 2759, 2744, 2730,
6118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2716, 2702, 2688, 2674, 2661, 2647, 2634, 2621,
6128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2608, 2595, 2582, 2570, 2557, 2545, 2532, 2520,
6138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2508, 2496, 2484, 2473, 2461, 2449, 2438, 2427,
6148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2416, 2404, 2394, 2383, 2372, 2361, 2351, 2340,
6158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2330, 2319, 2309, 2299, 2289, 2279, 2269, 2259,
6168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2250, 2240, 2231, 2221, 2212, 2202, 2193, 2184,
6178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2175, 2166, 2157, 2148, 2139, 2131, 2122, 2114,
6188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2105, 2097, 2088, 2080, 2072, 2064, 2056, 2048,
6198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2040, 2032, 2024, 2016, 2008, 2001, 1993, 1985,
6208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1978, 1971, 1963, 1956, 1949, 1941, 1934, 1927,
6218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1920, 1913, 1906, 1899, 1892, 1885, 1879, 1872,
6228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1865, 1859, 1852, 1846, 1839, 1833, 1826, 1820,
6238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1814, 1807, 1801, 1795, 1789, 1783, 1777, 1771,
6248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1765, 1759, 1753, 1747, 1741, 1736, 1730, 1724,
6258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1718, 1713, 1707, 1702, 1696, 1691, 1685, 1680,
6268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1675, 1669, 1664, 1659, 1653, 1648, 1643, 1638,
6278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1633, 1628, 1623, 1618, 1613, 1608, 1603, 1598,
6288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1593, 1588, 1583, 1579, 1574, 1569, 1565, 1560,
6298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1555, 1551, 1546, 1542, 1537, 1533, 1528, 1524,
6308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1519, 1515, 1510, 1506, 1502, 1497, 1493, 1489,
6318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1485, 1481, 1476, 1472, 1468, 1464, 1460, 1456,
6328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1452, 1448, 1444, 1440, 1436, 1432, 1428, 1424,
6338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1420, 1416, 1413, 1409, 1405, 1401, 1398, 1394,
6348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1390, 1387, 1383, 1379, 1376, 1372, 1368, 1365,
6358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1361, 1358, 1354, 1351, 1347, 1344, 1340, 1337,
6368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1334, 1330, 1327, 1323, 1320, 1317, 1314, 1310,
6378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1307, 1304, 1300, 1297, 1294, 1291, 1288, 1285,
6388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1281, 1278, 1275, 1272, 1269, 1266, 1263, 1260,
6398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1257, 1254, 1251, 1248, 1245, 1242, 1239, 1236,
6408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1233, 1230, 1227, 1224, 1222, 1219, 1216, 1213,
6418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1210, 1208, 1205, 1202, 1199, 1197, 1194, 1191,
6428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1188, 1186, 1183, 1180, 1178, 1175, 1172, 1170,
6438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1167, 1165, 1162, 1159, 1157, 1154, 1152, 1149,
6448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1147, 1144, 1142, 1139, 1137, 1134, 1132, 1129,
6458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1127, 1125, 1122, 1120, 1117, 1115, 1113, 1110,
6468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1108, 1106, 1103, 1101, 1099, 1096, 1094, 1092,
6478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1089, 1087, 1085, 1083, 1081, 1078, 1076, 1074,
6488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1072, 1069, 1067, 1065, 1063, 1061, 1059, 1057,
6498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1054, 1052, 1050, 1048, 1046, 1044, 1042, 1040,
6508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1038, 1036, 1034, 1032, 1030, 1028, 1026, 1024,
6518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1022, 1020, 1018, 1016, 1014, 1012, 1010, 1008,
6528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1006, 1004, 1002, 1000, 998, 996, 994, 992,
6538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  991, 989, 987, 985, 983, 981, 979, 978,
6548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  976, 974, 972, 970, 969, 967, 965, 963,
6558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  961, 960, 958, 956, 954, 953, 951, 949,
6568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  948, 946, 944, 942, 941, 939, 937, 936,
6578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  934, 932, 931, 929, 927, 926, 924, 923,
6588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  921, 919, 918, 916, 914, 913, 911, 910,
6598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  908, 907, 905, 903, 902, 900, 899, 897,
6608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  896, 894, 893, 891, 890, 888, 887, 885,
6618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  884, 882, 881, 879, 878, 876, 875, 873,
6628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  872, 870, 869, 868, 866, 865, 863, 862,
6638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  860, 859, 858, 856, 855, 853, 852, 851,
6648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  849, 848, 846, 845, 844, 842, 841, 840,
6658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  838, 837, 836, 834, 833, 832, 830, 829,
6668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  828, 826, 825, 824, 823, 821, 820, 819,
6678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  817, 816, 815, 814, 812, 811, 810, 809,
6688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  807, 806, 805, 804, 802, 801, 800, 799,
6698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  798, 796, 795, 794, 793, 791, 790, 789,
6708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  788, 787, 786, 784, 783, 782, 781, 780,
6718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  779, 777, 776, 775, 774, 773, 772, 771,
6728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  769, 768, 767, 766, 765, 764, 763, 762,
6738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  760, 759, 758, 757, 756, 755, 754, 753,
6748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  752, 751, 750, 748, 747, 746, 745, 744,
6758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  743, 742, 741, 740, 739, 738, 737, 736,
6768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  735, 734, 733, 732, 731, 730, 729, 728,
6778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  727, 726, 725, 724, 723, 722, 721, 720,
6788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  719, 718, 717, 716, 715, 714, 713, 712,
6798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  711, 710, 709, 708, 707, 706, 705, 704,
6808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  703, 702, 701, 700, 699, 699, 698, 697,
6818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  696, 695, 694, 693, 692, 691, 690, 689,
6828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  688, 688, 687, 686, 685, 684, 683, 682,
6838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  681, 680, 680, 679, 678, 677, 676, 675,
6848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  674, 673, 673, 672, 671, 670, 669, 668,
6858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  667, 667, 666, 665, 664, 663, 662, 661,
6868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  661, 660, 659, 658, 657, 657, 656, 655,
6878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  654, 653, 652, 652, 651, 650, 649, 648,
6888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  648, 647, 646, 645, 644, 644, 643, 642,
6898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  641, 640, 640, 639, 638, 637, 637, 636,
6908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  635, 634, 633, 633, 632, 631, 630, 630,
6918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  629, 628, 627, 627, 626, 625, 624, 624,
6928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  623, 622, 621, 621, 620, 619, 618, 618,
6938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  617, 616, 616, 615, 614, 613, 613, 612,
6948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  611, 611, 610, 609, 608, 608, 607, 606,
6958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  606, 605, 604, 604, 603, 602, 601, 601,
6968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  600, 599, 599, 598, 597, 597, 596, 595,
6978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  595, 594, 593, 593, 592, 591, 591, 590,
6988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  589, 589, 588, 587, 587, 586, 585, 585,
6998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  584, 583, 583, 582, 581, 581, 580, 579,
7008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  579, 578, 578, 577, 576, 576, 575, 574,
7018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  574, 573, 572, 572, 571, 571, 570, 569,
7028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  569, 568, 568, 567, 566, 566, 565, 564,
7038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  564, 563, 563, 562, 561, 561, 560, 560,
7048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  559, 558, 558, 557, 557, 556, 555, 555,
7058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  554, 554, 553, 553, 552, 551, 551, 550,
7068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  550, 549, 548, 548, 547, 547, 546, 546,
7078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  545, 544, 544, 543, 543, 542, 542, 541,
7088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  541, 540, 539, 539, 538, 538, 537, 537,
7098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  536, 536, 535, 534, 534, 533, 533, 532,
7108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  532, 531, 531, 530, 530, 529, 529, 528,
7118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  527, 527, 526, 526, 525, 525, 524, 524,
7128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  523, 523, 522, 522, 521, 521, 520, 520,
7138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  519, 519, 518, 518, 517, 517, 516, 516,
7148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  515, 515, 514, 514
7158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora};
7168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Note that LinearToGamma() expects the values to be premultiplied by 4,
7188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// so we incorporate this factor 4 inside the DIVIDE_BY_ALPHA macro directly.
7198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define DIVIDE_BY_ALPHA(sum, a)  (((sum) * kInvAlpha[(a)]) >> (kAlphaFix - 2))
7208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#else
7228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define DIVIDE_BY_ALPHA(sum, a) (4 * (sum) / (a))
7248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif  // USE_INVERSE_ALPHA_TABLE
7268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int LinearToGammaWeighted(const uint8_t* src,
7288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             const uint8_t* a_ptr,
7298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             uint32_t total_a, int step,
7308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             int rgb_stride) {
7318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const uint32_t sum =
7328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[0] * GammaToLinear(src[0]) +
7338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[step] * GammaToLinear(src[step]) +
7348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[rgb_stride] * GammaToLinear(src[rgb_stride]) +
7358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[rgb_stride + step] * GammaToLinear(src[rgb_stride + step]);
7368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(total_a > 0 && total_a <= 4 * 0xff);
7378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if defined(USE_INVERSE_ALPHA_TABLE)
7388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert((uint64_t)sum * kInvAlpha[total_a] < ((uint64_t)1 << 32));
7398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif
7408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return LinearToGamma(DIVIDE_BY_ALPHA(sum, total_a), 0);
7418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
7428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE void ConvertRowToY(const uint8_t* const r_ptr,
7448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      const uint8_t* const g_ptr,
7458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      const uint8_t* const b_ptr,
7468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      int step,
7478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      uint8_t* const dst_y,
7488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      int width,
7498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      VP8Random* const rg) {
7508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j;
7517c8da7ce66017295a65ec028084b90800be377f8James Zern  for (i = 0, j = 0; i < width; i += 1, j += step) {
7528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_y[i] = RGBToY(r_ptr[j], g_ptr[j], b_ptr[j], rg);
7538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
7548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
7558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7567c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE void AccumulateRGBA(const uint8_t* const r_ptr,
7577c8da7ce66017295a65ec028084b90800be377f8James Zern                                       const uint8_t* const g_ptr,
7587c8da7ce66017295a65ec028084b90800be377f8James Zern                                       const uint8_t* const b_ptr,
7597c8da7ce66017295a65ec028084b90800be377f8James Zern                                       const uint8_t* const a_ptr,
7607c8da7ce66017295a65ec028084b90800be377f8James Zern                                       int rgb_stride,
7617c8da7ce66017295a65ec028084b90800be377f8James Zern                                       uint16_t* dst, int width) {
7628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j;
7637c8da7ce66017295a65ec028084b90800be377f8James Zern  // we loop over 2x2 blocks and produce one R/G/B/A value for each.
7647c8da7ce66017295a65ec028084b90800be377f8James Zern  for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * 4, dst += 4) {
7658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const uint32_t a = SUM4ALPHA(a_ptr + j);
7668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    int r, g, b;
7678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (a == 4 * 0xff || a == 0) {
7688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = SUM4(r_ptr + j, 4);
7698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = SUM4(g_ptr + j, 4);
7708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = SUM4(b_ptr + j, 4);
7718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    } else {
7728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 4, rgb_stride);
7738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 4, rgb_stride);
7748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 4, rgb_stride);
7758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
7767c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[0] = r;
7777c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[1] = g;
7787c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[2] = b;
7797c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[3] = a;
7808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
7818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (width & 1) {
7828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const uint32_t a = 2u * SUM2ALPHA(a_ptr + j);
7838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    int r, g, b;
7848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (a == 4 * 0xff || a == 0) {
7858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = SUM2(r_ptr + j);
7868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = SUM2(g_ptr + j);
7878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = SUM2(b_ptr + j);
7888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    } else {
7898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 0, rgb_stride);
7908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 0, rgb_stride);
7918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 0, rgb_stride);
7928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
7937c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[0] = r;
7947c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[1] = g;
7957c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[2] = b;
7967c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[3] = a;
7977c8da7ce66017295a65ec028084b90800be377f8James Zern  }
7987c8da7ce66017295a65ec028084b90800be377f8James Zern}
7997c8da7ce66017295a65ec028084b90800be377f8James Zern
8007c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE void AccumulateRGB(const uint8_t* const r_ptr,
8017c8da7ce66017295a65ec028084b90800be377f8James Zern                                      const uint8_t* const g_ptr,
8027c8da7ce66017295a65ec028084b90800be377f8James Zern                                      const uint8_t* const b_ptr,
8037c8da7ce66017295a65ec028084b90800be377f8James Zern                                      int step, int rgb_stride,
8047c8da7ce66017295a65ec028084b90800be377f8James Zern                                      uint16_t* dst, int width) {
8057c8da7ce66017295a65ec028084b90800be377f8James Zern  int i, j;
8067c8da7ce66017295a65ec028084b90800be377f8James Zern  for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * step, dst += 4) {
8077c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[0] = SUM4(r_ptr + j, step);
8087c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[1] = SUM4(g_ptr + j, step);
8097c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[2] = SUM4(b_ptr + j, step);
8107c8da7ce66017295a65ec028084b90800be377f8James Zern  }
8117c8da7ce66017295a65ec028084b90800be377f8James Zern  if (width & 1) {
8127c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[0] = SUM2(r_ptr + j);
8137c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[1] = SUM2(g_ptr + j);
8147c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[2] = SUM2(b_ptr + j);
8158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
8168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
8178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
8187c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE void ConvertRowsToUV(const uint16_t* rgb,
8198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        uint8_t* const dst_u,
8208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        uint8_t* const dst_v,
8218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        int width,
8228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        VP8Random* const rg) {
8237c8da7ce66017295a65ec028084b90800be377f8James Zern  int i;
8247c8da7ce66017295a65ec028084b90800be377f8James Zern  for (i = 0; i < width; i += 1, rgb += 4) {
8257c8da7ce66017295a65ec028084b90800be377f8James Zern    const int r = rgb[0], g = rgb[1], b = rgb[2];
8268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_u[i] = RGBToU(r, g, b, rg);
8278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_v[i] = RGBToV(r, g, b, rg);
8288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
82933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
83033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
83198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zernstatic int ImportYUVAFromRGBA(const uint8_t* r_ptr,
83298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                              const uint8_t* g_ptr,
83398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                              const uint8_t* b_ptr,
83498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                              const uint8_t* a_ptr,
83533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              int step,         // bytes per pixel
83633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              int rgb_stride,   // bytes per scanline
83733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              float dithering,
8388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              int use_iterative_conversion,
83933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              WebPPicture* const picture) {
8408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int y;
84133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int width = picture->width;
84233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int height = picture->height;
84333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride);
8447c8da7ce66017295a65ec028084b90800be377f8James Zern  const int is_rgb = (r_ptr < b_ptr);  // otherwise it's bgr
84533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  picture->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
84733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  picture->use_argb = 0;
84833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // disable smart conversion if source is too small (overkill).
8508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (width < kMinDimensionIterativeConversion ||
8518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      height < kMinDimensionIterativeConversion) {
8528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    use_iterative_conversion = 0;
8538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
85433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (!WebPPictureAllocYUVA(picture, width, height)) {
8568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    return 0;
8578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
8588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (has_alpha) {
8598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    WebPInitAlphaProcessing();
8608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    assert(step == 4);
8617c8da7ce66017295a65ec028084b90800be377f8James Zern#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE)
8628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    assert(kAlphaFix + kGammaFix <= 31);
8638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif
86433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
86533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (use_iterative_conversion) {
8678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    InitGammaTablesF();
8688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) {
8698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      return 0;
87033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
8718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (has_alpha) {
8728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      WebPExtractAlpha(a_ptr, rgb_stride, width, height,
8738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                       picture->a, picture->a_stride);
87433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
8758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  } else {
8767c8da7ce66017295a65ec028084b90800be377f8James Zern    const int uv_width = (width + 1) >> 1;
8777c8da7ce66017295a65ec028084b90800be377f8James Zern    int use_dsp = (step == 3);  // use special function in this case
8787c8da7ce66017295a65ec028084b90800be377f8James Zern    // temporary storage for accumulated R/G/B values during conversion to U/V
8797c8da7ce66017295a65ec028084b90800be377f8James Zern    uint16_t* const tmp_rgb =
8807c8da7ce66017295a65ec028084b90800be377f8James Zern        (uint16_t*)WebPSafeMalloc(4 * uv_width, sizeof(*tmp_rgb));
8818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_y = picture->y;
8828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_u = picture->u;
8838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_v = picture->v;
8848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_a = picture->a;
8858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
8868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    VP8Random base_rg;
8878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    VP8Random* rg = NULL;
8888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (dithering > 0.) {
8898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      VP8InitRandom(&base_rg, dithering);
8908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      rg = &base_rg;
8917c8da7ce66017295a65ec028084b90800be377f8James Zern      use_dsp = 0;   // can't use dsp in this case
89233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
8937c8da7ce66017295a65ec028084b90800be377f8James Zern    WebPInitConvertARGBToYUV();
8948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    InitGammaTables();
8958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
8967c8da7ce66017295a65ec028084b90800be377f8James Zern    if (tmp_rgb == NULL) return 0;  // malloc error
8977c8da7ce66017295a65ec028084b90800be377f8James Zern
8988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    // Downsample Y/U/V planes, two rows at a time
8998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (y = 0; y < (height >> 1); ++y) {
9008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      int rows_have_alpha = has_alpha;
9017c8da7ce66017295a65ec028084b90800be377f8James Zern      if (use_dsp) {
9027c8da7ce66017295a65ec028084b90800be377f8James Zern        if (is_rgb) {
90398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertRGB24ToY(r_ptr, dst_y, width);
90498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertRGB24ToY(r_ptr + rgb_stride,
90598a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                              dst_y + picture->y_stride, width);
9067c8da7ce66017295a65ec028084b90800be377f8James Zern        } else {
90798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertBGR24ToY(b_ptr, dst_y, width);
90898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertBGR24ToY(b_ptr + rgb_stride,
90998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                              dst_y + picture->y_stride, width);
9107c8da7ce66017295a65ec028084b90800be377f8James Zern        }
9117c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
91298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg);
91398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        ConvertRowToY(r_ptr + rgb_stride,
91498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                      g_ptr + rgb_stride,
91598a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                      b_ptr + rgb_stride, step,
9167c8da7ce66017295a65ec028084b90800be377f8James Zern                      dst_y + picture->y_stride, width, rg);
9177c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_y += 2 * picture->y_stride;
9198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (has_alpha) {
92098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        rows_have_alpha &= !WebPExtractAlpha(a_ptr, rgb_stride, width, 2,
9218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             dst_a, picture->a_stride);
9228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        dst_a += 2 * picture->a_stride;
9238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9247c8da7ce66017295a65ec028084b90800be377f8James Zern      // Collect averaged R/G/B(/A)
9258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (!rows_have_alpha) {
92698a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        AccumulateRGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, tmp_rgb, width);
9277c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
92898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, rgb_stride, tmp_rgb, width);
9297c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9307c8da7ce66017295a65ec028084b90800be377f8James Zern      // Convert to U/V
9317c8da7ce66017295a65ec028084b90800be377f8James Zern      if (rg == NULL) {
9327c8da7ce66017295a65ec028084b90800be377f8James Zern        WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
9338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      } else {
9347c8da7ce66017295a65ec028084b90800be377f8James Zern        ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
9358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_u += picture->uv_stride;
9378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_v += picture->uv_stride;
93898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      r_ptr += 2 * rgb_stride;
93998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      b_ptr += 2 * rgb_stride;
94098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      g_ptr += 2 * rgb_stride;
94198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      if (has_alpha) a_ptr += 2 * rgb_stride;
9428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
9438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (height & 1) {    // extra last row
9448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      int row_has_alpha = has_alpha;
9457c8da7ce66017295a65ec028084b90800be377f8James Zern      if (use_dsp) {
9467c8da7ce66017295a65ec028084b90800be377f8James Zern        if (r_ptr < b_ptr) {
94798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertRGB24ToY(r_ptr, dst_y, width);
9487c8da7ce66017295a65ec028084b90800be377f8James Zern        } else {
94998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertBGR24ToY(b_ptr, dst_y, width);
9507c8da7ce66017295a65ec028084b90800be377f8James Zern        }
9517c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
95298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg);
9537c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (row_has_alpha) {
95598a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        row_has_alpha &= !WebPExtractAlpha(a_ptr, 0, width, 1, dst_a, 0);
9568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9577c8da7ce66017295a65ec028084b90800be377f8James Zern      // Collect averaged R/G/B(/A)
9588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (!row_has_alpha) {
9597c8da7ce66017295a65ec028084b90800be377f8James Zern        // Collect averaged R/G/B
96098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        AccumulateRGB(r_ptr, g_ptr, b_ptr, step, /* rgb_stride = */ 0,
96198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                      tmp_rgb, width);
9627c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
96398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, /* rgb_stride = */ 0,
96498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                       tmp_rgb, width);
9657c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9667c8da7ce66017295a65ec028084b90800be377f8James Zern      if (rg == NULL) {
9677c8da7ce66017295a65ec028084b90800be377f8James Zern        WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
9688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      } else {
9697c8da7ce66017295a65ec028084b90800be377f8James Zern        ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
97033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
97133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
9727c8da7ce66017295a65ec028084b90800be377f8James Zern    WebPSafeFree(tmp_rgb);
97333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
97433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
97533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
97633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
97733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#undef SUM4
9788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM2
9798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM4ALPHA
9808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM2ALPHA
98133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
98233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
98333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// call for ARGB->YUVA conversion
98433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
9858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int PictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace,
9868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                             float dithering, int use_iterative_conversion) {
98733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
98833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture->argb == NULL) {
98933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
9908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  } else if ((colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
9918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
99233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {
99333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const argb = (const uint8_t*)picture->argb;
99433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const r = ALPHA_IS_LAST ? argb + 2 : argb + 1;
99533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const g = ALPHA_IS_LAST ? argb + 1 : argb + 2;
99633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const b = ALPHA_IS_LAST ? argb + 0 : argb + 3;
99733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const a = ALPHA_IS_LAST ? argb + 3 : argb + 0;
99833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
9998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    picture->colorspace = WEBP_YUV420;
100033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride,
10018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              dithering, use_iterative_conversion, picture);
100233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
100333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
100433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
10058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Aroraint WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace,
10068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                  float dithering) {
10078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, colorspace, dithering, 0);
10088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
10098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
101033f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) {
10118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, colorspace, 0.f, 0);
10128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
10138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1014fa39824bb690c5806358871f46940d0450973d8aJames Zernint WebPPictureSharpARGBToYUVA(WebPPicture* picture) {
10158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1);
101633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
1017fa39824bb690c5806358871f46940d0450973d8aJames Zern// for backward compatibility
1018fa39824bb690c5806358871f46940d0450973d8aJames Zernint WebPPictureSmartARGBToYUVA(WebPPicture* picture) {
1019fa39824bb690c5806358871f46940d0450973d8aJames Zern  return WebPPictureSharpARGBToYUVA(picture);
1020fa39824bb690c5806358871f46940d0450973d8aJames Zern}
102133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
102233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
102333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// call for YUVA -> ARGB conversion
102433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
102533f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureYUVAToARGB(WebPPicture* picture) {
102633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
102733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture->y == NULL || picture->u == NULL || picture->v == NULL) {
102833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
102933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
103033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) {
103133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
103233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
103333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if ((picture->colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
103433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
103533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
103633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  // Allocate a new argb buffer (discarding the previous one).
103733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!WebPPictureAllocARGB(picture, picture->width, picture->height)) return 0;
103833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  picture->use_argb = 1;
103933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
104033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  // Convert
104133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  {
104233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int y;
104333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int width = picture->width;
104433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int height = picture->height;
104533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int argb_stride = 4 * picture->argb_stride;
104633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    uint8_t* dst = (uint8_t*)picture->argb;
104733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t *cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y;
104833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    WebPUpsampleLinePairFunc upsample = WebPGetLinePairConverter(ALPHA_IS_LAST);
104933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
105033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // First row, with replicated top samples.
105133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
105233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    cur_y += picture->y_stride;
105333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    dst += argb_stride;
105433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Center rows.
105533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (y = 1; y + 1 < height; y += 2) {
105633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t* const top_u = cur_u;
105733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t* const top_v = cur_v;
105833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_u += picture->uv_stride;
105933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_v += picture->uv_stride;
106033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      upsample(cur_y, cur_y + picture->y_stride, top_u, top_v, cur_u, cur_v,
106133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora               dst, dst + argb_stride, width);
106233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_y += 2 * picture->y_stride;
106333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      dst += 2 * argb_stride;
106433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
106533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Last row (if needed), with replicated bottom samples.
106633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (height > 1 && !(height & 1)) {
106733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
106833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
106933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Insert alpha values if needed, in replacement for the default 0xff ones.
107033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (picture->colorspace & WEBP_CSP_ALPHA_BIT) {
107133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      for (y = 0; y < height; ++y) {
107233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        uint32_t* const argb_dst = picture->argb + y * picture->argb_stride;
107333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        const uint8_t* const src = picture->a + y * picture->a_stride;
107433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        int x;
107533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        for (x = 0; x < width; ++x) {
107633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora          argb_dst[x] = (argb_dst[x] & 0x00ffffffu) | ((uint32_t)src[x] << 24);
107733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        }
107833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
107933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
108033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
108133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
108233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
108333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
108433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
108533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// automatic import / conversion
108633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
108733f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int Import(WebPPicture* const picture,
108833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                  const uint8_t* const rgb, int rgb_stride,
108933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                  int step, int swap_rb, int import_alpha) {
109033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  int y;
109198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  const uint8_t* r_ptr = rgb + (swap_rb ? 2 : 0);
109298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  const uint8_t* g_ptr = rgb + 1;
109398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  const uint8_t* b_ptr = rgb + (swap_rb ? 0 : 2);
109498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL;
109533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int width = picture->width;
109633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int height = picture->height;
109733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
109833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!picture->use_argb) {
109933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
11008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              0.f /* no dithering */, 0, picture);
110133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
110233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!WebPPictureAlloc(picture)) return 0;
110333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
11047c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8EncDspARGBInit();
11057c8da7ce66017295a65ec028084b90800be377f8James Zern
11067c8da7ce66017295a65ec028084b90800be377f8James Zern  if (import_alpha) {
110798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    uint32_t* dst = picture->argb;
11087c8da7ce66017295a65ec028084b90800be377f8James Zern    assert(step == 4);
11097c8da7ce66017295a65ec028084b90800be377f8James Zern    for (y = 0; y < height; ++y) {
111098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      VP8PackARGB(a_ptr, r_ptr, g_ptr, b_ptr, width, dst);
111198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      a_ptr += rgb_stride;
111298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      r_ptr += rgb_stride;
111398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      g_ptr += rgb_stride;
111498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      b_ptr += rgb_stride;
111598a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      dst += picture->argb_stride;
11167c8da7ce66017295a65ec028084b90800be377f8James Zern    }
11177c8da7ce66017295a65ec028084b90800be377f8James Zern  } else {
111898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    uint32_t* dst = picture->argb;
11197c8da7ce66017295a65ec028084b90800be377f8James Zern    assert(step >= 3);
11207c8da7ce66017295a65ec028084b90800be377f8James Zern    for (y = 0; y < height; ++y) {
112198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      VP8PackRGB(r_ptr, g_ptr, b_ptr, width, step, dst);
112298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      r_ptr += rgb_stride;
112398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      g_ptr += rgb_stride;
112498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      b_ptr += rgb_stride;
112598a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      dst += picture->argb_stride;
112633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
112733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
112833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
112933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
113033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
113133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Public API
113233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
113333f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportRGB(WebPPicture* picture,
113433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                         const uint8_t* rgb, int rgb_stride) {
11350912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgb != NULL)
11360912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgb, rgb_stride, 3, 0, 0)
11370912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
113833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
113933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
114033f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportBGR(WebPPicture* picture,
114133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                         const uint8_t* rgb, int rgb_stride) {
11420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgb != NULL)
11430912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgb, rgb_stride, 3, 1, 0)
11440912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
114533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
114633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
114733f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportRGBA(WebPPicture* picture,
114833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11490912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
11500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgba, rgba_stride, 4, 0, 1)
11510912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
115233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
115333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
115433f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportBGRA(WebPPicture* picture,
115533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11560912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
11570912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgba, rgba_stride, 4, 1, 1)
11580912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
115933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
116033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
116133f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportRGBX(WebPPicture* picture,
116233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11630912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
11640912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgba, rgba_stride, 4, 0, 0)
11650912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
116633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
116733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
116833f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportBGRX(WebPPicture* picture,
116933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11700912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
11710912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgba, rgba_stride, 4, 1, 0)
11720912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
117333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
117433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
117533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
1176