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