picture_csp_enc.c revision 0912efc2528d03c59d45dd9bdc9ff9ec800a3fc1
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
1833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#include "./vp8enci.h"
1933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#include "../utils/random.h"
208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#include "../utils/utils.h"
2133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#include "../dsp/yuv.h"
2233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Uncomment to disable gamma-compression during RGB->U/V averaging
2433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define USE_GAMMA_COMPRESSION
2533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// If defined, use table to compute x / alpha.
278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define USE_INVERSE_ALPHA_TABLE
288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2933f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic const union {
3033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  uint32_t argb;
3133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  uint8_t  bytes[4];
3233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora} test_endian = { 0xff000000u };
3333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define ALPHA_IS_LAST (test_endian.bytes[3] == 0xff)
3433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
3533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
3633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Detection of non-trivial transparency
3733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
3833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Returns true if alpha[] has non-0xff values.
3933f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int CheckNonOpaque(const uint8_t* alpha, int width, int height,
4033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          int x_step, int y_step) {
4133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (alpha == NULL) return 0;
4233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (height-- > 0) {
4333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int x;
4433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (x = 0; x < width * x_step; x += x_step) {
4533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      if (alpha[x] != 0xff) return 1;  // TODO(skal): check 4/8 bytes at a time.
4633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
4733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    alpha += y_step;
4833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
4933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 0;
5033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
5133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
5233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Checking for the presence of non-opaque alpha.
5333f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureHasTransparency(const WebPPicture* picture) {
5433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
5533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!picture->use_argb) {
5633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return CheckNonOpaque(picture->a, picture->width, picture->height,
5733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          1, picture->a_stride);
5833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {
5933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int x, y;
6033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint32_t* argb = picture->argb;
6133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (argb == NULL) return 0;
6233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (y = 0; y < picture->height; ++y) {
6333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      for (x = 0; x < picture->width; ++x) {
6433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        if (argb[x] < 0xff000000u) return 1;   // test any alpha values != 0xff
6533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
6633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      argb += picture->argb_stride;
6733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
6833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
6933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 0;
7033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
7133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
7233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Code for gamma correction
7433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
7533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if defined(USE_GAMMA_COMPRESSION)
7633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
7733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// gamma-compensates loss of resolution during chroma subsampling
788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define kGamma 0.80      // for now we use a different gamma value than kGammaF
7933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaFix 12     // fixed-point precision for linear values
8033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaScale ((1 << kGammaFix) - 1)
8133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabFix 7   // fixed-point fractional bits precision
8233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabScale (1 << kGammaTabFix)
8333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabRounder (kGammaTabScale >> 1)
8433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabSize (1 << (kGammaFix - kGammaTabFix))
8533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8633f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int kLinearToGammaTab[kGammaTabSize + 1];
8733f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic uint16_t kGammaToLinearTab[256];
887c8da7ce66017295a65ec028084b90800be377f8James Zernstatic volatile int kGammaTablesOk = 0;
8933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
907c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {
9133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!kGammaTablesOk) {
9233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int v;
938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const double scale = (double)(1 << kGammaTabFix) / kGammaScale;
948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const double norm = 1. / 255.;
9533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (v = 0; v <= 255; ++v) {
9633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      kGammaToLinearTab[v] =
978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora          (uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5);
9833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
9933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (v = 0; v <= kGammaTabSize; ++v) {
1008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5);
10133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
10233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    kGammaTablesOk = 1;
10333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
10433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
10533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
10633f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE uint32_t GammaToLinear(uint8_t v) {
10733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return kGammaToLinearTab[v];
10833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
10933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int Interpolate(int v) {
11133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int tab_pos = v >> (kGammaTabFix + 2);    // integer part
11233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int x = v & ((kGammaTabScale << 2) - 1);  // fractional part
11333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int v0 = kLinearToGammaTab[tab_pos];
11433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int v1 = kLinearToGammaTab[tab_pos + 1];
11533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x);   // interpolate
1168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(tab_pos + 1 < kGammaTabSize + 1);
1178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return y;
1188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Convert a linear value 'v' to YUV_FIX+2 fixed-point precision
1218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// U/V value, suitable for RGBToU/V calls.
1228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
1238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int y = Interpolate(base_value << shift);   // final uplifted value
1248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (y + kGammaTabRounder) >> kGammaTabFix;    // descale
12533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
12633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
12733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#else
12833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1297c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {}
13033f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; }
13133f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
13233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (int)(base_value << shift);
13333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
13433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
13533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif    // USE_GAMMA_COMPRESSION
13633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
13733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
1388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// RGB -> YUV conversion
1398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToY(int r, int g, int b, VP8Random* const rg) {
1418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (rg == NULL) ? VP8RGBToY(r, g, b, YUV_HALF)
1428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                      : VP8RGBToY(r, g, b, VP8RandomBits(rg, YUV_FIX));
1438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToU(int r, int g, int b, VP8Random* const rg) {
1468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (rg == NULL) ? VP8RGBToU(r, g, b, YUV_HALF << 2)
1478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                      : VP8RGBToU(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
1488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToV(int r, int g, int b, VP8Random* const rg) {
1518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (rg == NULL) ? VP8RGBToV(r, g, b, YUV_HALF << 2)
1528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                      : VP8RGBToV(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
1538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
1568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Smart RGB->YUV conversion
1578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic const int kNumIterations = 6;
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
1748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// We use tables of different size and precision, along with a 'real-world'
1758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Gamma value close to ~2.
1768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define kGammaF 2.2
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;
1868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (v = 0; v <= MAX_Y_T; ++v) {
1878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      kGammaToLinearTabF[v] = (float)pow(norm * v, kGammaF);
1888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
1898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (v = 0; v <= kGammaTabSize; ++v) {
1908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      kLinearToGammaTabF[v] = (float)(MAX_Y_T * pow(scale * v, 1. / kGammaF));
1918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
1928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    // to prevent small rounding errors to cause read-overflow:
1938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    kLinearToGammaTabF[kGammaTabSize + 1] = kLinearToGammaTabF[kGammaTabSize];
1948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    kGammaTablesFOk = 1;
1958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
1968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE float GammaToLinearF(int v) {
1998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return kGammaToLinearTabF[v];
2008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2027c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE int LinearToGammaF(float value) {
2038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float v = value * kGammaTabSize;
2048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int tab_pos = (int)v;
2058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float x = v - (float)tab_pos;      // fractional part
2068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float v0 = kLinearToGammaTabF[tab_pos + 0];
2078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float v1 = kLinearToGammaTabF[tab_pos + 1];
2088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float y = v1 * x + v0 * (1.f - x);  // interpolate
2097c8da7ce66017295a65ec028084b90800be377f8James Zern  return (int)(y + .5);
2108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#else
2138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2147c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) {}
2158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE float GammaToLinearF(int v) {
2168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float norm = 1.f / MAX_Y_T;
2178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return norm * v;
2188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2197c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE int LinearToGammaF(float value) {
2207c8da7ce66017295a65ec028084b90800be377f8James Zern  return (int)(MAX_Y_T * value + .5);
2218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif    // USE_GAMMA_COMPRESSION
2248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
2268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic uint8_t clip_8b(fixed_t v) {
2288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
2298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic fixed_y_t clip_y(int y) {
2328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T;
2338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
23633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToGray(int r, int g, int b) {
2388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int luma = 19595 * r + 38470 * g + 7471 * b + YUV_HALF;
2398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (luma >> YUV_FIX);
2408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic float RGBToGrayF(float r, float g, float b) {
2438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return 0.299f * r + 0.587f * g + 0.114f * b;
2448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
24533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2467c8da7ce66017295a65ec028084b90800be377f8James Zernstatic int ScaleDown(int a, int b, int c, int d) {
2478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float A = GammaToLinearF(a);
2488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float B = GammaToLinearF(b);
2498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float C = GammaToLinearF(c);
2508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float D = GammaToLinearF(d);
2518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return LinearToGammaF(0.25f * (A + B + C + D));
2528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int len) {
2558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  while (len-- > 0) {
2568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float R = GammaToLinearF(src[0]);
2578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float G = GammaToLinearF(src[1]);
2588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float B = GammaToLinearF(src[2]);
2598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float Y = RGBToGrayF(R, G, B);
2607c8da7ce66017295a65ec028084b90800be377f8James Zern    *dst++ = (fixed_y_t)LinearToGammaF(Y);
2618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    src += 3;
2628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
2638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2657c8da7ce66017295a65ec028084b90800be377f8James Zernstatic int UpdateChroma(const fixed_y_t* src1,
2667c8da7ce66017295a65ec028084b90800be377f8James Zern                        const fixed_y_t* src2,
2677c8da7ce66017295a65ec028084b90800be377f8James Zern                        fixed_t* dst, fixed_y_t* tmp, int len) {
2687c8da7ce66017295a65ec028084b90800be377f8James Zern  int diff = 0;
2698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  while (len--> 0) {
2707c8da7ce66017295a65ec028084b90800be377f8James Zern    const int r = ScaleDown(src1[0], src1[3], src2[0], src2[3]);
2717c8da7ce66017295a65ec028084b90800be377f8James Zern    const int g = ScaleDown(src1[1], src1[4], src2[1], src2[4]);
2727c8da7ce66017295a65ec028084b90800be377f8James Zern    const int b = ScaleDown(src1[2], src1[5], src2[2], src2[5]);
2737c8da7ce66017295a65ec028084b90800be377f8James Zern    const int W = RGBToGray(r, g, b);
2747c8da7ce66017295a65ec028084b90800be377f8James Zern    const int r_avg = (src1[0] + src1[3] + src2[0] + src2[3] + 2) >> 2;
2757c8da7ce66017295a65ec028084b90800be377f8James Zern    const int g_avg = (src1[1] + src1[4] + src2[1] + src2[4] + 2) >> 2;
2767c8da7ce66017295a65ec028084b90800be377f8James Zern    const int b_avg = (src1[2] + src1[5] + src2[2] + src2[5] + 2) >> 2;
2777c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[0] = (fixed_t)(r - W);
2787c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[1] = (fixed_t)(g - W);
2797c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[2] = (fixed_t)(b - W);
2808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst += 3;
2818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    src1 += 6;
2828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    src2 += 6;
2838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (tmp != NULL) {
2847c8da7ce66017295a65ec028084b90800be377f8James Zern      tmp[0] = tmp[1] = clip_y(W);
2858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      tmp += 2;
2868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
2877c8da7ce66017295a65ec028084b90800be377f8James Zern    diff += abs(RGBToGray(r_avg, g_avg, b_avg) - W);
2888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
2897c8da7ce66017295a65ec028084b90800be377f8James Zern  return diff;
2908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
2938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int Filter(const fixed_t* const A, const fixed_t* const B,
2958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              int rightwise) {
2968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int v;
2978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (!rightwise) {
2988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    v = (A[0] * 9 + A[-3] * 3 + B[0] * 3 + B[-3]);
2998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  } else {
3008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    v = (A[0] * 9 + A[+3] * 3 + B[0] * 3 + B[+3]);
3018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (v + 8) >> 4;
3038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int Filter2(int A, int B) { return (A * 3 + B + 2) >> 2; }
3068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
3088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3097c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE fixed_y_t UpLift(uint8_t a) {  // 8bit -> SFIX
3107c8da7ce66017295a65ec028084b90800be377f8James Zern  return ((fixed_y_t)a << SFIX) | SHALF;
3118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic void ImportOneRow(const uint8_t* const r_ptr,
3148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         const uint8_t* const g_ptr,
3158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         const uint8_t* const b_ptr,
3168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         int step,
3178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         int pic_width,
3188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         fixed_y_t* const dst) {
3198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i;
3208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (i = 0; i < pic_width; ++i) {
3218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int off = i * step;
3228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst[3 * i + 0] = UpLift(r_ptr[off]);
3238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst[3 * i + 1] = UpLift(g_ptr[off]);
3248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst[3 * i + 2] = UpLift(b_ptr[off]);
3258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (pic_width & 1) {  // replicate rightmost pixel
3278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    memcpy(dst + 3 * pic_width, dst + 3 * (pic_width - 1), 3 * sizeof(*dst));
3288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic void InterpolateTwoRows(const fixed_y_t* const best_y,
3328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               const fixed_t* const prev_uv,
3338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               const fixed_t* const cur_uv,
3348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               const fixed_t* const next_uv,
3358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               int w,
3368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               fixed_y_t* const out1,
3378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               fixed_y_t* const out2) {
3388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, k;
3398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  {  // special boundary case for i==0
3407c8da7ce66017295a65ec028084b90800be377f8James Zern    const int W0 = best_y[0];
3417c8da7ce66017295a65ec028084b90800be377f8James Zern    const int W1 = best_y[w];
3428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (k = 0; k <= 2; ++k) {
3437c8da7ce66017295a65ec028084b90800be377f8James Zern      out1[k] = clip_y(Filter2(cur_uv[k], prev_uv[k]) + W0);
3447c8da7ce66017295a65ec028084b90800be377f8James Zern      out2[k] = clip_y(Filter2(cur_uv[k], next_uv[k]) + W1);
3458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
3468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (i = 1; i < w - 1; ++i) {
3487c8da7ce66017295a65ec028084b90800be377f8James Zern    const int W0 = best_y[i + 0];
3497c8da7ce66017295a65ec028084b90800be377f8James Zern    const int W1 = best_y[i + w];
3508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int off = 3 * (i >> 1);
3518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (k = 0; k <= 2; ++k) {
3528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int tmp0 = Filter(cur_uv + off + k, prev_uv + off + k, i & 1);
3538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int tmp1 = Filter(cur_uv + off + k, next_uv + off + k, i & 1);
3547c8da7ce66017295a65ec028084b90800be377f8James Zern      out1[3 * i + k] = clip_y(tmp0 + W0);
3557c8da7ce66017295a65ec028084b90800be377f8James Zern      out2[3 * i + k] = clip_y(tmp1 + W1);
3568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
3578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  {  // special boundary case for i == w - 1
3597c8da7ce66017295a65ec028084b90800be377f8James Zern    const int W0 = best_y[i + 0];
3607c8da7ce66017295a65ec028084b90800be377f8James Zern    const int W1 = best_y[i + w];
3618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int off = 3 * (i >> 1);
3628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (k = 0; k <= 2; ++k) {
3637c8da7ce66017295a65ec028084b90800be377f8James Zern      out1[3 * i + k] = clip_y(Filter2(cur_uv[off + k], prev_uv[off + k]) + W0);
3647c8da7ce66017295a65ec028084b90800be377f8James Zern      out2[3 * i + k] = clip_y(Filter2(cur_uv[off + k], next_uv[off + k]) + W1);
3658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
3668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) {
3707c8da7ce66017295a65ec028084b90800be377f8James Zern  const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER;
3717c8da7ce66017295a65ec028084b90800be377f8James Zern  return clip_8b(16 + (luma >> (YUV_FIX + SFIX)));
3728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) {
3757c8da7ce66017295a65ec028084b90800be377f8James Zern  const int u =  -9719 * r - 19081 * g + 28800 * b + SROUNDER;
3767c8da7ce66017295a65ec028084b90800be377f8James Zern  return clip_8b(128 + (u >> (YUV_FIX + SFIX)));
3778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) {
3807c8da7ce66017295a65ec028084b90800be377f8James Zern  const int v = +28800 * r - 24116 * g -  4684 * b + SROUNDER;
3817c8da7ce66017295a65ec028084b90800be377f8James Zern  return clip_8b(128 + (v >> (YUV_FIX + SFIX)));
3828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int ConvertWRGBToYUV(const fixed_y_t* const best_y,
3858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                            const fixed_t* const best_uv,
3868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                            WebPPicture* const picture) {
3878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j;
3888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int w = (picture->width + 1) & ~1;
3898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int h = (picture->height + 1) & ~1;
3908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_w = w >> 1;
3918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_h = h >> 1;
3928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (j = 0; j < picture->height; ++j) {
3938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (i = 0; i < picture->width; ++i) {
3948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off = 3 * ((i >> 1) + (j >> 1) * uv_w);
3958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off2 = i + j * picture->y_stride;
3967c8da7ce66017295a65ec028084b90800be377f8James Zern      const int W = best_y[i + j * w];
3978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int r = best_uv[off + 0] + W;
3988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int g = best_uv[off + 1] + W;
3998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int b = best_uv[off + 2] + W;
4008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      picture->y[off2] = ConvertRGBToY(r, g, b);
4018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
4028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
4038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (j = 0; j < uv_h; ++j) {
4048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* const dst_u = picture->u + j * picture->uv_stride;
4058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* const dst_v = picture->v + j * picture->uv_stride;
4068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (i = 0; i < uv_w; ++i) {
4078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off = 3 * (i + j * uv_w);
4088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int r = best_uv[off + 0];
4098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int g = best_uv[off + 1];
4108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int b = best_uv[off + 2];
4118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_u[i] = ConvertRGBToU(r, g, b);
4128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_v[i] = ConvertRGBToV(r, g, b);
4138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
4148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
4158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return 1;
4168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
4178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
4198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Main function
4208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T)))
4228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int PreprocessARGB(const uint8_t* const r_ptr,
4248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                          const uint8_t* const g_ptr,
4258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                          const uint8_t* const b_ptr,
4268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                          int step, int rgb_stride,
4278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                          WebPPicture* const picture) {
4288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // we expand the right/bottom border if needed
4298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int w = (picture->width + 1) & ~1;
4308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int h = (picture->height + 1) & ~1;
4318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_w = w >> 1;
4328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_h = h >> 1;
4338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j, iter;
4348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // TODO(skal): allocate one big memory chunk. But for now, it's easier
4368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // for valgrind debugging to have several chunks.
4378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t);   // scratch
4388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_y_t* const best_y = SAFE_ALLOC(w, h, fixed_y_t);
4398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_y_t* const target_y = SAFE_ALLOC(w, h, fixed_y_t);
4408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
4418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_t* const best_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
4428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_t* const target_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
4438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
4448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int ok;
4457c8da7ce66017295a65ec028084b90800be377f8James Zern  int diff_sum = 0;
4467c8da7ce66017295a65ec028084b90800be377f8James Zern  const int first_diff_threshold = (int)(2.5 * w * h);
4477c8da7ce66017295a65ec028084b90800be377f8James Zern  const int min_improvement = 5;   // stop if improvement is below this %
4487c8da7ce66017295a65ec028084b90800be377f8James Zern  const int min_first_improvement = 80;
4498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (best_y == NULL || best_uv == NULL ||
4518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      target_y == NULL || target_uv == NULL ||
4528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      best_rgb_y == NULL || best_rgb_uv == NULL ||
4538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      tmp_buffer == NULL) {
4548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
4558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    goto End;
4568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
4578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(picture->width >= kMinDimensionIterativeConversion);
4588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(picture->height >= kMinDimensionIterativeConversion);
4598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // Import RGB samples to W/RGB representation.
4618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (j = 0; j < picture->height; j += 2) {
4628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int is_last_row = (j == picture->height - 1);
4638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    fixed_y_t* const src1 = tmp_buffer;
4648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    fixed_y_t* const src2 = tmp_buffer + 3 * w;
4658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int off1 = j * rgb_stride;
4668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int off2 = off1 + rgb_stride;
4678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int uv_off = (j >> 1) * 3 * uv_w;
4688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    fixed_y_t* const dst_y = best_y + j * w;
4698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    // prepare two rows of input
4718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    ImportOneRow(r_ptr + off1, g_ptr + off1, b_ptr + off1,
4728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                 step, picture->width, src1);
4738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (!is_last_row) {
4748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      ImportOneRow(r_ptr + off2, g_ptr + off2, b_ptr + off2,
4758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                   step, picture->width, src2);
4768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    } else {
4778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      memcpy(src2, src1, 3 * w * sizeof(*src2));
4788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
4798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    UpdateW(src1, target_y + (j + 0) * w, w);
4808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    UpdateW(src2, target_y + (j + 1) * w, w);
4817c8da7ce66017295a65ec028084b90800be377f8James Zern    diff_sum += UpdateChroma(src1, src2, target_uv + uv_off, dst_y, uv_w);
4828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    memcpy(best_uv + uv_off, target_uv + uv_off, 3 * uv_w * sizeof(*best_uv));
4838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    memcpy(dst_y + w, dst_y, w * sizeof(*dst_y));
4848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
4858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // Iterate and resolve clipping conflicts.
4878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (iter = 0; iter < kNumIterations; ++iter) {
4888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    int k;
4898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const fixed_t* cur_uv = best_uv;
4908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const fixed_t* prev_uv = best_uv;
4917c8da7ce66017295a65ec028084b90800be377f8James Zern    const int old_diff_sum = diff_sum;
4927c8da7ce66017295a65ec028084b90800be377f8James Zern    diff_sum = 0;
4938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (j = 0; j < h; j += 2) {
4948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      fixed_y_t* const src1 = tmp_buffer;
4958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      fixed_y_t* const src2 = tmp_buffer + 3 * w;
4968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      {
4978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
4988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        InterpolateTwoRows(best_y + j * w, prev_uv, cur_uv, next_uv,
4998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                           w, src1, src2);
5008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        prev_uv = cur_uv;
5018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        cur_uv = next_uv;
5028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
5038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      UpdateW(src1, best_rgb_y + 0 * w, w);
5058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      UpdateW(src2, best_rgb_y + 1 * w, w);
5067c8da7ce66017295a65ec028084b90800be377f8James Zern      diff_sum += UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w);
5078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      // update two rows of Y and one row of RGB
5098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      for (i = 0; i < 2 * w; ++i) {
5108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        const int off = i + j * w;
5118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        const int diff_y = target_y[off] - best_rgb_y[i];
5128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        const int new_y = (int)best_y[off] + diff_y;
5138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        best_y[off] = clip_y(new_y);
5148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
5158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      for (i = 0; i < uv_w; ++i) {
5168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        const int off = 3 * (i + (j >> 1) * uv_w);
5178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        int W;
5188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        for (k = 0; k <= 2; ++k) {
5198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora          const int diff_uv = (int)target_uv[off + k] - best_rgb_uv[3 * i + k];
5208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora          best_uv[off + k] += diff_uv;
5218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        }
5228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        W = RGBToGray(best_uv[off + 0], best_uv[off + 1], best_uv[off + 2]);
5238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        for (k = 0; k <= 2; ++k) {
5248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora          best_uv[off + k] -= W;
5258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        }
5268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
5278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
5287c8da7ce66017295a65ec028084b90800be377f8James Zern    // test exit condition
5297c8da7ce66017295a65ec028084b90800be377f8James Zern    if (diff_sum > 0) {
5307c8da7ce66017295a65ec028084b90800be377f8James Zern      const int improvement = 100 * abs(diff_sum - old_diff_sum) / diff_sum;
5317c8da7ce66017295a65ec028084b90800be377f8James Zern      // Check if first iteration gave good result already, without a large
5327c8da7ce66017295a65ec028084b90800be377f8James Zern      // jump of improvement (otherwise it means we need to try few extra
5337c8da7ce66017295a65ec028084b90800be377f8James Zern      // iterations, just to be sure).
5347c8da7ce66017295a65ec028084b90800be377f8James Zern      if (iter == 0 && diff_sum < first_diff_threshold &&
5357c8da7ce66017295a65ec028084b90800be377f8James Zern          improvement < min_first_improvement) {
5367c8da7ce66017295a65ec028084b90800be377f8James Zern        break;
5377c8da7ce66017295a65ec028084b90800be377f8James Zern      }
5387c8da7ce66017295a65ec028084b90800be377f8James Zern      // then, check if improvement is stalling.
5397c8da7ce66017295a65ec028084b90800be377f8James Zern      if (improvement < min_improvement) {
5407c8da7ce66017295a65ec028084b90800be377f8James Zern        break;
5417c8da7ce66017295a65ec028084b90800be377f8James Zern      }
5427c8da7ce66017295a65ec028084b90800be377f8James Zern    } else {
5437c8da7ce66017295a65ec028084b90800be377f8James Zern      break;
5447c8da7ce66017295a65ec028084b90800be377f8James Zern    }
5458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
5468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // final reconstruction
5488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  ok = ConvertWRGBToYUV(best_y, best_uv, picture);
5498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora End:
5518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(best_y);
5528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(best_uv);
5538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(target_y);
5548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(target_uv);
5558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(best_rgb_y);
5568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(best_rgb_uv);
5578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(tmp_buffer);
5588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return ok;
5598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
5608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SAFE_ALLOC
5618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
5638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// "Fast" regular RGB->YUV
5648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM4(ptr, step) LinearToGamma(                     \
5668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[0]) +                              \
5678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[(step)]) +                         \
5688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[rgb_stride]) +                     \
5698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[rgb_stride + (step)]), 0)          \
5708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM2(ptr) \
57233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    LinearToGamma(GammaToLinear((ptr)[0]) + GammaToLinear((ptr)[rgb_stride]), 1)
57333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
5748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM2ALPHA(ptr) ((ptr)[0] + (ptr)[rgb_stride])
5758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM4ALPHA(ptr) (SUM2ALPHA(ptr) + SUM2ALPHA((ptr) + 4))
5768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if defined(USE_INVERSE_ALPHA_TABLE)
5788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic const int kAlphaFix = 19;
5808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Following table is (1 << kAlphaFix) / a. The (v * kInvAlpha[a]) >> kAlphaFix
5818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// formula is then equal to v / a in most (99.6%) cases. Note that this table
5828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// and constant are adjusted very tightly to fit 32b arithmetic.
5838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// In particular, they use the fact that the operands for 'v / a' are actually
5848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3
5858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// with ai in [0..255] and pi in [0..1<<kGammaFix). The constraint to avoid
5868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// overflow is: kGammaFix + kAlphaFix <= 31.
5878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic const uint32_t kInvAlpha[4 * 0xff + 1] = {
5888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  0,  /* alpha = 0 */
5898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  524288, 262144, 174762, 131072, 104857, 87381, 74898, 65536,
5908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  58254, 52428, 47662, 43690, 40329, 37449, 34952, 32768,
5918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  30840, 29127, 27594, 26214, 24966, 23831, 22795, 21845,
5928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  20971, 20164, 19418, 18724, 18078, 17476, 16912, 16384,
5938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  15887, 15420, 14979, 14563, 14169, 13797, 13443, 13107,
5948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  12787, 12483, 12192, 11915, 11650, 11397, 11155, 10922,
5958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  10699, 10485, 10280, 10082, 9892, 9709, 9532, 9362,
5968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  9198, 9039, 8886, 8738, 8594, 8456, 8322, 8192,
5978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  8065, 7943, 7825, 7710, 7598, 7489, 7384, 7281,
5988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  7182, 7084, 6990, 6898, 6808, 6721, 6636, 6553,
5998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  6472, 6393, 6316, 6241, 6168, 6096, 6026, 5957,
6008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  5890, 5825, 5761, 5698, 5637, 5577, 5518, 5461,
6018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  5405, 5349, 5295, 5242, 5190, 5140, 5090, 5041,
6028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4993, 4946, 4899, 4854, 4809, 4766, 4723, 4681,
6038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4639, 4599, 4559, 4519, 4481, 4443, 4405, 4369,
6048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4332, 4297, 4262, 4228, 4194, 4161, 4128, 4096,
6058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4064, 4032, 4002, 3971, 3942, 3912, 3883, 3855,
6068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3826, 3799, 3771, 3744, 3718, 3692, 3666, 3640,
6078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3615, 3591, 3566, 3542, 3518, 3495, 3472, 3449,
6088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3426, 3404, 3382, 3360, 3339, 3318, 3297, 3276,
6098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3256, 3236, 3216, 3196, 3177, 3158, 3139, 3120,
6108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3102, 3084, 3066, 3048, 3030, 3013, 2995, 2978,
6118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2962, 2945, 2928, 2912, 2896, 2880, 2864, 2849,
6128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2833, 2818, 2803, 2788, 2774, 2759, 2744, 2730,
6138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2716, 2702, 2688, 2674, 2661, 2647, 2634, 2621,
6148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2608, 2595, 2582, 2570, 2557, 2545, 2532, 2520,
6158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2508, 2496, 2484, 2473, 2461, 2449, 2438, 2427,
6168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2416, 2404, 2394, 2383, 2372, 2361, 2351, 2340,
6178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2330, 2319, 2309, 2299, 2289, 2279, 2269, 2259,
6188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2250, 2240, 2231, 2221, 2212, 2202, 2193, 2184,
6198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2175, 2166, 2157, 2148, 2139, 2131, 2122, 2114,
6208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2105, 2097, 2088, 2080, 2072, 2064, 2056, 2048,
6218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2040, 2032, 2024, 2016, 2008, 2001, 1993, 1985,
6228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1978, 1971, 1963, 1956, 1949, 1941, 1934, 1927,
6238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1920, 1913, 1906, 1899, 1892, 1885, 1879, 1872,
6248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1865, 1859, 1852, 1846, 1839, 1833, 1826, 1820,
6258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1814, 1807, 1801, 1795, 1789, 1783, 1777, 1771,
6268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1765, 1759, 1753, 1747, 1741, 1736, 1730, 1724,
6278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1718, 1713, 1707, 1702, 1696, 1691, 1685, 1680,
6288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1675, 1669, 1664, 1659, 1653, 1648, 1643, 1638,
6298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1633, 1628, 1623, 1618, 1613, 1608, 1603, 1598,
6308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1593, 1588, 1583, 1579, 1574, 1569, 1565, 1560,
6318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1555, 1551, 1546, 1542, 1537, 1533, 1528, 1524,
6328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1519, 1515, 1510, 1506, 1502, 1497, 1493, 1489,
6338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1485, 1481, 1476, 1472, 1468, 1464, 1460, 1456,
6348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1452, 1448, 1444, 1440, 1436, 1432, 1428, 1424,
6358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1420, 1416, 1413, 1409, 1405, 1401, 1398, 1394,
6368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1390, 1387, 1383, 1379, 1376, 1372, 1368, 1365,
6378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1361, 1358, 1354, 1351, 1347, 1344, 1340, 1337,
6388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1334, 1330, 1327, 1323, 1320, 1317, 1314, 1310,
6398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1307, 1304, 1300, 1297, 1294, 1291, 1288, 1285,
6408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1281, 1278, 1275, 1272, 1269, 1266, 1263, 1260,
6418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1257, 1254, 1251, 1248, 1245, 1242, 1239, 1236,
6428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1233, 1230, 1227, 1224, 1222, 1219, 1216, 1213,
6438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1210, 1208, 1205, 1202, 1199, 1197, 1194, 1191,
6448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1188, 1186, 1183, 1180, 1178, 1175, 1172, 1170,
6458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1167, 1165, 1162, 1159, 1157, 1154, 1152, 1149,
6468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1147, 1144, 1142, 1139, 1137, 1134, 1132, 1129,
6478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1127, 1125, 1122, 1120, 1117, 1115, 1113, 1110,
6488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1108, 1106, 1103, 1101, 1099, 1096, 1094, 1092,
6498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1089, 1087, 1085, 1083, 1081, 1078, 1076, 1074,
6508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1072, 1069, 1067, 1065, 1063, 1061, 1059, 1057,
6518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1054, 1052, 1050, 1048, 1046, 1044, 1042, 1040,
6528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1038, 1036, 1034, 1032, 1030, 1028, 1026, 1024,
6538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1022, 1020, 1018, 1016, 1014, 1012, 1010, 1008,
6548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1006, 1004, 1002, 1000, 998, 996, 994, 992,
6558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  991, 989, 987, 985, 983, 981, 979, 978,
6568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  976, 974, 972, 970, 969, 967, 965, 963,
6578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  961, 960, 958, 956, 954, 953, 951, 949,
6588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  948, 946, 944, 942, 941, 939, 937, 936,
6598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  934, 932, 931, 929, 927, 926, 924, 923,
6608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  921, 919, 918, 916, 914, 913, 911, 910,
6618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  908, 907, 905, 903, 902, 900, 899, 897,
6628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  896, 894, 893, 891, 890, 888, 887, 885,
6638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  884, 882, 881, 879, 878, 876, 875, 873,
6648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  872, 870, 869, 868, 866, 865, 863, 862,
6658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  860, 859, 858, 856, 855, 853, 852, 851,
6668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  849, 848, 846, 845, 844, 842, 841, 840,
6678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  838, 837, 836, 834, 833, 832, 830, 829,
6688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  828, 826, 825, 824, 823, 821, 820, 819,
6698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  817, 816, 815, 814, 812, 811, 810, 809,
6708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  807, 806, 805, 804, 802, 801, 800, 799,
6718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  798, 796, 795, 794, 793, 791, 790, 789,
6728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  788, 787, 786, 784, 783, 782, 781, 780,
6738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  779, 777, 776, 775, 774, 773, 772, 771,
6748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  769, 768, 767, 766, 765, 764, 763, 762,
6758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  760, 759, 758, 757, 756, 755, 754, 753,
6768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  752, 751, 750, 748, 747, 746, 745, 744,
6778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  743, 742, 741, 740, 739, 738, 737, 736,
6788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  735, 734, 733, 732, 731, 730, 729, 728,
6798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  727, 726, 725, 724, 723, 722, 721, 720,
6808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  719, 718, 717, 716, 715, 714, 713, 712,
6818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  711, 710, 709, 708, 707, 706, 705, 704,
6828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  703, 702, 701, 700, 699, 699, 698, 697,
6838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  696, 695, 694, 693, 692, 691, 690, 689,
6848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  688, 688, 687, 686, 685, 684, 683, 682,
6858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  681, 680, 680, 679, 678, 677, 676, 675,
6868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  674, 673, 673, 672, 671, 670, 669, 668,
6878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  667, 667, 666, 665, 664, 663, 662, 661,
6888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  661, 660, 659, 658, 657, 657, 656, 655,
6898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  654, 653, 652, 652, 651, 650, 649, 648,
6908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  648, 647, 646, 645, 644, 644, 643, 642,
6918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  641, 640, 640, 639, 638, 637, 637, 636,
6928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  635, 634, 633, 633, 632, 631, 630, 630,
6938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  629, 628, 627, 627, 626, 625, 624, 624,
6948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  623, 622, 621, 621, 620, 619, 618, 618,
6958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  617, 616, 616, 615, 614, 613, 613, 612,
6968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  611, 611, 610, 609, 608, 608, 607, 606,
6978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  606, 605, 604, 604, 603, 602, 601, 601,
6988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  600, 599, 599, 598, 597, 597, 596, 595,
6998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  595, 594, 593, 593, 592, 591, 591, 590,
7008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  589, 589, 588, 587, 587, 586, 585, 585,
7018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  584, 583, 583, 582, 581, 581, 580, 579,
7028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  579, 578, 578, 577, 576, 576, 575, 574,
7038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  574, 573, 572, 572, 571, 571, 570, 569,
7048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  569, 568, 568, 567, 566, 566, 565, 564,
7058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  564, 563, 563, 562, 561, 561, 560, 560,
7068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  559, 558, 558, 557, 557, 556, 555, 555,
7078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  554, 554, 553, 553, 552, 551, 551, 550,
7088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  550, 549, 548, 548, 547, 547, 546, 546,
7098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  545, 544, 544, 543, 543, 542, 542, 541,
7108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  541, 540, 539, 539, 538, 538, 537, 537,
7118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  536, 536, 535, 534, 534, 533, 533, 532,
7128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  532, 531, 531, 530, 530, 529, 529, 528,
7138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  527, 527, 526, 526, 525, 525, 524, 524,
7148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  523, 523, 522, 522, 521, 521, 520, 520,
7158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  519, 519, 518, 518, 517, 517, 516, 516,
7168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  515, 515, 514, 514
7178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora};
7188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Note that LinearToGamma() expects the values to be premultiplied by 4,
7208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// so we incorporate this factor 4 inside the DIVIDE_BY_ALPHA macro directly.
7218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define DIVIDE_BY_ALPHA(sum, a)  (((sum) * kInvAlpha[(a)]) >> (kAlphaFix - 2))
7228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#else
7248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define DIVIDE_BY_ALPHA(sum, a) (4 * (sum) / (a))
7268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif  // USE_INVERSE_ALPHA_TABLE
7288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int LinearToGammaWeighted(const uint8_t* src,
7308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             const uint8_t* a_ptr,
7318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             uint32_t total_a, int step,
7328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             int rgb_stride) {
7338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const uint32_t sum =
7348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[0] * GammaToLinear(src[0]) +
7358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[step] * GammaToLinear(src[step]) +
7368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[rgb_stride] * GammaToLinear(src[rgb_stride]) +
7378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[rgb_stride + step] * GammaToLinear(src[rgb_stride + step]);
7388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(total_a > 0 && total_a <= 4 * 0xff);
7398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if defined(USE_INVERSE_ALPHA_TABLE)
7408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert((uint64_t)sum * kInvAlpha[total_a] < ((uint64_t)1 << 32));
7418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif
7428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return LinearToGamma(DIVIDE_BY_ALPHA(sum, total_a), 0);
7438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
7448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE void ConvertRowToY(const uint8_t* const r_ptr,
7468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      const uint8_t* const g_ptr,
7478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      const uint8_t* const b_ptr,
7488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      int step,
7498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      uint8_t* const dst_y,
7508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      int width,
7518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      VP8Random* const rg) {
7528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j;
7537c8da7ce66017295a65ec028084b90800be377f8James Zern  for (i = 0, j = 0; i < width; i += 1, j += step) {
7548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_y[i] = RGBToY(r_ptr[j], g_ptr[j], b_ptr[j], rg);
7558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
7568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
7578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7587c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE void AccumulateRGBA(const uint8_t* const r_ptr,
7597c8da7ce66017295a65ec028084b90800be377f8James Zern                                       const uint8_t* const g_ptr,
7607c8da7ce66017295a65ec028084b90800be377f8James Zern                                       const uint8_t* const b_ptr,
7617c8da7ce66017295a65ec028084b90800be377f8James Zern                                       const uint8_t* const a_ptr,
7627c8da7ce66017295a65ec028084b90800be377f8James Zern                                       int rgb_stride,
7637c8da7ce66017295a65ec028084b90800be377f8James Zern                                       uint16_t* dst, int width) {
7648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j;
7657c8da7ce66017295a65ec028084b90800be377f8James Zern  // we loop over 2x2 blocks and produce one R/G/B/A value for each.
7667c8da7ce66017295a65ec028084b90800be377f8James Zern  for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * 4, dst += 4) {
7678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const uint32_t a = SUM4ALPHA(a_ptr + j);
7688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    int r, g, b;
7698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (a == 4 * 0xff || a == 0) {
7708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = SUM4(r_ptr + j, 4);
7718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = SUM4(g_ptr + j, 4);
7728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = SUM4(b_ptr + j, 4);
7738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    } else {
7748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 4, rgb_stride);
7758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 4, rgb_stride);
7768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 4, rgb_stride);
7778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
7787c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[0] = r;
7797c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[1] = g;
7807c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[2] = b;
7817c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[3] = a;
7828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
7838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (width & 1) {
7848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const uint32_t a = 2u * SUM2ALPHA(a_ptr + j);
7858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    int r, g, b;
7868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (a == 4 * 0xff || a == 0) {
7878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = SUM2(r_ptr + j);
7888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = SUM2(g_ptr + j);
7898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = SUM2(b_ptr + j);
7908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    } else {
7918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 0, rgb_stride);
7928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 0, rgb_stride);
7938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 0, rgb_stride);
7948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
7957c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[0] = r;
7967c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[1] = g;
7977c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[2] = b;
7987c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[3] = a;
7997c8da7ce66017295a65ec028084b90800be377f8James Zern  }
8007c8da7ce66017295a65ec028084b90800be377f8James Zern}
8017c8da7ce66017295a65ec028084b90800be377f8James Zern
8027c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE void AccumulateRGB(const uint8_t* const r_ptr,
8037c8da7ce66017295a65ec028084b90800be377f8James Zern                                      const uint8_t* const g_ptr,
8047c8da7ce66017295a65ec028084b90800be377f8James Zern                                      const uint8_t* const b_ptr,
8057c8da7ce66017295a65ec028084b90800be377f8James Zern                                      int step, int rgb_stride,
8067c8da7ce66017295a65ec028084b90800be377f8James Zern                                      uint16_t* dst, int width) {
8077c8da7ce66017295a65ec028084b90800be377f8James Zern  int i, j;
8087c8da7ce66017295a65ec028084b90800be377f8James Zern  for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * step, dst += 4) {
8097c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[0] = SUM4(r_ptr + j, step);
8107c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[1] = SUM4(g_ptr + j, step);
8117c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[2] = SUM4(b_ptr + j, step);
8127c8da7ce66017295a65ec028084b90800be377f8James Zern  }
8137c8da7ce66017295a65ec028084b90800be377f8James Zern  if (width & 1) {
8147c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[0] = SUM2(r_ptr + j);
8157c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[1] = SUM2(g_ptr + j);
8167c8da7ce66017295a65ec028084b90800be377f8James Zern    dst[2] = SUM2(b_ptr + j);
8178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
8188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
8198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
8207c8da7ce66017295a65ec028084b90800be377f8James Zernstatic WEBP_INLINE void ConvertRowsToUV(const uint16_t* rgb,
8218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        uint8_t* const dst_u,
8228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        uint8_t* const dst_v,
8238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        int width,
8248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        VP8Random* const rg) {
8257c8da7ce66017295a65ec028084b90800be377f8James Zern  int i;
8267c8da7ce66017295a65ec028084b90800be377f8James Zern  for (i = 0; i < width; i += 1, rgb += 4) {
8277c8da7ce66017295a65ec028084b90800be377f8James Zern    const int r = rgb[0], g = rgb[1], b = rgb[2];
8288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_u[i] = RGBToU(r, g, b, rg);
8298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_v[i] = RGBToV(r, g, b, rg);
8308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
83133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
83233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
83333f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int ImportYUVAFromRGBA(const uint8_t* const r_ptr,
83433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              const uint8_t* const g_ptr,
83533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              const uint8_t* const b_ptr,
83633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              const uint8_t* const a_ptr,
83733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              int step,         // bytes per pixel
83833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              int rgb_stride,   // bytes per scanline
83933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              float dithering,
8408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              int use_iterative_conversion,
84133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              WebPPicture* const picture) {
8428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int y;
84333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int width = picture->width;
84433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int height = picture->height;
84533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride);
8467c8da7ce66017295a65ec028084b90800be377f8James Zern  const int is_rgb = (r_ptr < b_ptr);  // otherwise it's bgr
84733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  picture->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
84933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  picture->use_argb = 0;
85033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // disable smart conversion if source is too small (overkill).
8528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (width < kMinDimensionIterativeConversion ||
8538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      height < kMinDimensionIterativeConversion) {
8548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    use_iterative_conversion = 0;
8558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
85633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (!WebPPictureAllocYUVA(picture, width, height)) {
8588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    return 0;
8598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
8608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (has_alpha) {
8618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    WebPInitAlphaProcessing();
8628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    assert(step == 4);
8637c8da7ce66017295a65ec028084b90800be377f8James Zern#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE)
8648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    assert(kAlphaFix + kGammaFix <= 31);
8658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif
86633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
86733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (use_iterative_conversion) {
8698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    InitGammaTablesF();
8708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) {
8718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      return 0;
87233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
8738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (has_alpha) {
8748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      WebPExtractAlpha(a_ptr, rgb_stride, width, height,
8758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                       picture->a, picture->a_stride);
87633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
8778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  } else {
8787c8da7ce66017295a65ec028084b90800be377f8James Zern    const int uv_width = (width + 1) >> 1;
8797c8da7ce66017295a65ec028084b90800be377f8James Zern    int use_dsp = (step == 3);  // use special function in this case
8807c8da7ce66017295a65ec028084b90800be377f8James Zern    // temporary storage for accumulated R/G/B values during conversion to U/V
8817c8da7ce66017295a65ec028084b90800be377f8James Zern    uint16_t* const tmp_rgb =
8827c8da7ce66017295a65ec028084b90800be377f8James Zern        (uint16_t*)WebPSafeMalloc(4 * uv_width, sizeof(*tmp_rgb));
8838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_y = picture->y;
8848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_u = picture->u;
8858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_v = picture->v;
8868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_a = picture->a;
8878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
8888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    VP8Random base_rg;
8898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    VP8Random* rg = NULL;
8908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (dithering > 0.) {
8918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      VP8InitRandom(&base_rg, dithering);
8928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      rg = &base_rg;
8937c8da7ce66017295a65ec028084b90800be377f8James Zern      use_dsp = 0;   // can't use dsp in this case
89433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
8957c8da7ce66017295a65ec028084b90800be377f8James Zern    WebPInitConvertARGBToYUV();
8968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    InitGammaTables();
8978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
8987c8da7ce66017295a65ec028084b90800be377f8James Zern    if (tmp_rgb == NULL) return 0;  // malloc error
8997c8da7ce66017295a65ec028084b90800be377f8James Zern
9008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    // Downsample Y/U/V planes, two rows at a time
9018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (y = 0; y < (height >> 1); ++y) {
9028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      int rows_have_alpha = has_alpha;
9038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off1 = (2 * y + 0) * rgb_stride;
9048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off2 = (2 * y + 1) * rgb_stride;
9057c8da7ce66017295a65ec028084b90800be377f8James Zern      if (use_dsp) {
9067c8da7ce66017295a65ec028084b90800be377f8James Zern        if (is_rgb) {
9077c8da7ce66017295a65ec028084b90800be377f8James Zern          WebPConvertRGB24ToY(r_ptr + off1, dst_y, width);
9087c8da7ce66017295a65ec028084b90800be377f8James Zern          WebPConvertRGB24ToY(r_ptr + off2, dst_y + picture->y_stride, width);
9097c8da7ce66017295a65ec028084b90800be377f8James Zern        } else {
9107c8da7ce66017295a65ec028084b90800be377f8James Zern          WebPConvertBGR24ToY(b_ptr + off1, dst_y, width);
9117c8da7ce66017295a65ec028084b90800be377f8James Zern          WebPConvertBGR24ToY(b_ptr + off2, dst_y + picture->y_stride, width);
9127c8da7ce66017295a65ec028084b90800be377f8James Zern        }
9137c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
9147c8da7ce66017295a65ec028084b90800be377f8James Zern        ConvertRowToY(r_ptr + off1, g_ptr + off1, b_ptr + off1, step,
9157c8da7ce66017295a65ec028084b90800be377f8James Zern                      dst_y, width, rg);
9167c8da7ce66017295a65ec028084b90800be377f8James Zern        ConvertRowToY(r_ptr + off2, g_ptr + off2, b_ptr + off2, step,
9177c8da7ce66017295a65ec028084b90800be377f8James Zern                      dst_y + picture->y_stride, width, rg);
9187c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_y += 2 * picture->y_stride;
9208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (has_alpha) {
9218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        rows_have_alpha &= !WebPExtractAlpha(a_ptr + off1, rgb_stride,
9228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             width, 2,
9238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             dst_a, picture->a_stride);
9248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        dst_a += 2 * picture->a_stride;
9258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9267c8da7ce66017295a65ec028084b90800be377f8James Zern      // Collect averaged R/G/B(/A)
9278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (!rows_have_alpha) {
9287c8da7ce66017295a65ec028084b90800be377f8James Zern        AccumulateRGB(r_ptr + off1, g_ptr + off1, b_ptr + off1,
9297c8da7ce66017295a65ec028084b90800be377f8James Zern                      step, rgb_stride, tmp_rgb, width);
9307c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
9317c8da7ce66017295a65ec028084b90800be377f8James Zern        AccumulateRGBA(r_ptr + off1, g_ptr + off1, b_ptr + off1, a_ptr + off1,
9327c8da7ce66017295a65ec028084b90800be377f8James Zern                       rgb_stride, tmp_rgb, width);
9337c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9347c8da7ce66017295a65ec028084b90800be377f8James Zern      // Convert to U/V
9357c8da7ce66017295a65ec028084b90800be377f8James Zern      if (rg == NULL) {
9367c8da7ce66017295a65ec028084b90800be377f8James Zern        WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
9378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      } else {
9387c8da7ce66017295a65ec028084b90800be377f8James Zern        ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
9398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_u += picture->uv_stride;
9418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_v += picture->uv_stride;
9428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
9438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (height & 1) {    // extra last row
9448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off = 2 * y * rgb_stride;
9458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      int row_has_alpha = has_alpha;
9467c8da7ce66017295a65ec028084b90800be377f8James Zern      if (use_dsp) {
9477c8da7ce66017295a65ec028084b90800be377f8James Zern        if (r_ptr < b_ptr) {
9487c8da7ce66017295a65ec028084b90800be377f8James Zern          WebPConvertRGB24ToY(r_ptr + off, dst_y, width);
9497c8da7ce66017295a65ec028084b90800be377f8James Zern        } else {
9507c8da7ce66017295a65ec028084b90800be377f8James Zern          WebPConvertBGR24ToY(b_ptr + off, dst_y, width);
9517c8da7ce66017295a65ec028084b90800be377f8James Zern        }
9527c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
9537c8da7ce66017295a65ec028084b90800be377f8James Zern        ConvertRowToY(r_ptr + off, g_ptr + off, b_ptr + off, step,
9547c8da7ce66017295a65ec028084b90800be377f8James Zern                      dst_y, width, rg);
9557c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (row_has_alpha) {
9578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        row_has_alpha &= !WebPExtractAlpha(a_ptr + off, 0, width, 1, dst_a, 0);
9588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9597c8da7ce66017295a65ec028084b90800be377f8James Zern      // Collect averaged R/G/B(/A)
9608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (!row_has_alpha) {
9617c8da7ce66017295a65ec028084b90800be377f8James Zern        // Collect averaged R/G/B
9627c8da7ce66017295a65ec028084b90800be377f8James Zern        AccumulateRGB(r_ptr + off, g_ptr + off, b_ptr + off,
9637c8da7ce66017295a65ec028084b90800be377f8James Zern                      step, /* rgb_stride = */ 0, tmp_rgb, width);
9647c8da7ce66017295a65ec028084b90800be377f8James Zern      } else {
9657c8da7ce66017295a65ec028084b90800be377f8James Zern        AccumulateRGBA(r_ptr + off, g_ptr + off, b_ptr + off, a_ptr + off,
9667c8da7ce66017295a65ec028084b90800be377f8James Zern                       /* rgb_stride = */ 0, tmp_rgb, width);
9677c8da7ce66017295a65ec028084b90800be377f8James Zern      }
9687c8da7ce66017295a65ec028084b90800be377f8James Zern      if (rg == NULL) {
9697c8da7ce66017295a65ec028084b90800be377f8James Zern        WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
9708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      } else {
9717c8da7ce66017295a65ec028084b90800be377f8James Zern        ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
97233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
97333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
9747c8da7ce66017295a65ec028084b90800be377f8James Zern    WebPSafeFree(tmp_rgb);
97533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
97633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
97733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
97833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
97933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#undef SUM4
9808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM2
9818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM4ALPHA
9828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM2ALPHA
98333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
98433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
98533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// call for ARGB->YUVA conversion
98633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
9878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int PictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace,
9888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                             float dithering, int use_iterative_conversion) {
98933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
99033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture->argb == NULL) {
99133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
9928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  } else if ((colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
9938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
99433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {
99533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const argb = (const uint8_t*)picture->argb;
99633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const r = ALPHA_IS_LAST ? argb + 2 : argb + 1;
99733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const g = ALPHA_IS_LAST ? argb + 1 : argb + 2;
99833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const b = ALPHA_IS_LAST ? argb + 0 : argb + 3;
99933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const a = ALPHA_IS_LAST ? argb + 3 : argb + 0;
100033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
10018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    picture->colorspace = WEBP_YUV420;
100233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride,
10038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              dithering, use_iterative_conversion, picture);
100433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
100533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
100633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
10078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Aroraint WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace,
10088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                  float dithering) {
10098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, colorspace, dithering, 0);
10108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
10118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
101233f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) {
10138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, colorspace, 0.f, 0);
10148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
10158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
10168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Aroraint WebPPictureSmartARGBToYUVA(WebPPicture* picture) {
10178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1);
101833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
101933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
102033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
102133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// call for YUVA -> ARGB conversion
102233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
102333f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureYUVAToARGB(WebPPicture* picture) {
102433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
102533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture->y == NULL || picture->u == NULL || picture->v == NULL) {
102633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
102733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
102833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) {
102933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
103033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
103133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if ((picture->colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
103233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
103333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
103433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  // Allocate a new argb buffer (discarding the previous one).
103533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!WebPPictureAllocARGB(picture, picture->width, picture->height)) return 0;
103633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  picture->use_argb = 1;
103733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
103833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  // Convert
103933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  {
104033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int y;
104133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int width = picture->width;
104233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int height = picture->height;
104333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int argb_stride = 4 * picture->argb_stride;
104433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    uint8_t* dst = (uint8_t*)picture->argb;
104533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t *cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y;
104633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    WebPUpsampleLinePairFunc upsample = WebPGetLinePairConverter(ALPHA_IS_LAST);
104733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
104833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // First row, with replicated top samples.
104933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
105033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    cur_y += picture->y_stride;
105133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    dst += argb_stride;
105233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Center rows.
105333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (y = 1; y + 1 < height; y += 2) {
105433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t* const top_u = cur_u;
105533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t* const top_v = cur_v;
105633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_u += picture->uv_stride;
105733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_v += picture->uv_stride;
105833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      upsample(cur_y, cur_y + picture->y_stride, top_u, top_v, cur_u, cur_v,
105933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora               dst, dst + argb_stride, width);
106033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_y += 2 * picture->y_stride;
106133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      dst += 2 * argb_stride;
106233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
106333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Last row (if needed), with replicated bottom samples.
106433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (height > 1 && !(height & 1)) {
106533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
106633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
106733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Insert alpha values if needed, in replacement for the default 0xff ones.
106833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (picture->colorspace & WEBP_CSP_ALPHA_BIT) {
106933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      for (y = 0; y < height; ++y) {
107033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        uint32_t* const argb_dst = picture->argb + y * picture->argb_stride;
107133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        const uint8_t* const src = picture->a + y * picture->a_stride;
107233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        int x;
107333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        for (x = 0; x < width; ++x) {
107433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora          argb_dst[x] = (argb_dst[x] & 0x00ffffffu) | ((uint32_t)src[x] << 24);
107533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        }
107633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
107733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
107833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
107933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
108033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
108133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
108233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
108333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// automatic import / conversion
108433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
108533f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int Import(WebPPicture* const picture,
108633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                  const uint8_t* const rgb, int rgb_stride,
108733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                  int step, int swap_rb, int import_alpha) {
108833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  int y;
108933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const uint8_t* const r_ptr = rgb + (swap_rb ? 2 : 0);
109033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const uint8_t* const g_ptr = rgb + 1;
109133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const uint8_t* const b_ptr = rgb + (swap_rb ? 0 : 2);
109233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const uint8_t* const a_ptr = import_alpha ? rgb + 3 : NULL;
109333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int width = picture->width;
109433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int height = picture->height;
109533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
109633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!picture->use_argb) {
109733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
10988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              0.f /* no dithering */, 0, picture);
109933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
110033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!WebPPictureAlloc(picture)) return 0;
110133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
11027c8da7ce66017295a65ec028084b90800be377f8James Zern  VP8EncDspARGBInit();
11037c8da7ce66017295a65ec028084b90800be377f8James Zern
11047c8da7ce66017295a65ec028084b90800be377f8James Zern  if (import_alpha) {
11057c8da7ce66017295a65ec028084b90800be377f8James Zern    assert(step == 4);
11067c8da7ce66017295a65ec028084b90800be377f8James Zern    for (y = 0; y < height; ++y) {
11077c8da7ce66017295a65ec028084b90800be377f8James Zern      uint32_t* const dst = &picture->argb[y * picture->argb_stride];
11087c8da7ce66017295a65ec028084b90800be377f8James Zern      const int offset = y * rgb_stride;
11097c8da7ce66017295a65ec028084b90800be377f8James Zern      VP8PackARGB(a_ptr + offset, r_ptr + offset, g_ptr + offset,
11107c8da7ce66017295a65ec028084b90800be377f8James Zern                  b_ptr + offset, width, dst);
11117c8da7ce66017295a65ec028084b90800be377f8James Zern    }
11127c8da7ce66017295a65ec028084b90800be377f8James Zern  } else {
11137c8da7ce66017295a65ec028084b90800be377f8James Zern    assert(step >= 3);
11147c8da7ce66017295a65ec028084b90800be377f8James Zern    for (y = 0; y < height; ++y) {
11157c8da7ce66017295a65ec028084b90800be377f8James Zern      uint32_t* const dst = &picture->argb[y * picture->argb_stride];
11167c8da7ce66017295a65ec028084b90800be377f8James Zern      const int offset = y * rgb_stride;
11177c8da7ce66017295a65ec028084b90800be377f8James Zern      VP8PackRGB(r_ptr + offset, g_ptr + offset, b_ptr + offset,
11187c8da7ce66017295a65ec028084b90800be377f8James Zern                 width, step, dst);
111933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
112033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
112133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
112233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
112333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
112433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Public API
112533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
112633f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportRGB(WebPPicture* picture,
112733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                         const uint8_t* rgb, int rgb_stride) {
11280912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgb != NULL)
11290912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgb, rgb_stride, 3, 0, 0)
11300912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
113133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
113233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
113333f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportBGR(WebPPicture* picture,
113433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                         const uint8_t* rgb, int rgb_stride) {
11350912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgb != NULL)
11360912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgb, rgb_stride, 3, 1, 0)
11370912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
113833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
113933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
114033f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportRGBA(WebPPicture* picture,
114133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11420912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
11430912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgba, rgba_stride, 4, 0, 1)
11440912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
114533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
114633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
114733f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportBGRA(WebPPicture* picture,
114833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11490912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
11500912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgba, rgba_stride, 4, 1, 1)
11510912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
115233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
115333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
115433f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportRGBX(WebPPicture* picture,
115533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11560912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
11570912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgba, rgba_stride, 4, 0, 0)
11580912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
115933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
116033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
116133f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportBGRX(WebPPicture* picture,
116233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
11630912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern  return (picture != NULL && rgba != NULL)
11640912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             ? Import(picture, rgba, rgba_stride, 4, 1, 0)
11650912efc2528d03c59d45dd9bdc9ff9ec800a3fc1James Zern             : 0;
116633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
116733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
116833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
1169