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