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
18a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern#include "src/enc/vp8i_enc.h"
19a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern#include "src/utils/random_utils.h"
20a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern#include "src/utils/utils.h"
21a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern#include "src/dsp/dsp.h"
22a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern#include "src/dsp/lossless.h"
23a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern#include "src/dsp/yuv.h"
2433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Uncomment to disable gamma-compression during RGB->U/V averaging
2633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define USE_GAMMA_COMPRESSION
2733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// If defined, use table to compute x / alpha.
298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define USE_INVERSE_ALPHA_TABLE
308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3133f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic const union {
3233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  uint32_t argb;
3333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  uint8_t  bytes[4];
3433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora} test_endian = { 0xff000000u };
3533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define ALPHA_IS_LAST (test_endian.bytes[3] == 0xff)
3633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
3733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
3833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Detection of non-trivial transparency
3933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
4033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Returns true if alpha[] has non-0xff values.
4133f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int CheckNonOpaque(const uint8_t* alpha, int width, int height,
4233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          int x_step, int y_step) {
4333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (alpha == NULL) return 0;
44a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern  WebPInitAlphaProcessing();
45a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern  if (x_step == 1) {
46a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern    for (; height-- > 0; alpha += y_step) {
47a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern      if (WebPHasAlpha8b(alpha, width)) return 1;
48a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern    }
49a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern  } else {
50a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern    for (; height-- > 0; alpha += y_step) {
51a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern      if (WebPHasAlpha32b(alpha, width)) return 1;
5233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
5333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
5433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 0;
5533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
5633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
5733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Checking for the presence of non-opaque alpha.
5833f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureHasTransparency(const WebPPicture* picture) {
5933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
6033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!picture->use_argb) {
6133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return CheckNonOpaque(picture->a, picture->width, picture->height,
6233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          1, picture->a_stride);
6333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {
64a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern    const int alpha_offset = ALPHA_IS_LAST ? 3 : 0;
65a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern    return CheckNonOpaque((const uint8_t*)picture->argb + alpha_offset,
66a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern                          picture->width, picture->height,
67a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern                          4, picture->argb_stride * sizeof(*picture->argb));
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
174a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern// We use tables of different size and precision for the Rec709 / BT2020
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;
186a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern    const double a = 0.09929682680944;
187a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern    const double thresh = 0.018053968510807;
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    assert(step == 4);
8607c8da7ce66017295a65ec028084b90800be377f8James Zern#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE)
8618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    assert(kAlphaFix + kGammaFix <= 31);
8628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif
86333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
86433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (use_iterative_conversion) {
8668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    InitGammaTablesF();
8678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) {
8688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      return 0;
86933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
8708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (has_alpha) {
8718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      WebPExtractAlpha(a_ptr, rgb_stride, width, height,
8728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                       picture->a, picture->a_stride);
87333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
8748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  } else {
8757c8da7ce66017295a65ec028084b90800be377f8James Zern    const int uv_width = (width + 1) >> 1;
8767c8da7ce66017295a65ec028084b90800be377f8James Zern    int use_dsp = (step == 3);  // use special function in this case
8777c8da7ce66017295a65ec028084b90800be377f8James Zern    // temporary storage for accumulated R/G/B values during conversion to U/V
8787c8da7ce66017295a65ec028084b90800be377f8James Zern    uint16_t* const tmp_rgb =
8797c8da7ce66017295a65ec028084b90800be377f8James Zern        (uint16_t*)WebPSafeMalloc(4 * uv_width, sizeof(*tmp_rgb));
8808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_y = picture->y;
8818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_u = picture->u;
8828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_v = picture->v;
8838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_a = picture->a;
8848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
8858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    VP8Random base_rg;
8868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    VP8Random* rg = NULL;
8878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (dithering > 0.) {
8888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      VP8InitRandom(&base_rg, dithering);
8898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      rg = &base_rg;
8907c8da7ce66017295a65ec028084b90800be377f8James Zern      use_dsp = 0;   // can't use dsp in this case
89133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
8927c8da7ce66017295a65ec028084b90800be377f8James Zern    WebPInitConvertARGBToYUV();
8938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    InitGammaTables();
8948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
8957c8da7ce66017295a65ec028084b90800be377f8James Zern    if (tmp_rgb == NULL) return 0;  // malloc error
8967c8da7ce66017295a65ec028084b90800be377f8James Zern
8978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    // Downsample Y/U/V planes, two rows at a time
8988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (y = 0; y < (height >> 1); ++y) {
8998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      int rows_have_alpha = has_alpha;
9007c8da7ce66017295a65ec028084b90800be377f8James Zern      if (use_dsp) {
9017c8da7ce66017295a65ec028084b90800be377f8James Zern        if (is_rgb) {
90298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertRGB24ToY(r_ptr, dst_y, width);
90398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertRGB24ToY(r_ptr + rgb_stride,
90498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                              dst_y + picture->y_stride, width);
9057c8da7ce66017295a65ec028084b90800be377f8James Zern        } else {
90698a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertBGR24ToY(b_ptr, dst_y, width);
90798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertBGR24ToY(b_ptr + rgb_stride,
90898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                              dst_y + picture->y_stride, width);
9097c8da7ce66017295a65ec028084b90800be377f8James Zern        }
9107c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
91198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg);
91298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        ConvertRowToY(r_ptr + rgb_stride,
91398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                      g_ptr + rgb_stride,
91498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                      b_ptr + rgb_stride, step,
9157c8da7ce66017295a65ec028084b90800be377f8James Zern                      dst_y + picture->y_stride, width, rg);
9167c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_y += 2 * picture->y_stride;
9188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (has_alpha) {
91998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        rows_have_alpha &= !WebPExtractAlpha(a_ptr, rgb_stride, width, 2,
9208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             dst_a, picture->a_stride);
9218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        dst_a += 2 * picture->a_stride;
9228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9237c8da7ce66017295a65ec028084b90800be377f8James Zern      // Collect averaged R/G/B(/A)
9248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (!rows_have_alpha) {
92598a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        AccumulateRGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, tmp_rgb, width);
9267c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
92798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, rgb_stride, tmp_rgb, width);
9287c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9297c8da7ce66017295a65ec028084b90800be377f8James Zern      // Convert to U/V
9307c8da7ce66017295a65ec028084b90800be377f8James Zern      if (rg == NULL) {
9317c8da7ce66017295a65ec028084b90800be377f8James Zern        WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
9328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      } else {
9337c8da7ce66017295a65ec028084b90800be377f8James Zern        ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
9348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_u += picture->uv_stride;
9368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_v += picture->uv_stride;
93798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      r_ptr += 2 * rgb_stride;
93898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      b_ptr += 2 * rgb_stride;
93998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      g_ptr += 2 * rgb_stride;
94098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      if (has_alpha) a_ptr += 2 * rgb_stride;
9418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
9428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (height & 1) {    // extra last row
9438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      int row_has_alpha = has_alpha;
9447c8da7ce66017295a65ec028084b90800be377f8James Zern      if (use_dsp) {
9457c8da7ce66017295a65ec028084b90800be377f8James Zern        if (r_ptr < b_ptr) {
94698a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertRGB24ToY(r_ptr, dst_y, width);
9477c8da7ce66017295a65ec028084b90800be377f8James Zern        } else {
94898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern          WebPConvertBGR24ToY(b_ptr, dst_y, width);
9497c8da7ce66017295a65ec028084b90800be377f8James Zern        }
9507c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
95198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        ConvertRowToY(r_ptr, g_ptr, b_ptr, step, dst_y, width, rg);
9527c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (row_has_alpha) {
95498a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        row_has_alpha &= !WebPExtractAlpha(a_ptr, 0, width, 1, dst_a, 0);
9558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9567c8da7ce66017295a65ec028084b90800be377f8James Zern      // Collect averaged R/G/B(/A)
9578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (!row_has_alpha) {
9587c8da7ce66017295a65ec028084b90800be377f8James Zern        // Collect averaged R/G/B
95998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        AccumulateRGB(r_ptr, g_ptr, b_ptr, step, /* rgb_stride = */ 0,
96098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                      tmp_rgb, width);
9617c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
96298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern        AccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, /* rgb_stride = */ 0,
96398a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern                       tmp_rgb, width);
9647c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9657c8da7ce66017295a65ec028084b90800be377f8James Zern      if (rg == NULL) {
9667c8da7ce66017295a65ec028084b90800be377f8James Zern        WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
9678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      } else {
9687c8da7ce66017295a65ec028084b90800be377f8James Zern        ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
96933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
97033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
9717c8da7ce66017295a65ec028084b90800be377f8James Zern    WebPSafeFree(tmp_rgb);
97233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
97333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
97433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
97533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
97633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#undef SUM4
9778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM2
9788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM4ALPHA
9798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM2ALPHA
98033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
98133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
98233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// call for ARGB->YUVA conversion
98333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
9848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int PictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace,
9858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                             float dithering, int use_iterative_conversion) {
98633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
98733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture->argb == NULL) {
98833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
9898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  } else if ((colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
9908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
99133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {
99233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const argb = (const uint8_t*)picture->argb;
99333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const r = ALPHA_IS_LAST ? argb + 2 : argb + 1;
99433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const g = ALPHA_IS_LAST ? argb + 1 : argb + 2;
99533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const b = ALPHA_IS_LAST ? argb + 0 : argb + 3;
99633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const a = ALPHA_IS_LAST ? argb + 3 : argb + 0;
99733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
9988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    picture->colorspace = WEBP_YUV420;
99933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride,
10008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              dithering, use_iterative_conversion, picture);
100133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
100233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
100333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
10048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Aroraint WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace,
10058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                  float dithering) {
10068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, colorspace, dithering, 0);
10078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
10088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
100933f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) {
10108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, colorspace, 0.f, 0);
10118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
10128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1013fa39824bb690c5806358871f46940d0450973d8aJames Zernint WebPPictureSharpARGBToYUVA(WebPPicture* picture) {
10148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1);
101533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
1016fa39824bb690c5806358871f46940d0450973d8aJames Zern// for backward compatibility
1017fa39824bb690c5806358871f46940d0450973d8aJames Zernint WebPPictureSmartARGBToYUVA(WebPPicture* picture) {
1018fa39824bb690c5806358871f46940d0450973d8aJames Zern  return WebPPictureSharpARGBToYUVA(picture);
1019fa39824bb690c5806358871f46940d0450973d8aJames Zern}
102033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
102133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
102233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// call for YUVA -> ARGB conversion
102333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
102433f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureYUVAToARGB(WebPPicture* picture) {
102533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
102633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture->y == NULL || picture->u == NULL || picture->v == NULL) {
102733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
102833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
102933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) {
103033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
103133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
103233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if ((picture->colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
103333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
103433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
103533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  // Allocate a new argb buffer (discarding the previous one).
103633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!WebPPictureAllocARGB(picture, picture->width, picture->height)) return 0;
103733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  picture->use_argb = 1;
103833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
103933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  // Convert
104033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  {
104133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int y;
104233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int width = picture->width;
104333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int height = picture->height;
104433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int argb_stride = 4 * picture->argb_stride;
104533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    uint8_t* dst = (uint8_t*)picture->argb;
104633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t *cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y;
104733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    WebPUpsampleLinePairFunc upsample = WebPGetLinePairConverter(ALPHA_IS_LAST);
104833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
104933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // First row, with replicated top samples.
105033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
105133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    cur_y += picture->y_stride;
105233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    dst += argb_stride;
105333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Center rows.
105433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (y = 1; y + 1 < height; y += 2) {
105533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t* const top_u = cur_u;
105633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t* const top_v = cur_v;
105733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_u += picture->uv_stride;
105833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_v += picture->uv_stride;
105933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      upsample(cur_y, cur_y + picture->y_stride, top_u, top_v, cur_u, cur_v,
106033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora               dst, dst + argb_stride, width);
106133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_y += 2 * picture->y_stride;
106233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      dst += 2 * argb_stride;
106333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
106433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Last row (if needed), with replicated bottom samples.
106533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (height > 1 && !(height & 1)) {
106633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
106733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
106833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Insert alpha values if needed, in replacement for the default 0xff ones.
106933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (picture->colorspace & WEBP_CSP_ALPHA_BIT) {
107033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      for (y = 0; y < height; ++y) {
107133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        uint32_t* const argb_dst = picture->argb + y * picture->argb_stride;
107233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        const uint8_t* const src = picture->a + y * picture->a_stride;
107333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        int x;
107433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        for (x = 0; x < width; ++x) {
107533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora          argb_dst[x] = (argb_dst[x] & 0x00ffffffu) | ((uint32_t)src[x] << 24);
107633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        }
107733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
107833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
107933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
108033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
108133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
108233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
108333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
108433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// automatic import / conversion
108533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
108633f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int Import(WebPPicture* const picture,
1087a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern                  const uint8_t* rgb, int rgb_stride,
108833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                  int step, int swap_rb, int import_alpha) {
108933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  int y;
109098a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  const uint8_t* r_ptr = rgb + (swap_rb ? 2 : 0);
109198a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  const uint8_t* g_ptr = rgb + 1;
109298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern  const uint8_t* b_ptr = rgb + (swap_rb ? 0 : 2);
109333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int width = picture->width;
109433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int height = picture->height;
109533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
109633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!picture->use_argb) {
1097a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern    const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL;
109833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
10998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              0.f /* no dithering */, 0, picture);
110033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
110133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!WebPPictureAlloc(picture)) return 0;
110233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1103a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern  VP8LDspInit();
1104a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern  WebPInitAlphaProcessing();
11057c8da7ce66017295a65ec028084b90800be377f8James Zern
11067c8da7ce66017295a65ec028084b90800be377f8James Zern  if (import_alpha) {
110798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    uint32_t* dst = picture->argb;
1108a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern    const int do_copy =
1109a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern        (!swap_rb && !ALPHA_IS_LAST) || (swap_rb && ALPHA_IS_LAST);
11107c8da7ce66017295a65ec028084b90800be377f8James Zern    assert(step == 4);
11117c8da7ce66017295a65ec028084b90800be377f8James Zern    for (y = 0; y < height; ++y) {
1112a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern      if (do_copy) {
1113a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern        memcpy(dst, rgb, width * 4);
1114a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern      } else {
1115a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern        // RGBA input order. Need to swap R and B.
1116a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern        VP8LConvertBGRAToRGBA((const uint32_t*)rgb, width, (uint8_t*)dst);
1117a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern      }
1118a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern      rgb += rgb_stride;
111998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      dst += picture->argb_stride;
11207c8da7ce66017295a65ec028084b90800be377f8James Zern    }
11217c8da7ce66017295a65ec028084b90800be377f8James Zern  } else {
112298a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern    uint32_t* dst = picture->argb;
11237c8da7ce66017295a65ec028084b90800be377f8James Zern    assert(step >= 3);
11247c8da7ce66017295a65ec028084b90800be377f8James Zern    for (y = 0; y < height; ++y) {
1125a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern      WebPPackRGB(r_ptr, g_ptr, b_ptr, width, step, dst);
112698a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      r_ptr += rgb_stride;
112798a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      g_ptr += rgb_stride;
112898a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      b_ptr += rgb_stride;
112998a63a77eb8652c81d64b5b7c3d8a347111807caJames Zern      dst += picture->argb_stride;
113033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
113133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
113233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
113333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
113433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
113533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Public API
113633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1137a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern#if !defined(WEBP_REDUCE_CSP)
113833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
113933f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportBGR(WebPPicture* picture,
114033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                         const uint8_t* rgb, int rgb_stride) {
11410912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgb != NULL)
11420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgb, rgb_stride, 3, 1, 0)
11430912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
114433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
114533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1146a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zernint WebPPictureImportBGRA(WebPPicture* picture,
114733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11480912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
1149a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern             ? Import(picture, rgba, rgba_stride, 4, 1, 1)
11500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
115133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
115233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1153a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern
1154a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zernint WebPPictureImportBGRX(WebPPicture* picture,
115533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11560912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
1157a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern             ? Import(picture, rgba, rgba_stride, 4, 1, 0)
11580912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
115933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
116033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1161a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern#endif   // WEBP_REDUCE_CSP
1162a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern
1163a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zernint WebPPictureImportRGB(WebPPicture* picture,
1164a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern                         const uint8_t* rgb, int rgb_stride) {
1165a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern  return (picture != NULL && rgb != NULL)
1166a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern             ? Import(picture, rgb, rgb_stride, 3, 0, 0)
1167a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern             : 0;
1168a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern}
1169a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern
1170a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zernint WebPPictureImportRGBA(WebPPicture* picture,
117133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11720912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
1173a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern             ? Import(picture, rgba, rgba_stride, 4, 0, 1)
11740912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
117533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
117633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1177a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zernint WebPPictureImportRGBX(WebPPicture* picture,
117833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11790912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
1180a187300ff9a8a7c10b1fb2ec84223fdd14e6d47bJames Zern             ? Import(picture, rgba, rgba_stride, 4, 0, 0)
11810912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
118233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
118333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
118433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
1185