Coverage Report

Created: 2025-10-12 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebp/src/dsp/yuv.c
Line
Count
Source
1
// Copyright 2010 Google Inc. All Rights Reserved.
2
//
3
// Use of this source code is governed by a BSD-style license
4
// that can be found in the COPYING file in the root of the source
5
// tree. An additional intellectual property rights grant can be found
6
// in the file PATENTS. All contributing project authors may
7
// be found in the AUTHORS file in the root of the source tree.
8
// -----------------------------------------------------------------------------
9
//
10
// YUV->RGB conversion functions
11
//
12
// Author: Skal (pascal.massimino@gmail.com)
13
14
#include "src/dsp/yuv.h"
15
16
#include <assert.h>
17
#include <stdlib.h>
18
19
#include "src/dsp/cpu.h"
20
#include "src/dsp/dsp.h"
21
#include "src/webp/decode.h"
22
#include "src/webp/types.h"
23
24
// Uncomment to disable gamma-compression during RGB->U/V averaging
25
#define USE_GAMMA_COMPRESSION
26
27
// If defined, use table to compute x / alpha.
28
#define USE_INVERSE_ALPHA_TABLE
29
30
#ifdef USE_GAMMA_COMPRESSION
31
#include <math.h>
32
#endif
33
34
//-----------------------------------------------------------------------------
35
// Plain-C version
36
37
#define ROW_FUNC(FUNC_NAME, FUNC, XSTEP)                                     \
38
  static void FUNC_NAME(                                                     \
39
      const uint8_t* WEBP_RESTRICT y, const uint8_t* WEBP_RESTRICT u,        \
40
0
      const uint8_t* WEBP_RESTRICT v, uint8_t* WEBP_RESTRICT dst, int len) { \
41
0
    const uint8_t* const end = dst + (len & ~1) * (XSTEP);                   \
42
0
    while (dst != end) {                                                     \
43
0
      FUNC(y[0], u[0], v[0], dst);                                           \
44
0
      FUNC(y[1], u[0], v[0], dst + (XSTEP));                                 \
45
0
      y += 2;                                                                \
46
0
      ++u;                                                                   \
47
0
      ++v;                                                                   \
48
0
      dst += 2 * (XSTEP);                                                    \
49
0
    }                                                                        \
50
0
    if (len & 1) {                                                           \
51
0
      FUNC(y[0], u[0], v[0], dst);                                           \
52
0
    }                                                                        \
53
0
  }
Unexecuted instantiation: yuv.c:YuvToRgbRow
Unexecuted instantiation: yuv.c:YuvToRgbaRow
Unexecuted instantiation: yuv.c:YuvToBgrRow
Unexecuted instantiation: yuv.c:YuvToBgraRow
Unexecuted instantiation: yuv.c:YuvToArgbRow
Unexecuted instantiation: yuv.c:YuvToRgba4444Row
Unexecuted instantiation: yuv.c:YuvToRgb565Row
54
55
// All variants implemented.
56
ROW_FUNC(YuvToRgbRow, VP8YuvToRgb, 3)
57
ROW_FUNC(YuvToBgrRow, VP8YuvToBgr, 3)
58
ROW_FUNC(YuvToRgbaRow, VP8YuvToRgba, 4)
59
ROW_FUNC(YuvToBgraRow, VP8YuvToBgra, 4)
60
ROW_FUNC(YuvToArgbRow, VP8YuvToArgb, 4)
61
ROW_FUNC(YuvToRgba4444Row, VP8YuvToRgba4444, 2)
62
ROW_FUNC(YuvToRgb565Row, VP8YuvToRgb565, 2)
63
64
#undef ROW_FUNC
65
66
// Main call for processing a plane with a WebPSamplerRowFunc function:
67
void WebPSamplerProcessPlane(const uint8_t* WEBP_RESTRICT y, int y_stride,
68
                             const uint8_t* WEBP_RESTRICT u,
69
                             const uint8_t* WEBP_RESTRICT v, int uv_stride,
70
                             uint8_t* WEBP_RESTRICT dst, int dst_stride,
71
0
                             int width, int height, WebPSamplerRowFunc func) {
72
0
  int j;
73
0
  for (j = 0; j < height; ++j) {
74
0
    func(y, u, v, dst, width);
75
0
    y += y_stride;
76
0
    if (j & 1) {
77
0
      u += uv_stride;
78
0
      v += uv_stride;
79
0
    }
80
0
    dst += dst_stride;
81
0
  }
82
0
}
83
84
//-----------------------------------------------------------------------------
85
// Main call
86
87
WebPSamplerRowFunc WebPSamplers[MODE_LAST];
88
89
extern VP8CPUInfo VP8GetCPUInfo;
90
extern void WebPInitSamplersSSE2(void);
91
extern void WebPInitSamplersSSE41(void);
92
extern void WebPInitSamplersMIPS32(void);
93
extern void WebPInitSamplersMIPSdspR2(void);
94
95
1
WEBP_DSP_INIT_FUNC(WebPInitSamplers) {
96
1
  WebPSamplers[MODE_RGB] = YuvToRgbRow;
97
1
  WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
98
1
  WebPSamplers[MODE_BGR] = YuvToBgrRow;
99
1
  WebPSamplers[MODE_BGRA] = YuvToBgraRow;
100
1
  WebPSamplers[MODE_ARGB] = YuvToArgbRow;
101
1
  WebPSamplers[MODE_RGBA_4444] = YuvToRgba4444Row;
102
1
  WebPSamplers[MODE_RGB_565] = YuvToRgb565Row;
103
1
  WebPSamplers[MODE_rgbA] = YuvToRgbaRow;
104
1
  WebPSamplers[MODE_bgrA] = YuvToBgraRow;
105
1
  WebPSamplers[MODE_Argb] = YuvToArgbRow;
106
1
  WebPSamplers[MODE_rgbA_4444] = YuvToRgba4444Row;
107
108
  // If defined, use CPUInfo() to overwrite some pointers with faster versions.
109
1
  if (VP8GetCPUInfo != NULL) {
110
1
#if defined(WEBP_HAVE_SSE2)
111
1
    if (VP8GetCPUInfo(kSSE2)) {
112
1
      WebPInitSamplersSSE2();
113
1
    }
114
1
#endif  // WEBP_HAVE_SSE2
115
1
#if defined(WEBP_HAVE_SSE41)
116
1
    if (VP8GetCPUInfo(kSSE4_1)) {
117
1
      WebPInitSamplersSSE41();
118
1
    }
119
1
#endif  // WEBP_HAVE_SSE41
120
#if defined(WEBP_USE_MIPS32)
121
    if (VP8GetCPUInfo(kMIPS32)) {
122
      WebPInitSamplersMIPS32();
123
    }
124
#endif  // WEBP_USE_MIPS32
125
#if defined(WEBP_USE_MIPS_DSP_R2)
126
    if (VP8GetCPUInfo(kMIPSdspR2)) {
127
      WebPInitSamplersMIPSdspR2();
128
    }
129
#endif  // WEBP_USE_MIPS_DSP_R2
130
1
  }
131
1
}
132
133
//-----------------------------------------------------------------------------
134
// ARGB -> YUV converters
135
136
static void ConvertARGBToY_C(const uint32_t* WEBP_RESTRICT argb,
137
0
                             uint8_t* WEBP_RESTRICT y, int width) {
138
0
  int i;
139
0
  for (i = 0; i < width; ++i) {
140
0
    const uint32_t p = argb[i];
141
0
    y[i] =
142
0
        VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff, YUV_HALF);
143
0
  }
144
0
}
145
146
void WebPConvertARGBToUV_C(const uint32_t* WEBP_RESTRICT argb,
147
                           uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v,
148
0
                           int src_width, int do_store) {
149
  // No rounding. Last pixel is dealt with separately.
150
0
  const int uv_width = src_width >> 1;
151
0
  int i;
152
0
  for (i = 0; i < uv_width; ++i) {
153
0
    const uint32_t v0 = argb[2 * i + 0];
154
0
    const uint32_t v1 = argb[2 * i + 1];
155
    // VP8RGBToU/V expects four accumulated pixels. Hence we need to
156
    // scale r/g/b value by a factor 2. We just shift v0/v1 one bit less.
157
0
    const int r = ((v0 >> 15) & 0x1fe) + ((v1 >> 15) & 0x1fe);
158
0
    const int g = ((v0 >> 7) & 0x1fe) + ((v1 >> 7) & 0x1fe);
159
0
    const int b = ((v0 << 1) & 0x1fe) + ((v1 << 1) & 0x1fe);
160
0
    const int tmp_u = VP8RGBToU(r, g, b, YUV_HALF << 2);
161
0
    const int tmp_v = VP8RGBToV(r, g, b, YUV_HALF << 2);
162
0
    if (do_store) {
163
0
      u[i] = tmp_u;
164
0
      v[i] = tmp_v;
165
0
    } else {
166
      // Approximated average-of-four. But it's an acceptable diff.
167
0
      u[i] = (u[i] + tmp_u + 1) >> 1;
168
0
      v[i] = (v[i] + tmp_v + 1) >> 1;
169
0
    }
170
0
  }
171
0
  if (src_width & 1) {  // last pixel
172
0
    const uint32_t v0 = argb[2 * i + 0];
173
0
    const int r = (v0 >> 14) & 0x3fc;
174
0
    const int g = (v0 >> 6) & 0x3fc;
175
0
    const int b = (v0 << 2) & 0x3fc;
176
0
    const int tmp_u = VP8RGBToU(r, g, b, YUV_HALF << 2);
177
0
    const int tmp_v = VP8RGBToV(r, g, b, YUV_HALF << 2);
178
0
    if (do_store) {
179
0
      u[i] = tmp_u;
180
0
      v[i] = tmp_v;
181
0
    } else {
182
0
      u[i] = (u[i] + tmp_u + 1) >> 1;
183
0
      v[i] = (v[i] + tmp_v + 1) >> 1;
184
0
    }
185
0
  }
186
0
}
187
188
//-----------------------------------------------------------------------------
189
190
static void ConvertRGBToY_C(const uint8_t* WEBP_RESTRICT rgb,
191
0
                            uint8_t* WEBP_RESTRICT y, int width, int step) {
192
0
  int i;
193
0
  for (i = 0; i < width; ++i, rgb += step) {
194
0
    y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF);
195
0
  }
196
0
}
197
198
static void ConvertBGRToY_C(const uint8_t* WEBP_RESTRICT bgr,
199
0
                            uint8_t* WEBP_RESTRICT y, int width, int step) {
200
0
  int i;
201
0
  for (i = 0; i < width; ++i, bgr += step) {
202
0
    y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF);
203
0
  }
204
0
}
205
206
void WebPConvertRGBA32ToUV_C(const uint16_t* WEBP_RESTRICT rgb,
207
                             uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v,
208
409k
                             int width) {
209
409k
  int i;
210
3.37M
  for (i = 0; i < width; i += 1, rgb += 4) {
211
2.96M
    const int r = rgb[0], g = rgb[1], b = rgb[2];
212
2.96M
    u[i] = VP8RGBToU(r, g, b, YUV_HALF << 2);
213
2.96M
    v[i] = VP8RGBToV(r, g, b, YUV_HALF << 2);
214
2.96M
  }
215
409k
}
216
217
//------------------------------------------------------------------------------
218
// Code for gamma correction
219
220
#if defined(USE_GAMMA_COMPRESSION)
221
222
// Gamma correction compensates loss of resolution during chroma subsampling.
223
34
#define GAMMA_FIX 12     // fixed-point precision for linear values
224
1.23G
#define GAMMA_TAB_FIX 7  // fixed-point fractional bits precision
225
34
#define GAMMA_TAB_SIZE (1 << (GAMMA_FIX - GAMMA_TAB_FIX))
226
static const double kGamma = 0.80;
227
static const int kGammaScale = ((1 << GAMMA_FIX) - 1);
228
static const int kGammaTabScale = (1 << GAMMA_TAB_FIX);
229
static const int kGammaTabRounder = (1 << GAMMA_TAB_FIX >> 1);
230
231
static int kLinearToGammaTab[GAMMA_TAB_SIZE + 1];
232
static uint16_t kGammaToLinearTab[256];
233
static volatile int kGammaTablesOk = 0;
234
extern VP8CPUInfo VP8GetCPUInfo;
235
236
1
WEBP_DSP_INIT_FUNC(WebPInitGammaTables) {
237
1
  if (!kGammaTablesOk) {
238
1
    int v;
239
1
    const double scale = (double)(1 << GAMMA_TAB_FIX) / kGammaScale;
240
1
    const double norm = 1. / 255.;
241
257
    for (v = 0; v <= 255; ++v) {
242
256
      kGammaToLinearTab[v] =
243
256
          (uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5);
244
256
    }
245
34
    for (v = 0; v <= GAMMA_TAB_SIZE; ++v) {
246
33
      kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5);
247
33
    }
248
1
    kGammaTablesOk = 1;
249
1
  }
250
1
}
251
252
2.47G
static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) {
253
2.47G
  return kGammaToLinearTab[v];
254
2.47G
}
255
256
618M
static WEBP_INLINE int Interpolate(int v) {
257
618M
  const int tab_pos = v >> (GAMMA_TAB_FIX + 2);   // integer part
258
618M
  const int x = v & ((kGammaTabScale << 2) - 1);  // fractional part
259
618M
  const int v0 = kLinearToGammaTab[tab_pos];
260
618M
  const int v1 = kLinearToGammaTab[tab_pos + 1];
261
618M
  const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x);  // interpolate
262
618M
  assert(tab_pos + 1 < GAMMA_TAB_SIZE + 1);
263
618M
  return y;
264
618M
}
265
266
// Convert a linear value 'v' to YUV_FIX+2 fixed-point precision
267
// U/V value, suitable for RGBToU/V calls.
268
618M
static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
269
618M
  const int y = Interpolate(base_value << shift);  // final uplifted value
270
618M
  return (y + kGammaTabRounder) >> GAMMA_TAB_FIX;  // descale
271
618M
}
272
273
#else
274
275
void WebPInitGammaTables(void) {}
276
static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; }
277
static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
278
  return (int)(base_value << shift);
279
}
280
281
#endif  // USE_GAMMA_COMPRESSION
282
283
#define SUM4(ptr, step)                                                  \
284
  LinearToGamma(GammaToLinear((ptr)[0]) + GammaToLinear((ptr)[(step)]) + \
285
                    GammaToLinear((ptr)[rgb_stride]) +                   \
286
                    GammaToLinear((ptr)[rgb_stride + (step)]),           \
287
                0)
288
289
#define SUM2(ptr) \
290
  LinearToGamma(GammaToLinear((ptr)[0]) + GammaToLinear((ptr)[rgb_stride]), 1)
291
292
//------------------------------------------------------------------------------
293
// "Fast" regular RGB->YUV
294
295
#define SUM4(ptr, step)                                                  \
296
343M
  LinearToGamma(GammaToLinear((ptr)[0]) + GammaToLinear((ptr)[(step)]) + \
297
343M
                    GammaToLinear((ptr)[rgb_stride]) +                   \
298
343M
                    GammaToLinear((ptr)[rgb_stride + (step)]),           \
299
343M
                0)
300
301
#define SUM2(ptr) \
302
358k
  LinearToGamma(GammaToLinear((ptr)[0]) + GammaToLinear((ptr)[rgb_stride]), 1)
303
304
358M
#define SUM2ALPHA(ptr) ((ptr)[0] + (ptr)[rgb_stride])
305
178M
#define SUM4ALPHA(ptr) (SUM2ALPHA(ptr) + SUM2ALPHA((ptr) + 4))
306
307
#if defined(USE_INVERSE_ALPHA_TABLE)
308
309
static const int kAlphaFix = 19;
310
// Following table is (1 << kAlphaFix) / a. The (v * kInvAlpha[a]) >> kAlphaFix
311
// formula is then equal to v / a in most (99.6%) cases. Note that this table
312
// and constant are adjusted very tightly to fit 32b arithmetic.
313
// In particular, they use the fact that the operands for 'v / a' are actually
314
// derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3
315
// with ai in [0..255] and pi in [0..1<<GAMMA_FIX). The constraint to avoid
316
// overflow is: GAMMA_FIX + kAlphaFix <= 31.
317
static const uint32_t kInvAlpha[4 * 0xff + 1] = {
318
    0, /* alpha = 0 */
319
    524288, 262144, 174762, 131072, 104857, 87381, 74898, 65536, 58254, 52428,
320
    47662,  43690,  40329,  37449,  34952,  32768, 30840, 29127, 27594, 26214,
321
    24966,  23831,  22795,  21845,  20971,  20164, 19418, 18724, 18078, 17476,
322
    16912,  16384,  15887,  15420,  14979,  14563, 14169, 13797, 13443, 13107,
323
    12787,  12483,  12192,  11915,  11650,  11397, 11155, 10922, 10699, 10485,
324
    10280,  10082,  9892,   9709,   9532,   9362,  9198,  9039,  8886,  8738,
325
    8594,   8456,   8322,   8192,   8065,   7943,  7825,  7710,  7598,  7489,
326
    7384,   7281,   7182,   7084,   6990,   6898,  6808,  6721,  6636,  6553,
327
    6472,   6393,   6316,   6241,   6168,   6096,  6026,  5957,  5890,  5825,
328
    5761,   5698,   5637,   5577,   5518,   5461,  5405,  5349,  5295,  5242,
329
    5190,   5140,   5090,   5041,   4993,   4946,  4899,  4854,  4809,  4766,
330
    4723,   4681,   4639,   4599,   4559,   4519,  4481,  4443,  4405,  4369,
331
    4332,   4297,   4262,   4228,   4194,   4161,  4128,  4096,  4064,  4032,
332
    4002,   3971,   3942,   3912,   3883,   3855,  3826,  3799,  3771,  3744,
333
    3718,   3692,   3666,   3640,   3615,   3591,  3566,  3542,  3518,  3495,
334
    3472,   3449,   3426,   3404,   3382,   3360,  3339,  3318,  3297,  3276,
335
    3256,   3236,   3216,   3196,   3177,   3158,  3139,  3120,  3102,  3084,
336
    3066,   3048,   3030,   3013,   2995,   2978,  2962,  2945,  2928,  2912,
337
    2896,   2880,   2864,   2849,   2833,   2818,  2803,  2788,  2774,  2759,
338
    2744,   2730,   2716,   2702,   2688,   2674,  2661,  2647,  2634,  2621,
339
    2608,   2595,   2582,   2570,   2557,   2545,  2532,  2520,  2508,  2496,
340
    2484,   2473,   2461,   2449,   2438,   2427,  2416,  2404,  2394,  2383,
341
    2372,   2361,   2351,   2340,   2330,   2319,  2309,  2299,  2289,  2279,
342
    2269,   2259,   2250,   2240,   2231,   2221,  2212,  2202,  2193,  2184,
343
    2175,   2166,   2157,   2148,   2139,   2131,  2122,  2114,  2105,  2097,
344
    2088,   2080,   2072,   2064,   2056,   2048,  2040,  2032,  2024,  2016,
345
    2008,   2001,   1993,   1985,   1978,   1971,  1963,  1956,  1949,  1941,
346
    1934,   1927,   1920,   1913,   1906,   1899,  1892,  1885,  1879,  1872,
347
    1865,   1859,   1852,   1846,   1839,   1833,  1826,  1820,  1814,  1807,
348
    1801,   1795,   1789,   1783,   1777,   1771,  1765,  1759,  1753,  1747,
349
    1741,   1736,   1730,   1724,   1718,   1713,  1707,  1702,  1696,  1691,
350
    1685,   1680,   1675,   1669,   1664,   1659,  1653,  1648,  1643,  1638,
351
    1633,   1628,   1623,   1618,   1613,   1608,  1603,  1598,  1593,  1588,
352
    1583,   1579,   1574,   1569,   1565,   1560,  1555,  1551,  1546,  1542,
353
    1537,   1533,   1528,   1524,   1519,   1515,  1510,  1506,  1502,  1497,
354
    1493,   1489,   1485,   1481,   1476,   1472,  1468,  1464,  1460,  1456,
355
    1452,   1448,   1444,   1440,   1436,   1432,  1428,  1424,  1420,  1416,
356
    1413,   1409,   1405,   1401,   1398,   1394,  1390,  1387,  1383,  1379,
357
    1376,   1372,   1368,   1365,   1361,   1358,  1354,  1351,  1347,  1344,
358
    1340,   1337,   1334,   1330,   1327,   1323,  1320,  1317,  1314,  1310,
359
    1307,   1304,   1300,   1297,   1294,   1291,  1288,  1285,  1281,  1278,
360
    1275,   1272,   1269,   1266,   1263,   1260,  1257,  1254,  1251,  1248,
361
    1245,   1242,   1239,   1236,   1233,   1230,  1227,  1224,  1222,  1219,
362
    1216,   1213,   1210,   1208,   1205,   1202,  1199,  1197,  1194,  1191,
363
    1188,   1186,   1183,   1180,   1178,   1175,  1172,  1170,  1167,  1165,
364
    1162,   1159,   1157,   1154,   1152,   1149,  1147,  1144,  1142,  1139,
365
    1137,   1134,   1132,   1129,   1127,   1125,  1122,  1120,  1117,  1115,
366
    1113,   1110,   1108,   1106,   1103,   1101,  1099,  1096,  1094,  1092,
367
    1089,   1087,   1085,   1083,   1081,   1078,  1076,  1074,  1072,  1069,
368
    1067,   1065,   1063,   1061,   1059,   1057,  1054,  1052,  1050,  1048,
369
    1046,   1044,   1042,   1040,   1038,   1036,  1034,  1032,  1030,  1028,
370
    1026,   1024,   1022,   1020,   1018,   1016,  1014,  1012,  1010,  1008,
371
    1006,   1004,   1002,   1000,   998,    996,   994,   992,   991,   989,
372
    987,    985,    983,    981,    979,    978,   976,   974,   972,   970,
373
    969,    967,    965,    963,    961,    960,   958,   956,   954,   953,
374
    951,    949,    948,    946,    944,    942,   941,   939,   937,   936,
375
    934,    932,    931,    929,    927,    926,   924,   923,   921,   919,
376
    918,    916,    914,    913,    911,    910,   908,   907,   905,   903,
377
    902,    900,    899,    897,    896,    894,   893,   891,   890,   888,
378
    887,    885,    884,    882,    881,    879,   878,   876,   875,   873,
379
    872,    870,    869,    868,    866,    865,   863,   862,   860,   859,
380
    858,    856,    855,    853,    852,    851,   849,   848,   846,   845,
381
    844,    842,    841,    840,    838,    837,   836,   834,   833,   832,
382
    830,    829,    828,    826,    825,    824,   823,   821,   820,   819,
383
    817,    816,    815,    814,    812,    811,   810,   809,   807,   806,
384
    805,    804,    802,    801,    800,    799,   798,   796,   795,   794,
385
    793,    791,    790,    789,    788,    787,   786,   784,   783,   782,
386
    781,    780,    779,    777,    776,    775,   774,   773,   772,   771,
387
    769,    768,    767,    766,    765,    764,   763,   762,   760,   759,
388
    758,    757,    756,    755,    754,    753,   752,   751,   750,   748,
389
    747,    746,    745,    744,    743,    742,   741,   740,   739,   738,
390
    737,    736,    735,    734,    733,    732,   731,   730,   729,   728,
391
    727,    726,    725,    724,    723,    722,   721,   720,   719,   718,
392
    717,    716,    715,    714,    713,    712,   711,   710,   709,   708,
393
    707,    706,    705,    704,    703,    702,   701,   700,   699,   699,
394
    698,    697,    696,    695,    694,    693,   692,   691,   690,   689,
395
    688,    688,    687,    686,    685,    684,   683,   682,   681,   680,
396
    680,    679,    678,    677,    676,    675,   674,   673,   673,   672,
397
    671,    670,    669,    668,    667,    667,   666,   665,   664,   663,
398
    662,    661,    661,    660,    659,    658,   657,   657,   656,   655,
399
    654,    653,    652,    652,    651,    650,   649,   648,   648,   647,
400
    646,    645,    644,    644,    643,    642,   641,   640,   640,   639,
401
    638,    637,    637,    636,    635,    634,   633,   633,   632,   631,
402
    630,    630,    629,    628,    627,    627,   626,   625,   624,   624,
403
    623,    622,    621,    621,    620,    619,   618,   618,   617,   616,
404
    616,    615,    614,    613,    613,    612,   611,   611,   610,   609,
405
    608,    608,    607,    606,    606,    605,   604,   604,   603,   602,
406
    601,    601,    600,    599,    599,    598,   597,   597,   596,   595,
407
    595,    594,    593,    593,    592,    591,   591,   590,   589,   589,
408
    588,    587,    587,    586,    585,    585,   584,   583,   583,   582,
409
    581,    581,    580,    579,    579,    578,   578,   577,   576,   576,
410
    575,    574,    574,    573,    572,    572,   571,   571,   570,   569,
411
    569,    568,    568,    567,    566,    566,   565,   564,   564,   563,
412
    563,    562,    561,    561,    560,    560,   559,   558,   558,   557,
413
    557,    556,    555,    555,    554,    554,   553,   553,   552,   551,
414
    551,    550,    550,    549,    548,    548,   547,   547,   546,   546,
415
    545,    544,    544,    543,    543,    542,   542,   541,   541,   540,
416
    539,    539,    538,    538,    537,    537,   536,   536,   535,   534,
417
    534,    533,    533,    532,    532,    531,   531,   530,   530,   529,
418
    529,    528,    527,    527,    526,    526,   525,   525,   524,   524,
419
    523,    523,    522,    522,    521,    521,   520,   520,   519,   519,
420
    518,    518,    517,    517,    516,    516,   515,   515,   514,   514};
421
422
// Note that LinearToGamma() expects the values to be premultiplied by 4,
423
// so we incorporate this factor 4 inside the DIVIDE_BY_ALPHA macro directly.
424
274M
#define DIVIDE_BY_ALPHA(sum, a) (((sum) * kInvAlpha[(a)]) >> (kAlphaFix - 2))
425
426
#else
427
428
#define DIVIDE_BY_ALPHA(sum, a) (4 * (sum) / (a))
429
430
#endif  // USE_INVERSE_ALPHA_TABLE
431
432
static WEBP_INLINE int LinearToGammaWeighted(const uint8_t* src,
433
                                             const uint8_t* a_ptr,
434
                                             uint32_t total_a, int step,
435
274M
                                             int rgb_stride) {
436
274M
  const uint32_t sum =
437
274M
      a_ptr[0] * GammaToLinear(src[0]) +
438
274M
      a_ptr[step] * GammaToLinear(src[step]) +
439
274M
      a_ptr[rgb_stride] * GammaToLinear(src[rgb_stride]) +
440
274M
      a_ptr[rgb_stride + step] * GammaToLinear(src[rgb_stride + step]);
441
274M
  assert(total_a > 0 && total_a <= 4 * 0xff);
442
274M
#if defined(USE_INVERSE_ALPHA_TABLE)
443
274M
  assert((uint64_t)sum * kInvAlpha[total_a] < ((uint64_t)1 << 32));
444
274M
#endif
445
274M
  return LinearToGamma(DIVIDE_BY_ALPHA(sum, total_a), 0);
446
274M
}
447
448
void WebPAccumulateRGBA(const uint8_t* const r_ptr, const uint8_t* const g_ptr,
449
                        const uint8_t* const b_ptr, const uint8_t* const a_ptr,
450
403k
                        int rgb_stride, uint16_t* dst, int width) {
451
403k
  int i, j;
452
  // we loop over 2x2 blocks and produce one R/G/B/A value for each.
453
179M
  for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * 4, dst += 4) {
454
178M
    const uint32_t a = SUM4ALPHA(a_ptr + j);
455
178M
    int r, g, b;
456
178M
    if (a == 4 * 0xff || a == 0) {
457
87.5M
      r = SUM4(r_ptr + j, 4);
458
87.5M
      g = SUM4(g_ptr + j, 4);
459
87.5M
      b = SUM4(b_ptr + j, 4);
460
91.4M
    } else {
461
91.4M
      r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 4, rgb_stride);
462
91.4M
      g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 4, rgb_stride);
463
91.4M
      b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 4, rgb_stride);
464
91.4M
    }
465
178M
    dst[0] = r;
466
178M
    dst[1] = g;
467
178M
    dst[2] = b;
468
178M
    dst[3] = a;
469
178M
  }
470
403k
  if (width & 1) {
471
193k
    const uint32_t a = 2u * SUM2ALPHA(a_ptr + j);
472
193k
    int r, g, b;
473
193k
    if (a == 4 * 0xff || a == 0) {
474
87.6k
      r = SUM2(r_ptr + j);
475
87.6k
      g = SUM2(g_ptr + j);
476
87.6k
      b = SUM2(b_ptr + j);
477
105k
    } else {
478
105k
      r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 0, rgb_stride);
479
105k
      g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 0, rgb_stride);
480
105k
      b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 0, rgb_stride);
481
105k
    }
482
193k
    dst[0] = r;
483
193k
    dst[1] = g;
484
193k
    dst[2] = b;
485
193k
    dst[3] = a;
486
193k
  }
487
403k
}
488
489
void WebPAccumulateRGB(const uint8_t* const r_ptr, const uint8_t* const g_ptr,
490
                       const uint8_t* const b_ptr, int step, int rgb_stride,
491
61.9k
                       uint16_t* dst, int width) {
492
61.9k
  int i, j;
493
27.1M
  for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * step, dst += 4) {
494
27.1M
    dst[0] = SUM4(r_ptr + j, step);
495
27.1M
    dst[1] = SUM4(g_ptr + j, step);
496
27.1M
    dst[2] = SUM4(b_ptr + j, step);
497
    // MemorySanitizer may raise false positives with data that passes through
498
    // RGBA32PackedToPlanar_16b_SSE41() due to incorrect modeling of shuffles.
499
    // See https://crbug.com/webp/573.
500
#ifdef WEBP_MSAN
501
    dst[3] = 0;
502
#endif
503
27.1M
  }
504
61.9k
  if (width & 1) {
505
31.9k
    dst[0] = SUM2(r_ptr + j);
506
31.9k
    dst[1] = SUM2(g_ptr + j);
507
31.9k
    dst[2] = SUM2(b_ptr + j);
508
#ifdef WEBP_MSAN
509
    dst[3] = 0;
510
#endif
511
31.9k
  }
512
61.9k
}
513
514
static void ImportYUVAFromRGBA_C(const uint8_t* r_ptr, const uint8_t* g_ptr,
515
                                 const uint8_t* b_ptr, const uint8_t* a_ptr,
516
                                 int step,        // bytes per pixel
517
                                 int rgb_stride,  // bytes per scanline
518
                                 int has_alpha, int width, int height,
519
                                 uint16_t* tmp_rgb, int y_stride, int uv_stride,
520
                                 int a_stride, uint8_t* dst_y, uint8_t* dst_u,
521
1.68k
                                 uint8_t* dst_v, uint8_t* dst_a) {
522
1.68k
  int y;
523
1.68k
  const int is_rgb = (r_ptr < b_ptr);  // otherwise it's bgr
524
1.68k
  const int uv_width = (width + 1) >> 1;
525
526
1.68k
  has_alpha &= dst_a != NULL;
527
1.68k
  if (has_alpha) {
528
1.22k
#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE)
529
1.22k
    assert(kAlphaFix + GAMMA_FIX <= 31);
530
1.22k
#endif
531
1.22k
  }
532
533
1.68k
  WebPInitGammaTables();
534
535
  // Downsample Y/U/V planes, two rows at a time
536
466k
  for (y = 0; y < (height >> 1); ++y) {
537
465k
    int rows_have_alpha = has_alpha;
538
465k
    if (is_rgb) {
539
0
      WebPConvertRGBToY(r_ptr, dst_y, width, step);
540
0
      WebPConvertRGBToY(r_ptr + rgb_stride, dst_y + y_stride, width, step);
541
465k
    } else {
542
465k
      WebPConvertBGRToY(b_ptr, dst_y, width, step);
543
465k
      WebPConvertBGRToY(b_ptr + rgb_stride, dst_y + y_stride, width, step);
544
465k
    }
545
465k
    dst_y += 2 * y_stride;
546
465k
    if (has_alpha) {
547
403k
      rows_have_alpha &=
548
403k
          !WebPExtractAlpha(a_ptr, rgb_stride, width, 2, dst_a, a_stride);
549
403k
      dst_a += 2 * a_stride;
550
403k
    }
551
    // Collect averaged R/G/B(/A)
552
465k
    if (!rows_have_alpha) {
553
61.7k
      WebPAccumulateRGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, tmp_rgb, width);
554
403k
    } else {
555
403k
      WebPAccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, rgb_stride, tmp_rgb,
556
403k
                         width);
557
403k
    }
558
    // Convert to U/V
559
465k
    WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
560
465k
    dst_u += uv_stride;
561
465k
    dst_v += uv_stride;
562
465k
    r_ptr += 2 * rgb_stride;
563
465k
    b_ptr += 2 * rgb_stride;
564
465k
    g_ptr += 2 * rgb_stride;
565
465k
    if (has_alpha) a_ptr += 2 * rgb_stride;
566
465k
  }
567
1.68k
}
568
569
static void ImportYUVAFromRGBALastLine_C(
570
    const uint8_t* r_ptr, const uint8_t* g_ptr, const uint8_t* b_ptr,
571
    const uint8_t* a_ptr,
572
    int step,  // bytes per pixel
573
    int has_alpha, int width, uint16_t* tmp_rgb, uint8_t* dst_y, uint8_t* dst_u,
574
836
    uint8_t* dst_v, uint8_t* dst_a) {
575
836
  const int is_rgb = (r_ptr < b_ptr);  // otherwise it's bgr
576
836
  const int uv_width = (width + 1) >> 1;
577
836
  int row_has_alpha = has_alpha && dst_a != NULL;
578
579
836
  if (is_rgb) {
580
0
    WebPConvertRGBToY(r_ptr, dst_y, width, step);
581
836
  } else {
582
836
    WebPConvertBGRToY(b_ptr, dst_y, width, step);
583
836
  }
584
836
  if (row_has_alpha) {
585
626
    row_has_alpha &= !WebPExtractAlpha(a_ptr, 0, width, 1, dst_a, 0);
586
626
  }
587
  // Collect averaged R/G/B(/A)
588
836
  if (!row_has_alpha) {
589
    // Collect averaged R/G/B
590
215
    WebPAccumulateRGB(r_ptr, g_ptr, b_ptr, step, /*rgb_stride=*/0, tmp_rgb,
591
215
                      width);
592
621
  } else {
593
621
    WebPAccumulateRGBA(r_ptr, g_ptr, b_ptr, a_ptr, /*rgb_stride=*/0, tmp_rgb,
594
621
                       width);
595
621
  }
596
836
  WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
597
836
}
598
599
//-----------------------------------------------------------------------------
600
601
void (*WebPConvertRGBToY)(const uint8_t* WEBP_RESTRICT rgb,
602
                          uint8_t* WEBP_RESTRICT y, int width, int step);
603
void (*WebPConvertBGRToY)(const uint8_t* WEBP_RESTRICT bgr,
604
                          uint8_t* WEBP_RESTRICT y, int width, int step);
605
void (*WebPConvertRGBA32ToUV)(const uint16_t* WEBP_RESTRICT rgb,
606
                              uint8_t* WEBP_RESTRICT u,
607
                              uint8_t* WEBP_RESTRICT v, int width);
608
609
void (*WebPImportYUVAFromRGBA)(const uint8_t* r_ptr, const uint8_t* g_ptr,
610
                               const uint8_t* b_ptr, const uint8_t* a_ptr,
611
                               int step,        // bytes per pixel
612
                               int rgb_stride,  // bytes per scanline
613
                               int has_alpha, int width, int height,
614
                               uint16_t* tmp_rgb, int y_stride, int uv_stride,
615
                               int a_stride, uint8_t* dst_y, uint8_t* dst_u,
616
                               uint8_t* dst_v, uint8_t* dst_a);
617
void (*WebPImportYUVAFromRGBALastLine)(
618
    const uint8_t* r_ptr, const uint8_t* g_ptr, const uint8_t* b_ptr,
619
    const uint8_t* a_ptr,
620
    int step,  // bytes per pixel
621
    int has_alpha, int width, uint16_t* tmp_rgb, uint8_t* dst_y, uint8_t* dst_u,
622
    uint8_t* dst_v, uint8_t* dst_a);
623
624
void (*WebPConvertARGBToY)(const uint32_t* WEBP_RESTRICT argb,
625
                           uint8_t* WEBP_RESTRICT y, int width);
626
void (*WebPConvertARGBToUV)(const uint32_t* WEBP_RESTRICT argb,
627
                            uint8_t* WEBP_RESTRICT u, uint8_t* WEBP_RESTRICT v,
628
                            int src_width, int do_store);
629
630
extern void WebPInitConvertARGBToYUVSSE2(void);
631
extern void WebPInitConvertARGBToYUVSSE41(void);
632
extern void WebPInitConvertARGBToYUVNEON(void);
633
634
1
WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
635
1
  WebPConvertARGBToY = ConvertARGBToY_C;
636
1
  WebPConvertARGBToUV = WebPConvertARGBToUV_C;
637
638
1
  WebPConvertRGBToY = ConvertRGBToY_C;
639
1
  WebPConvertBGRToY = ConvertBGRToY_C;
640
641
1
  WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C;
642
643
1
  WebPImportYUVAFromRGBA = ImportYUVAFromRGBA_C;
644
1
  WebPImportYUVAFromRGBALastLine = ImportYUVAFromRGBALastLine_C;
645
646
1
  if (VP8GetCPUInfo != NULL) {
647
1
#if defined(WEBP_HAVE_SSE2)
648
1
    if (VP8GetCPUInfo(kSSE2)) {
649
1
      WebPInitConvertARGBToYUVSSE2();
650
1
    }
651
1
#endif  // WEBP_HAVE_SSE2
652
1
#if defined(WEBP_HAVE_SSE41)
653
1
    if (VP8GetCPUInfo(kSSE4_1)) {
654
1
      WebPInitConvertARGBToYUVSSE41();
655
1
    }
656
1
#endif  // WEBP_HAVE_SSE41
657
1
  }
658
659
#if defined(WEBP_HAVE_NEON)
660
  if (WEBP_NEON_OMIT_C_CODE ||
661
      (VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
662
    WebPInitConvertARGBToYUVNEON();
663
  }
664
#endif  // WEBP_HAVE_NEON
665
666
1
  assert(WebPConvertARGBToY != NULL);
667
1
  assert(WebPConvertARGBToUV != NULL);
668
1
  assert(WebPConvertRGBToY != NULL);
669
1
  assert(WebPConvertBGRToY != NULL);
670
  assert(WebPConvertRGBA32ToUV != NULL);
671
1
}