picture_csp_enc.c revision 8c098653157979e397d3954fc2ea0ee43bae6ab2
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 Arorastatic WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
3633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (((uint32_t)a << 24) | (r << 16) | (g << 8) | b);
3733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
3833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
3933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
4033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Detection of non-trivial transparency
4133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
4233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Returns true if alpha[] has non-0xff values.
4333f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int CheckNonOpaque(const uint8_t* alpha, int width, int height,
4433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          int x_step, int y_step) {
4533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (alpha == NULL) return 0;
4633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  while (height-- > 0) {
4733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int x;
4833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (x = 0; x < width * x_step; x += x_step) {
4933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      if (alpha[x] != 0xff) return 1;  // TODO(skal): check 4/8 bytes at a time.
5033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
5133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    alpha += y_step;
5233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
5333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 0;
5433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
5533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
5633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Checking for the presence of non-opaque alpha.
5733f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureHasTransparency(const WebPPicture* picture) {
5833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
5933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!picture->use_argb) {
6033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return CheckNonOpaque(picture->a, picture->width, picture->height,
6133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          1, picture->a_stride);
6233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {
6333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int x, y;
6433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint32_t* argb = picture->argb;
6533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (argb == NULL) return 0;
6633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (y = 0; y < picture->height; ++y) {
6733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      for (x = 0; x < picture->width; ++x) {
6833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        if (argb[x] < 0xff000000u) return 1;   // test any alpha values != 0xff
6933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
7033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      argb += picture->argb_stride;
7133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
7233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
7333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 0;
7433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
7533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
7633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Code for gamma correction
7833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
7933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#if defined(USE_GAMMA_COMPRESSION)
8033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// gamma-compensates loss of resolution during chroma subsampling
828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define kGamma 0.80      // for now we use a different gamma value than kGammaF
8333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaFix 12     // fixed-point precision for linear values
8433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaScale ((1 << kGammaFix) - 1)
8533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabFix 7   // fixed-point fractional bits precision
8633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabScale (1 << kGammaTabFix)
8733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabRounder (kGammaTabScale >> 1)
8833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#define kGammaTabSize (1 << (kGammaFix - kGammaTabFix))
8933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
9033f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int kLinearToGammaTab[kGammaTabSize + 1];
9133f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic uint16_t kGammaToLinearTab[256];
9233f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int kGammaTablesOk = 0;
9333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
9433f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void InitGammaTables(void) {
9533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!kGammaTablesOk) {
9633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int v;
978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const double scale = (double)(1 << kGammaTabFix) / kGammaScale;
988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const double norm = 1. / 255.;
9933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (v = 0; v <= 255; ++v) {
10033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      kGammaToLinearTab[v] =
1018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora          (uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5);
10233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
10333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (v = 0; v <= kGammaTabSize; ++v) {
1048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5);
10533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
10633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    kGammaTablesOk = 1;
10733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
10833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
10933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
11033f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE uint32_t GammaToLinear(uint8_t v) {
11133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return kGammaToLinearTab[v];
11233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
11333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
1148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int Interpolate(int v) {
11533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int tab_pos = v >> (kGammaTabFix + 2);    // integer part
11633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int x = v & ((kGammaTabScale << 2) - 1);  // fractional part
11733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int v0 = kLinearToGammaTab[tab_pos];
11833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int v1 = kLinearToGammaTab[tab_pos + 1];
11933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x);   // interpolate
1208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(tab_pos + 1 < kGammaTabSize + 1);
1218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return y;
1228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Convert a linear value 'v' to YUV_FIX+2 fixed-point precision
1258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// U/V value, suitable for RGBToU/V calls.
1268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
1278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int y = Interpolate(base_value << shift);   // final uplifted value
1288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (y + kGammaTabRounder) >> kGammaTabFix;    // descale
12933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
13033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
13133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#else
13233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
13333f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic void InitGammaTables(void) {}
13433f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; }
13533f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
13633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (int)(base_value << shift);
13733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
13833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
13933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#endif    // USE_GAMMA_COMPRESSION
14033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
14133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
1428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// RGB -> YUV conversion
1438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToY(int r, int g, int b, VP8Random* const rg) {
1458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (rg == NULL) ? VP8RGBToY(r, g, b, YUV_HALF)
1468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                      : VP8RGBToY(r, g, b, VP8RandomBits(rg, YUV_FIX));
1478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToU(int r, int g, int b, VP8Random* const rg) {
1508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (rg == NULL) ? VP8RGBToU(r, g, b, YUV_HALF << 2)
1518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                      : VP8RGBToU(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
1528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToV(int r, int g, int b, VP8Random* const rg) {
1558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (rg == NULL) ? VP8RGBToV(r, g, b, YUV_HALF << 2)
1568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                      : VP8RGBToV(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
1578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
1588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
1608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Smart RGB->YUV conversion
1618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic const int kNumIterations = 6;
1638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic const int kMinDimensionIterativeConversion = 4;
1648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// We use a-priori a different precision for storing RGB and Y/W components
1668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// We could use YFIX=0 and only uint8_t for fixed_y_t, but it produces some
1678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// banding sometimes. Better use extra precision.
1688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// TODO(skal): cleanup once TFIX/YFIX values are fixed.
1698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Aroratypedef int16_t fixed_t;      // signed type with extra TFIX precision for UV
1718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Aroratypedef uint16_t fixed_y_t;   // unsigned type with extra YFIX precision for W
1728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define TFIX 6   // fixed-point precision of RGB
1738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define YFIX 2   // fixed point precision for Y/W
1748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define THALF ((1 << TFIX) >> 1)
1768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define MAX_Y_T ((256 << YFIX) - 1)
1778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define TROUNDER (1 << (YUV_FIX + TFIX - 1))
1788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if defined(USE_GAMMA_COMPRESSION)
1808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// float variant of gamma-correction
1828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// We use tables of different size and precision, along with a 'real-world'
1838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Gamma value close to ~2.
1848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define kGammaF 2.2
1858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic float kGammaToLinearTabF[MAX_Y_T + 1];   // size scales with Y_FIX
1868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic float kLinearToGammaTabF[kGammaTabSize + 2];
1878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int kGammaTablesFOk = 0;
1888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
1898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic void InitGammaTablesF(void) {
1908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (!kGammaTablesFOk) {
1918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    int v;
1928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const double norm = 1. / MAX_Y_T;
1938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const double scale = 1. / kGammaTabSize;
1948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (v = 0; v <= MAX_Y_T; ++v) {
1958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      kGammaToLinearTabF[v] = (float)pow(norm * v, kGammaF);
1968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
1978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (v = 0; v <= kGammaTabSize; ++v) {
1988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      kLinearToGammaTabF[v] = (float)(MAX_Y_T * pow(scale * v, 1. / kGammaF));
1998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
2008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    // to prevent small rounding errors to cause read-overflow:
2018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    kLinearToGammaTabF[kGammaTabSize + 1] = kLinearToGammaTabF[kGammaTabSize];
2028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    kGammaTablesFOk = 1;
2038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
2048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE float GammaToLinearF(int v) {
2078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return kGammaToLinearTabF[v];
2088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE float LinearToGammaF(float value) {
2118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float v = value * kGammaTabSize;
2128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int tab_pos = (int)v;
2138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float x = v - (float)tab_pos;      // fractional part
2148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float v0 = kLinearToGammaTabF[tab_pos + 0];
2158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float v1 = kLinearToGammaTabF[tab_pos + 1];
2168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float y = v1 * x + v0 * (1.f - x);  // interpolate
2178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return y;
2188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#else
2218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic void InitGammaTablesF(void) {}
2238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE float GammaToLinearF(int v) {
2248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float norm = 1.f / MAX_Y_T;
2258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return norm * v;
2268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE float LinearToGammaF(float value) {
2288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return MAX_Y_T * value;
2298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif    // USE_GAMMA_COMPRESSION
2328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
2348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// precision: YFIX -> TFIX
2368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int FixedYToW(int v) {
2378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if TFIX == YFIX
2388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return v;
2398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#elif TFIX >= YFIX
2408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return v << (TFIX - YFIX);
2418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#else
2428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return v >> (YFIX - TFIX);
2438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif
2448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int FixedWToY(int v) {
2478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if TFIX == YFIX
2488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return v;
2498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#elif YFIX >= TFIX
2508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return v << (YFIX - TFIX);
2518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#else
2528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return v >> (TFIX - YFIX);
2538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif
2548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic uint8_t clip_8b(fixed_t v) {
2578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
2588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic fixed_y_t clip_y(int y) {
2618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T;
2628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// precision: TFIX -> YFIX
2658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic fixed_y_t clip_fixed_t(fixed_t v) {
2668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int y = FixedWToY(v);
2678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const fixed_y_t w = clip_y(y);
2688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return w;
2698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
27233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int RGBToGray(int r, int g, int b) {
2748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int luma = 19595 * r + 38470 * g + 7471 * b + YUV_HALF;
2758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (luma >> YUV_FIX);
2768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic float RGBToGrayF(float r, float g, float b) {
2798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return 0.299f * r + 0.587f * g + 0.114f * b;
2808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
28133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
2828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic float ScaleDown(int a, int b, int c, int d) {
2838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float A = GammaToLinearF(a);
2848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float B = GammaToLinearF(b);
2858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float C = GammaToLinearF(c);
2868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const float D = GammaToLinearF(d);
2878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return LinearToGammaF(0.25f * (A + B + C + D));
2888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
2898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
2908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int len) {
2918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  while (len-- > 0) {
2928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float R = GammaToLinearF(src[0]);
2938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float G = GammaToLinearF(src[1]);
2948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float B = GammaToLinearF(src[2]);
2958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float Y = RGBToGrayF(R, G, B);
2968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    *dst++ = (fixed_y_t)(LinearToGammaF(Y) + .5);
2978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    src += 3;
2988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
2998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE void UpdateChroma(const fixed_y_t* src1,
3028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                     const fixed_y_t* src2,
3038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                     fixed_t* dst, fixed_y_t* tmp, int len) {
3048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  while (len--> 0) {
3058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float r = ScaleDown(src1[0], src1[3], src2[0], src2[3]);
3068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float g = ScaleDown(src1[1], src1[4], src2[1], src2[4]);
3078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float b = ScaleDown(src1[2], src1[5], src2[2], src2[5]);
3088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const float W = RGBToGrayF(r, g, b);
3098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst[0] = (fixed_t)FixedYToW((int)(r - W));
3108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst[1] = (fixed_t)FixedYToW((int)(g - W));
3118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst[2] = (fixed_t)FixedYToW((int)(b - W));
3128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst += 3;
3138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    src1 += 6;
3148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    src2 += 6;
3158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (tmp != NULL) {
3168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      tmp[0] = tmp[1] = clip_y((int)(W + .5));
3178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      tmp += 2;
3188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
3198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
3238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int Filter(const fixed_t* const A, const fixed_t* const B,
3258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              int rightwise) {
3268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int v;
3278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (!rightwise) {
3288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    v = (A[0] * 9 + A[-3] * 3 + B[0] * 3 + B[-3]);
3298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  } else {
3308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    v = (A[0] * 9 + A[+3] * 3 + B[0] * 3 + B[+3]);
3318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return (v + 8) >> 4;
3338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int Filter2(int A, int B) { return (A * 3 + B + 2) >> 2; }
3368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
3388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// 8bit -> YFIX
3408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE fixed_y_t UpLift(uint8_t a) {
3418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return ((fixed_y_t)a << YFIX) | (1 << (YFIX - 1));
3428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic void ImportOneRow(const uint8_t* const r_ptr,
3458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         const uint8_t* const g_ptr,
3468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         const uint8_t* const b_ptr,
3478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         int step,
3488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         int pic_width,
3498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                         fixed_y_t* const dst) {
3508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i;
3518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (i = 0; i < pic_width; ++i) {
3528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int off = i * step;
3538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst[3 * i + 0] = UpLift(r_ptr[off]);
3548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst[3 * i + 1] = UpLift(g_ptr[off]);
3558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst[3 * i + 2] = UpLift(b_ptr[off]);
3568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (pic_width & 1) {  // replicate rightmost pixel
3588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    memcpy(dst + 3 * pic_width, dst + 3 * (pic_width - 1), 3 * sizeof(*dst));
3598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
3618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
3628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic void InterpolateTwoRows(const fixed_y_t* const best_y,
3638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               const fixed_t* const prev_uv,
3648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               const fixed_t* const cur_uv,
3658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               const fixed_t* const next_uv,
3668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               int w,
3678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               fixed_y_t* const out1,
3688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                               fixed_y_t* const out2) {
3698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, k;
3708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  {  // special boundary case for i==0
3718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int W0 = FixedYToW(best_y[0]);
3728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int W1 = FixedYToW(best_y[w]);
3738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (k = 0; k <= 2; ++k) {
3748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      out1[k] = clip_fixed_t(Filter2(cur_uv[k], prev_uv[k]) + W0);
3758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      out2[k] = clip_fixed_t(Filter2(cur_uv[k], next_uv[k]) + W1);
3768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
3778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (i = 1; i < w - 1; ++i) {
3798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int W0 = FixedYToW(best_y[i + 0]);
3808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int W1 = FixedYToW(best_y[i + w]);
3818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int off = 3 * (i >> 1);
3828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (k = 0; k <= 2; ++k) {
3838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int tmp0 = Filter(cur_uv + off + k, prev_uv + off + k, i & 1);
3848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int tmp1 = Filter(cur_uv + off + k, next_uv + off + k, i & 1);
3858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      out1[3 * i + k] = clip_fixed_t(tmp0 + W0);
3868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      out2[3 * i + k] = clip_fixed_t(tmp1 + W1);
3878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
3888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
3898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  {  // special boundary case for i == w - 1
3908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int W0 = FixedYToW(best_y[i + 0]);
3918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int W1 = FixedYToW(best_y[i + w]);
3928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int off = 3 * (i >> 1);
3938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (k = 0; k <= 2; ++k) {
3948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      out1[3 * i + k] =
3958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora          clip_fixed_t(Filter2(cur_uv[off + k], prev_uv[off + k]) + W0);
3968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      out2[3 * i + k] =
3978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora          clip_fixed_t(Filter2(cur_uv[off + k], next_uv[off + k]) + W1);
3988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
3998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
4008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
4018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) {
4038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int luma = 16839 * r + 33059 * g + 6420 * b + TROUNDER;
4048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return clip_8b(16 + (luma >> (YUV_FIX + TFIX)));
4058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
4068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) {
4088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int u =  -9719 * r - 19081 * g + 28800 * b + TROUNDER;
4098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return clip_8b(128 + (u >> (YUV_FIX + TFIX)));
4108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
4118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) {
4138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int v = +28800 * r - 24116 * g -  4684 * b + TROUNDER;
4148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return clip_8b(128 + (v >> (YUV_FIX + TFIX)));
4158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
4168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int ConvertWRGBToYUV(const fixed_y_t* const best_y,
4188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                            const fixed_t* const best_uv,
4198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                            WebPPicture* const picture) {
4208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j;
4218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int w = (picture->width + 1) & ~1;
4228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int h = (picture->height + 1) & ~1;
4238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_w = w >> 1;
4248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_h = h >> 1;
4258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (j = 0; j < picture->height; ++j) {
4268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (i = 0; i < picture->width; ++i) {
4278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off = 3 * ((i >> 1) + (j >> 1) * uv_w);
4288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off2 = i + j * picture->y_stride;
4298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int W = FixedYToW(best_y[i + j * w]);
4308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int r = best_uv[off + 0] + W;
4318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int g = best_uv[off + 1] + W;
4328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int b = best_uv[off + 2] + W;
4338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      picture->y[off2] = ConvertRGBToY(r, g, b);
4348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
4358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
4368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (j = 0; j < uv_h; ++j) {
4378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* const dst_u = picture->u + j * picture->uv_stride;
4388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* const dst_v = picture->v + j * picture->uv_stride;
4398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (i = 0; i < uv_w; ++i) {
4408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off = 3 * (i + j * uv_w);
4418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int r = best_uv[off + 0];
4428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int g = best_uv[off + 1];
4438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int b = best_uv[off + 2];
4448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_u[i] = ConvertRGBToU(r, g, b);
4458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_v[i] = ConvertRGBToV(r, g, b);
4468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
4478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
4488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return 1;
4498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
4508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
4528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Main function
4538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T)))
4558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int PreprocessARGB(const uint8_t* const r_ptr,
4578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                          const uint8_t* const g_ptr,
4588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                          const uint8_t* const b_ptr,
4598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                          int step, int rgb_stride,
4608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                          WebPPicture* const picture) {
4618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // we expand the right/bottom border if needed
4628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int w = (picture->width + 1) & ~1;
4638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int h = (picture->height + 1) & ~1;
4648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_w = w >> 1;
4658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const int uv_h = h >> 1;
4668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j, iter;
4678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // TODO(skal): allocate one big memory chunk. But for now, it's easier
4698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // for valgrind debugging to have several chunks.
4708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t);   // scratch
4718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_y_t* const best_y = SAFE_ALLOC(w, h, fixed_y_t);
4728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_y_t* const target_y = SAFE_ALLOC(w, h, fixed_y_t);
4738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
4748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_t* const best_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
4758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_t* const target_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
4768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
4778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int ok;
4788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (best_y == NULL || best_uv == NULL ||
4808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      target_y == NULL || target_uv == NULL ||
4818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      best_rgb_y == NULL || best_rgb_uv == NULL ||
4828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      tmp_buffer == NULL) {
4838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
4848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    goto End;
4858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
4868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(picture->width >= kMinDimensionIterativeConversion);
4878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(picture->height >= kMinDimensionIterativeConversion);
4888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // Import RGB samples to W/RGB representation.
4908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (j = 0; j < picture->height; j += 2) {
4918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int is_last_row = (j == picture->height - 1);
4928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    fixed_y_t* const src1 = tmp_buffer;
4938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    fixed_y_t* const src2 = tmp_buffer + 3 * w;
4948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int off1 = j * rgb_stride;
4958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int off2 = off1 + rgb_stride;
4968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int uv_off = (j >> 1) * 3 * uv_w;
4978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    fixed_y_t* const dst_y = best_y + j * w;
4988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
4998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    // prepare two rows of input
5008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    ImportOneRow(r_ptr + off1, g_ptr + off1, b_ptr + off1,
5018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                 step, picture->width, src1);
5028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (!is_last_row) {
5038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      ImportOneRow(r_ptr + off2, g_ptr + off2, b_ptr + off2,
5048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                   step, picture->width, src2);
5058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    } else {
5068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      memcpy(src2, src1, 3 * w * sizeof(*src2));
5078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
5088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    UpdateW(src1, target_y + (j + 0) * w, w);
5098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    UpdateW(src2, target_y + (j + 1) * w, w);
5108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    UpdateChroma(src1, src2, target_uv + uv_off, dst_y, uv_w);
5118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    memcpy(best_uv + uv_off, target_uv + uv_off, 3 * uv_w * sizeof(*best_uv));
5128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    memcpy(dst_y + w, dst_y, w * sizeof(*dst_y));
5138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
5148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // Iterate and resolve clipping conflicts.
5168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (iter = 0; iter < kNumIterations; ++iter) {
5178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    int k;
5188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const fixed_t* cur_uv = best_uv;
5198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const fixed_t* prev_uv = best_uv;
5208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (j = 0; j < h; j += 2) {
5218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      fixed_y_t* const src1 = tmp_buffer;
5228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      fixed_y_t* const src2 = tmp_buffer + 3 * w;
5238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      {
5258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
5268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        InterpolateTwoRows(best_y + j * w, prev_uv, cur_uv, next_uv,
5278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                           w, src1, src2);
5288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        prev_uv = cur_uv;
5298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        cur_uv = next_uv;
5308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
5318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      UpdateW(src1, best_rgb_y + 0 * w, w);
5338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      UpdateW(src2, best_rgb_y + 1 * w, w);
5348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w);
5358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      // update two rows of Y and one row of RGB
5378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      for (i = 0; i < 2 * w; ++i) {
5388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        const int off = i + j * w;
5398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        const int diff_y = target_y[off] - best_rgb_y[i];
5408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        const int new_y = (int)best_y[off] + diff_y;
5418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        best_y[off] = clip_y(new_y);
5428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
5438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      for (i = 0; i < uv_w; ++i) {
5448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        const int off = 3 * (i + (j >> 1) * uv_w);
5458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        int W;
5468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        for (k = 0; k <= 2; ++k) {
5478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora          const int diff_uv = (int)target_uv[off + k] - best_rgb_uv[3 * i + k];
5488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora          best_uv[off + k] += diff_uv;
5498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        }
5508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        W = RGBToGray(best_uv[off + 0], best_uv[off + 1], best_uv[off + 2]);
5518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        for (k = 0; k <= 2; ++k) {
5528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora          best_uv[off + k] -= W;
5538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        }
5548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
5558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
5568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    // TODO(skal): add early-termination criterion
5578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
5588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // final reconstruction
5608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  ok = ConvertWRGBToYUV(best_y, best_uv, picture);
5618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora End:
5638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(best_y);
5648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(best_uv);
5658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(target_y);
5668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(target_uv);
5678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(best_rgb_y);
5688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(best_rgb_uv);
5698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  WebPSafeFree(tmp_buffer);
5708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return ok;
5718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
5728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SAFE_ALLOC
5738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora//------------------------------------------------------------------------------
5758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// "Fast" regular RGB->YUV
5768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM4(ptr, step) LinearToGamma(                     \
5788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[0]) +                              \
5798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[(step)]) +                         \
5808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[rgb_stride]) +                     \
5818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    GammaToLinear((ptr)[rgb_stride + (step)]), 0)          \
5828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM2(ptr) \
58433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    LinearToGamma(GammaToLinear((ptr)[0]) + GammaToLinear((ptr)[rgb_stride]), 1)
58533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
5868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM2ALPHA(ptr) ((ptr)[0] + (ptr)[rgb_stride])
5878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define SUM4ALPHA(ptr) (SUM2ALPHA(ptr) + SUM2ALPHA((ptr) + 4))
5888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if defined(USE_INVERSE_ALPHA_TABLE)
5908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
5918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic const int kAlphaFix = 19;
5928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Following table is (1 << kAlphaFix) / a. The (v * kInvAlpha[a]) >> kAlphaFix
5938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// formula is then equal to v / a in most (99.6%) cases. Note that this table
5948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// and constant are adjusted very tightly to fit 32b arithmetic.
5958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// In particular, they use the fact that the operands for 'v / a' are actually
5968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3
5978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// with ai in [0..255] and pi in [0..1<<kGammaFix). The constraint to avoid
5988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// overflow is: kGammaFix + kAlphaFix <= 31.
5998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic const uint32_t kInvAlpha[4 * 0xff + 1] = {
6008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  0,  /* alpha = 0 */
6018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  524288, 262144, 174762, 131072, 104857, 87381, 74898, 65536,
6028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  58254, 52428, 47662, 43690, 40329, 37449, 34952, 32768,
6038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  30840, 29127, 27594, 26214, 24966, 23831, 22795, 21845,
6048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  20971, 20164, 19418, 18724, 18078, 17476, 16912, 16384,
6058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  15887, 15420, 14979, 14563, 14169, 13797, 13443, 13107,
6068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  12787, 12483, 12192, 11915, 11650, 11397, 11155, 10922,
6078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  10699, 10485, 10280, 10082, 9892, 9709, 9532, 9362,
6088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  9198, 9039, 8886, 8738, 8594, 8456, 8322, 8192,
6098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  8065, 7943, 7825, 7710, 7598, 7489, 7384, 7281,
6108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  7182, 7084, 6990, 6898, 6808, 6721, 6636, 6553,
6118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  6472, 6393, 6316, 6241, 6168, 6096, 6026, 5957,
6128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  5890, 5825, 5761, 5698, 5637, 5577, 5518, 5461,
6138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  5405, 5349, 5295, 5242, 5190, 5140, 5090, 5041,
6148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4993, 4946, 4899, 4854, 4809, 4766, 4723, 4681,
6158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4639, 4599, 4559, 4519, 4481, 4443, 4405, 4369,
6168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4332, 4297, 4262, 4228, 4194, 4161, 4128, 4096,
6178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  4064, 4032, 4002, 3971, 3942, 3912, 3883, 3855,
6188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3826, 3799, 3771, 3744, 3718, 3692, 3666, 3640,
6198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3615, 3591, 3566, 3542, 3518, 3495, 3472, 3449,
6208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3426, 3404, 3382, 3360, 3339, 3318, 3297, 3276,
6218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3256, 3236, 3216, 3196, 3177, 3158, 3139, 3120,
6228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  3102, 3084, 3066, 3048, 3030, 3013, 2995, 2978,
6238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2962, 2945, 2928, 2912, 2896, 2880, 2864, 2849,
6248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2833, 2818, 2803, 2788, 2774, 2759, 2744, 2730,
6258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2716, 2702, 2688, 2674, 2661, 2647, 2634, 2621,
6268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2608, 2595, 2582, 2570, 2557, 2545, 2532, 2520,
6278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2508, 2496, 2484, 2473, 2461, 2449, 2438, 2427,
6288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2416, 2404, 2394, 2383, 2372, 2361, 2351, 2340,
6298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2330, 2319, 2309, 2299, 2289, 2279, 2269, 2259,
6308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2250, 2240, 2231, 2221, 2212, 2202, 2193, 2184,
6318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2175, 2166, 2157, 2148, 2139, 2131, 2122, 2114,
6328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2105, 2097, 2088, 2080, 2072, 2064, 2056, 2048,
6338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  2040, 2032, 2024, 2016, 2008, 2001, 1993, 1985,
6348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1978, 1971, 1963, 1956, 1949, 1941, 1934, 1927,
6358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1920, 1913, 1906, 1899, 1892, 1885, 1879, 1872,
6368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1865, 1859, 1852, 1846, 1839, 1833, 1826, 1820,
6378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1814, 1807, 1801, 1795, 1789, 1783, 1777, 1771,
6388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1765, 1759, 1753, 1747, 1741, 1736, 1730, 1724,
6398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1718, 1713, 1707, 1702, 1696, 1691, 1685, 1680,
6408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1675, 1669, 1664, 1659, 1653, 1648, 1643, 1638,
6418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1633, 1628, 1623, 1618, 1613, 1608, 1603, 1598,
6428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1593, 1588, 1583, 1579, 1574, 1569, 1565, 1560,
6438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1555, 1551, 1546, 1542, 1537, 1533, 1528, 1524,
6448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1519, 1515, 1510, 1506, 1502, 1497, 1493, 1489,
6458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1485, 1481, 1476, 1472, 1468, 1464, 1460, 1456,
6468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1452, 1448, 1444, 1440, 1436, 1432, 1428, 1424,
6478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1420, 1416, 1413, 1409, 1405, 1401, 1398, 1394,
6488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1390, 1387, 1383, 1379, 1376, 1372, 1368, 1365,
6498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1361, 1358, 1354, 1351, 1347, 1344, 1340, 1337,
6508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1334, 1330, 1327, 1323, 1320, 1317, 1314, 1310,
6518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1307, 1304, 1300, 1297, 1294, 1291, 1288, 1285,
6528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1281, 1278, 1275, 1272, 1269, 1266, 1263, 1260,
6538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1257, 1254, 1251, 1248, 1245, 1242, 1239, 1236,
6548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1233, 1230, 1227, 1224, 1222, 1219, 1216, 1213,
6558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1210, 1208, 1205, 1202, 1199, 1197, 1194, 1191,
6568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1188, 1186, 1183, 1180, 1178, 1175, 1172, 1170,
6578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1167, 1165, 1162, 1159, 1157, 1154, 1152, 1149,
6588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1147, 1144, 1142, 1139, 1137, 1134, 1132, 1129,
6598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1127, 1125, 1122, 1120, 1117, 1115, 1113, 1110,
6608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1108, 1106, 1103, 1101, 1099, 1096, 1094, 1092,
6618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1089, 1087, 1085, 1083, 1081, 1078, 1076, 1074,
6628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1072, 1069, 1067, 1065, 1063, 1061, 1059, 1057,
6638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1054, 1052, 1050, 1048, 1046, 1044, 1042, 1040,
6648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1038, 1036, 1034, 1032, 1030, 1028, 1026, 1024,
6658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1022, 1020, 1018, 1016, 1014, 1012, 1010, 1008,
6668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  1006, 1004, 1002, 1000, 998, 996, 994, 992,
6678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  991, 989, 987, 985, 983, 981, 979, 978,
6688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  976, 974, 972, 970, 969, 967, 965, 963,
6698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  961, 960, 958, 956, 954, 953, 951, 949,
6708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  948, 946, 944, 942, 941, 939, 937, 936,
6718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  934, 932, 931, 929, 927, 926, 924, 923,
6728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  921, 919, 918, 916, 914, 913, 911, 910,
6738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  908, 907, 905, 903, 902, 900, 899, 897,
6748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  896, 894, 893, 891, 890, 888, 887, 885,
6758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  884, 882, 881, 879, 878, 876, 875, 873,
6768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  872, 870, 869, 868, 866, 865, 863, 862,
6778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  860, 859, 858, 856, 855, 853, 852, 851,
6788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  849, 848, 846, 845, 844, 842, 841, 840,
6798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  838, 837, 836, 834, 833, 832, 830, 829,
6808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  828, 826, 825, 824, 823, 821, 820, 819,
6818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  817, 816, 815, 814, 812, 811, 810, 809,
6828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  807, 806, 805, 804, 802, 801, 800, 799,
6838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  798, 796, 795, 794, 793, 791, 790, 789,
6848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  788, 787, 786, 784, 783, 782, 781, 780,
6858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  779, 777, 776, 775, 774, 773, 772, 771,
6868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  769, 768, 767, 766, 765, 764, 763, 762,
6878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  760, 759, 758, 757, 756, 755, 754, 753,
6888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  752, 751, 750, 748, 747, 746, 745, 744,
6898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  743, 742, 741, 740, 739, 738, 737, 736,
6908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  735, 734, 733, 732, 731, 730, 729, 728,
6918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  727, 726, 725, 724, 723, 722, 721, 720,
6928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  719, 718, 717, 716, 715, 714, 713, 712,
6938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  711, 710, 709, 708, 707, 706, 705, 704,
6948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  703, 702, 701, 700, 699, 699, 698, 697,
6958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  696, 695, 694, 693, 692, 691, 690, 689,
6968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  688, 688, 687, 686, 685, 684, 683, 682,
6978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  681, 680, 680, 679, 678, 677, 676, 675,
6988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  674, 673, 673, 672, 671, 670, 669, 668,
6998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  667, 667, 666, 665, 664, 663, 662, 661,
7008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  661, 660, 659, 658, 657, 657, 656, 655,
7018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  654, 653, 652, 652, 651, 650, 649, 648,
7028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  648, 647, 646, 645, 644, 644, 643, 642,
7038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  641, 640, 640, 639, 638, 637, 637, 636,
7048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  635, 634, 633, 633, 632, 631, 630, 630,
7058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  629, 628, 627, 627, 626, 625, 624, 624,
7068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  623, 622, 621, 621, 620, 619, 618, 618,
7078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  617, 616, 616, 615, 614, 613, 613, 612,
7088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  611, 611, 610, 609, 608, 608, 607, 606,
7098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  606, 605, 604, 604, 603, 602, 601, 601,
7108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  600, 599, 599, 598, 597, 597, 596, 595,
7118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  595, 594, 593, 593, 592, 591, 591, 590,
7128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  589, 589, 588, 587, 587, 586, 585, 585,
7138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  584, 583, 583, 582, 581, 581, 580, 579,
7148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  579, 578, 578, 577, 576, 576, 575, 574,
7158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  574, 573, 572, 572, 571, 571, 570, 569,
7168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  569, 568, 568, 567, 566, 566, 565, 564,
7178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  564, 563, 563, 562, 561, 561, 560, 560,
7188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  559, 558, 558, 557, 557, 556, 555, 555,
7198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  554, 554, 553, 553, 552, 551, 551, 550,
7208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  550, 549, 548, 548, 547, 547, 546, 546,
7218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  545, 544, 544, 543, 543, 542, 542, 541,
7228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  541, 540, 539, 539, 538, 538, 537, 537,
7238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  536, 536, 535, 534, 534, 533, 533, 532,
7248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  532, 531, 531, 530, 530, 529, 529, 528,
7258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  527, 527, 526, 526, 525, 525, 524, 524,
7268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  523, 523, 522, 522, 521, 521, 520, 520,
7278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  519, 519, 518, 518, 517, 517, 516, 516,
7288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  515, 515, 514, 514
7298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora};
7308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// Note that LinearToGamma() expects the values to be premultiplied by 4,
7328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora// so we incorporate this factor 4 inside the DIVIDE_BY_ALPHA macro directly.
7338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define DIVIDE_BY_ALPHA(sum, a)  (((sum) * kInvAlpha[(a)]) >> (kAlphaFix - 2))
7348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#else
7368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#define DIVIDE_BY_ALPHA(sum, a) (4 * (sum) / (a))
7388c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7398c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif  // USE_INVERSE_ALPHA_TABLE
7408c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7418c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE int LinearToGammaWeighted(const uint8_t* src,
7428c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             const uint8_t* a_ptr,
7438c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             uint32_t total_a, int step,
7448c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             int rgb_stride) {
7458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  const uint32_t sum =
7468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[0] * GammaToLinear(src[0]) +
7478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[step] * GammaToLinear(src[step]) +
7488c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[rgb_stride] * GammaToLinear(src[rgb_stride]) +
7498c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      a_ptr[rgb_stride + step] * GammaToLinear(src[rgb_stride + step]);
7508c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert(total_a > 0 && total_a <= 4 * 0xff);
7518c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if defined(USE_INVERSE_ALPHA_TABLE)
7528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  assert((uint64_t)sum * kInvAlpha[total_a] < ((uint64_t)1 << 32));
7538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif
7548c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return LinearToGamma(DIVIDE_BY_ALPHA(sum, total_a), 0);
7558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
7568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE void ConvertRowToY(const uint8_t* const r_ptr,
7588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      const uint8_t* const g_ptr,
7598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      const uint8_t* const b_ptr,
7608c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      int step,
7618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      uint8_t* const dst_y,
7628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      int width,
7638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                      VP8Random* const rg) {
7648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j;
7658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (i = 0, j = 0; i < width; ++i, j += step) {
7668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_y[i] = RGBToY(r_ptr[j], g_ptr[j], b_ptr[j], rg);
7678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
7688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
7698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
7708c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE void ConvertRowsToUVWithAlpha(const uint8_t* const r_ptr,
7718c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                                 const uint8_t* const g_ptr,
7728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                                 const uint8_t* const b_ptr,
7738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                                 const uint8_t* const a_ptr,
7748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                                 int rgb_stride,
7758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                                 uint8_t* const dst_u,
7768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                                 uint8_t* const dst_v,
7778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                                 int width,
7788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                                 VP8Random* const rg) {
7798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j;
7808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // we loop over 2x2 blocks and produce one U/V value for each.
7818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (i = 0, j = 0; i < (width >> 1); ++i, j += 2 * sizeof(uint32_t)) {
7828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const uint32_t a = SUM4ALPHA(a_ptr + j);
7838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    int r, g, b;
7848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (a == 4 * 0xff || a == 0) {
7858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = SUM4(r_ptr + j, 4);
7868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = SUM4(g_ptr + j, 4);
7878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = SUM4(b_ptr + j, 4);
7888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    } else {
7898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 4, rgb_stride);
7908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 4, rgb_stride);
7918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 4, rgb_stride);
7928c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
7938c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_u[i] = RGBToU(r, g, b, rg);
7948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_v[i] = RGBToV(r, g, b, rg);
7958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
7968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (width & 1) {
7978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const uint32_t a = 2u * SUM2ALPHA(a_ptr + j);
7988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    int r, g, b;
7998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (a == 4 * 0xff || a == 0) {
8008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = SUM2(r_ptr + j);
8018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = SUM2(g_ptr + j);
8028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = SUM2(b_ptr + j);
8038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    } else {
8048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 0, rgb_stride);
8058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 0, rgb_stride);
8068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 0, rgb_stride);
8078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
8088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_u[i] = RGBToU(r, g, b, rg);
8098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_v[i] = RGBToV(r, g, b, rg);
8108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
8118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
8128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
8138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic WEBP_INLINE void ConvertRowsToUV(const uint8_t* const r_ptr,
8148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        const uint8_t* const g_ptr,
8158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        const uint8_t* const b_ptr,
8168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        int step, int rgb_stride,
8178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        uint8_t* const dst_u,
8188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        uint8_t* const dst_v,
8198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        int width,
8208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                        VP8Random* const rg) {
8218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int i, j;
8228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  for (i = 0, j = 0; i < (width >> 1); ++i, j += 2 * step) {
8238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int r = SUM4(r_ptr + j, step);
8248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int g = SUM4(g_ptr + j, step);
8258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int b = SUM4(b_ptr + j, step);
8268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_u[i] = RGBToU(r, g, b, rg);
8278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_v[i] = RGBToV(r, g, b, rg);
8288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
8298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (width & 1) {
8308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int r = SUM2(r_ptr + j);
8318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int g = SUM2(g_ptr + j);
8328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    const int b = SUM2(b_ptr + j);
8338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_u[i] = RGBToU(r, g, b, rg);
8348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    dst_v[i] = RGBToV(r, g, b, rg);
8358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
83633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
83733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
83833f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int ImportYUVAFromRGBA(const uint8_t* const r_ptr,
83933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              const uint8_t* const g_ptr,
84033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              const uint8_t* const b_ptr,
84133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              const uint8_t* const a_ptr,
84233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              int step,         // bytes per pixel
84333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              int rgb_stride,   // bytes per scanline
84433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              float dithering,
8458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              int use_iterative_conversion,
84633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                              WebPPicture* const picture) {
8478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  int y;
84833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int width = picture->width;
84933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int height = picture->height;
85033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride);
85133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  picture->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
85333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  picture->use_argb = 0;
85433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8558c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  // disable smart conversion if source is too small (overkill).
8568c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (width < kMinDimensionIterativeConversion ||
8578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      height < kMinDimensionIterativeConversion) {
8588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    use_iterative_conversion = 0;
8598c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
86033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8618c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (!WebPPictureAllocYUVA(picture, width, height)) {
8628c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    return 0;
8638c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  }
8648c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (has_alpha) {
8658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    WebPInitAlphaProcessing();
8668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    assert(step == 4);
8678c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if defined(USE_INVERSE_ALPHA_TABLE)
8688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    assert(kAlphaFix + kGammaFix <= 31);
8698c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif
87033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
87133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  if (use_iterative_conversion) {
8738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    InitGammaTablesF();
8748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) {
8758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      return 0;
87633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
8778c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (has_alpha) {
8788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      WebPExtractAlpha(a_ptr, rgb_stride, width, height,
8798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                       picture->a, picture->a_stride);
88033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
8818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  } else {
8828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_y = picture->y;
8838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_u = picture->u;
8848c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_v = picture->v;
8858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    uint8_t* dst_a = picture->a;
8868c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
8878c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    VP8Random base_rg;
8888c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    VP8Random* rg = NULL;
8898c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (dithering > 0.) {
8908c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      VP8InitRandom(&base_rg, dithering);
8918c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      rg = &base_rg;
89233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
89333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
8948c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    InitGammaTables();
8958c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
8968c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    // Downsample Y/U/V planes, two rows at a time
8978c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    for (y = 0; y < (height >> 1); ++y) {
8988c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      int rows_have_alpha = has_alpha;
8998c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off1 = (2 * y + 0) * rgb_stride;
9008c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off2 = (2 * y + 1) * rgb_stride;
9018c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      ConvertRowToY(r_ptr + off1, g_ptr + off1, b_ptr + off1, step,
9028c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                    dst_y, width, rg);
9038c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      ConvertRowToY(r_ptr + off2, g_ptr + off2, b_ptr + off2, step,
9048c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                    dst_y + picture->y_stride, width, rg);
9058c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_y += 2 * picture->y_stride;
9068c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (has_alpha) {
9078c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        rows_have_alpha &= !WebPExtractAlpha(a_ptr + off1, rgb_stride,
9088c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             width, 2,
9098c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                             dst_a, picture->a_stride);
9108c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        dst_a += 2 * picture->a_stride;
9118c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9128c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (!rows_have_alpha) {
9138c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        ConvertRowsToUV(r_ptr + off1, g_ptr + off1, b_ptr + off1,
9148c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                        step, rgb_stride, dst_u, dst_v, width, rg);
9158c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      } else {
9168c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        ConvertRowsToUVWithAlpha(r_ptr + off1, g_ptr + off1, b_ptr + off1,
9178c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                 a_ptr + off1, rgb_stride,
9188c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                 dst_u, dst_v, width, rg);
9198c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9208c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_u += picture->uv_stride;
9218c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      dst_v += picture->uv_stride;
9228c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    }
9238c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    if (height & 1) {    // extra last row
9248c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      const int off = 2 * y * rgb_stride;
9258c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      int row_has_alpha = has_alpha;
9268c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      ConvertRowToY(r_ptr + off, g_ptr + off, b_ptr + off, step,
9278c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                    dst_y, width, rg);
9288c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (row_has_alpha) {
9298c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        row_has_alpha &= !WebPExtractAlpha(a_ptr + off, 0, width, 1, dst_a, 0);
9308c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      }
9318c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      if (!row_has_alpha) {
9328c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        ConvertRowsToUV(r_ptr + off, g_ptr + off, b_ptr + off,
9338c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                        step, 0, dst_u, dst_v, width, rg);
9348c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora      } else {
9358c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora        ConvertRowsToUVWithAlpha(r_ptr + off, g_ptr + off, b_ptr + off,
9368c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                 a_ptr + off, 0,
9378c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                 dst_u, dst_v, width, rg);
93833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
93933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
94033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
94133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
94233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
94333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
94433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora#undef SUM4
9458c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM2
9468c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM4ALPHA
9478c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#undef SUM2ALPHA
94833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
94933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
95033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// call for ARGB->YUVA conversion
95133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
9528c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arorastatic int PictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace,
9538c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                             float dithering, int use_iterative_conversion) {
95433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
95533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture->argb == NULL) {
95633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
9578c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  } else if ((colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
9588c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
95933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  } else {
96033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const argb = (const uint8_t*)picture->argb;
96133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const r = ALPHA_IS_LAST ? argb + 2 : argb + 1;
96233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const g = ALPHA_IS_LAST ? argb + 1 : argb + 2;
96333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const b = ALPHA_IS_LAST ? argb + 0 : argb + 3;
96433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t* const a = ALPHA_IS_LAST ? argb + 3 : argb + 0;
96533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
9668c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora    picture->colorspace = WEBP_YUV420;
96733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride,
9688c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              dithering, use_iterative_conversion, picture);
96933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
97033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
97133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
9728c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Aroraint WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace,
9738c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                                  float dithering) {
9748c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, colorspace, dithering, 0);
9758c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
9768c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
97733f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) {
9788c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, colorspace, 0.f, 0);
9798c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora}
9808c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora
9818c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#if WEBP_ENCODER_ABI_VERSION > 0x0204
9828c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Aroraint WebPPictureSmartARGBToYUVA(WebPPicture* picture) {
9838c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora  return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1);
98433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
9858c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora#endif
98633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
98733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
98833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// call for YUVA -> ARGB conversion
98933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
99033f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureYUVAToARGB(WebPPicture* picture) {
99133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture == NULL) return 0;
99233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (picture->y == NULL || picture->u == NULL || picture->v == NULL) {
99333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
99433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
99533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) {
99633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
99733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
99833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if ((picture->colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
99933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
100033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
100133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  // Allocate a new argb buffer (discarding the previous one).
100233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!WebPPictureAllocARGB(picture, picture->width, picture->height)) return 0;
100333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  picture->use_argb = 1;
100433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
100533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  // Convert
100633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  {
100733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int y;
100833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int width = picture->width;
100933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int height = picture->height;
101033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const int argb_stride = 4 * picture->argb_stride;
101133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    uint8_t* dst = (uint8_t*)picture->argb;
101233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    const uint8_t *cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y;
101333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    WebPUpsampleLinePairFunc upsample = WebPGetLinePairConverter(ALPHA_IS_LAST);
101433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
101533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // First row, with replicated top samples.
101633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
101733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    cur_y += picture->y_stride;
101833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    dst += argb_stride;
101933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Center rows.
102033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (y = 1; y + 1 < height; y += 2) {
102133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t* const top_u = cur_u;
102233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const uint8_t* const top_v = cur_v;
102333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_u += picture->uv_stride;
102433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_v += picture->uv_stride;
102533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      upsample(cur_y, cur_y + picture->y_stride, top_u, top_v, cur_u, cur_v,
102633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora               dst, dst + argb_stride, width);
102733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      cur_y += 2 * picture->y_stride;
102833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      dst += 2 * argb_stride;
102933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
103033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Last row (if needed), with replicated bottom samples.
103133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (height > 1 && !(height & 1)) {
103233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
103333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
103433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    // Insert alpha values if needed, in replacement for the default 0xff ones.
103533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    if (picture->colorspace & WEBP_CSP_ALPHA_BIT) {
103633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      for (y = 0; y < height; ++y) {
103733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        uint32_t* const argb_dst = picture->argb + y * picture->argb_stride;
103833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        const uint8_t* const src = picture->a + y * picture->a_stride;
103933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        int x;
104033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        for (x = 0; x < width; ++x) {
104133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora          argb_dst[x] = (argb_dst[x] & 0x00ffffffu) | ((uint32_t)src[x] << 24);
104233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora        }
104333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      }
104433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
104533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
104633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
104733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
104833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
104933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
105033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// automatic import / conversion
105133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
105233f74dabbc7920a65ed435d7417987589febdc16Vikas Arorastatic int Import(WebPPicture* const picture,
105333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                  const uint8_t* const rgb, int rgb_stride,
105433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                  int step, int swap_rb, int import_alpha) {
105533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  int y;
105633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const uint8_t* const r_ptr = rgb + (swap_rb ? 2 : 0);
105733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const uint8_t* const g_ptr = rgb + 1;
105833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const uint8_t* const b_ptr = rgb + (swap_rb ? 0 : 2);
105933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const uint8_t* const a_ptr = import_alpha ? rgb + 3 : NULL;
106033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int width = picture->width;
106133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  const int height = picture->height;
106233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
106333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!picture->use_argb) {
106433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
10658c098653157979e397d3954fc2ea0ee43bae6ab2Vikas Arora                              0.f /* no dithering */, 0, picture);
106633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
106733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  if (!WebPPictureAlloc(picture)) return 0;
106833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
106933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  assert(step >= (import_alpha ? 4 : 3));
107033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  for (y = 0; y < height; ++y) {
107133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    uint32_t* const dst = &picture->argb[y * picture->argb_stride];
107233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    int x;
107333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    for (x = 0; x < width; ++x) {
107433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      const int offset = step * x + y * rgb_stride;
107533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora      dst[x] = MakeARGB32(import_alpha ? a_ptr[offset] : 0xff,
107633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          r_ptr[offset], g_ptr[offset], b_ptr[offset]);
107733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora    }
107833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  }
107933f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return 1;
108033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
108133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
108233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora// Public API
108333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
108433f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportRGB(WebPPicture* picture,
108533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                         const uint8_t* rgb, int rgb_stride) {
108633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (picture != NULL) ? Import(picture, rgb, rgb_stride, 3, 0, 0) : 0;
108733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
108833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
108933f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportBGR(WebPPicture* picture,
109033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                         const uint8_t* rgb, int rgb_stride) {
109133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (picture != NULL) ? Import(picture, rgb, rgb_stride, 3, 1, 0) : 0;
109233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
109333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
109433f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportRGBA(WebPPicture* picture,
109533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
109633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 0, 1) : 0;
109733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
109833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
109933f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportBGRA(WebPPicture* picture,
110033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
110133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 1, 1) : 0;
110233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
110333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
110433f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportRGBX(WebPPicture* picture,
110533f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
110633f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 0, 0) : 0;
110733f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
110833f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
110933f74dabbc7920a65ed435d7417987589febdc16Vikas Aroraint WebPPictureImportBGRX(WebPPicture* picture,
111033f74dabbc7920a65ed435d7417987589febdc16Vikas Arora                          const uint8_t* rgba, int rgba_stride) {
111133f74dabbc7920a65ed435d7417987589febdc16Vikas Arora  return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 1, 0) : 0;
111233f74dabbc7920a65ed435d7417987589febdc16Vikas Arora}
111333f74dabbc7920a65ed435d7417987589febdc16Vikas Arora
111433f74dabbc7920a65ed435d7417987589febdc16Vikas Arora//------------------------------------------------------------------------------
1115