1
// Copyright 2011 Google Inc. All Rights Reserved.
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
// -----------------------------------------------------------------------------
10
// YUV to RGB upsampling functions.
12
// Author: somnath@google.com (Somnath Banerjee)
17
#if defined(__cplusplus) || defined(c_plusplus)
21
//------------------------------------------------------------------------------
24
#ifdef FANCY_UPSAMPLING
26
// Fancy upsampling functions to convert YUV to RGB
27
WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
29
// Given samples laid out in a square as:
32
// we interpolate u/v as:
33
// ([9*a + 3*b + 3*c + d 3*a + 9*b + 3*c + d] + [8 8]) / 16
34
// ([3*a + b + 9*c + 3*d a + 3*b + 3*c + 9*d] [8 8]) / 16
36
// We process u and v together stashed into 32bit (16bit each).
37
#define LOAD_UV(u, v) ((u) | ((v) << 16))
39
#define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
40
static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
41
const uint8_t* top_u, const uint8_t* top_v, \
42
const uint8_t* cur_u, const uint8_t* cur_v, \
43
uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
45
const int last_pixel_pair = (len - 1) >> 1; \
46
uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]); /* top-left sample */ \
47
uint32_t l_uv = LOAD_UV(cur_u[0], cur_v[0]); /* left-sample */ \
49
const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
50
FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \
53
const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
54
FUNC(bottom_y[0], uv0 & 0xff, (uv0 >> 16), bottom_dst); \
56
for (x = 1; x <= last_pixel_pair; ++x) { \
57
const uint32_t t_uv = LOAD_UV(top_u[x], top_v[x]); /* top sample */ \
58
const uint32_t uv = LOAD_UV(cur_u[x], cur_v[x]); /* sample */ \
59
/* precompute invariant values associated with first and second diagonals*/\
60
const uint32_t avg = tl_uv + t_uv + l_uv + uv + 0x00080008u; \
61
const uint32_t diag_12 = (avg + 2 * (t_uv + l_uv)) >> 3; \
62
const uint32_t diag_03 = (avg + 2 * (tl_uv + uv)) >> 3; \
64
const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \
65
const uint32_t uv1 = (diag_03 + t_uv) >> 1; \
66
FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
67
top_dst + (2 * x - 1) * XSTEP); \
68
FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \
69
top_dst + (2 * x - 0) * XSTEP); \
72
const uint32_t uv0 = (diag_03 + l_uv) >> 1; \
73
const uint32_t uv1 = (diag_12 + uv) >> 1; \
74
FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
75
bottom_dst + (2 * x - 1) * XSTEP); \
76
FUNC(bottom_y[2 * x + 0], uv1 & 0xff, (uv1 >> 16), \
77
bottom_dst + (2 * x + 0) * XSTEP); \
84
const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
85
FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
86
top_dst + (len - 1) * XSTEP); \
89
const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
90
FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
91
bottom_dst + (len - 1) * XSTEP); \
96
// All variants implemented.
97
UPSAMPLE_FUNC(UpsampleRgbLinePair, VP8YuvToRgb, 3)
98
UPSAMPLE_FUNC(UpsampleBgrLinePair, VP8YuvToBgr, 3)
99
UPSAMPLE_FUNC(UpsampleRgbaLinePair, VP8YuvToRgba, 4)
100
UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
101
UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
102
UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 2)
103
UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
108
#endif // FANCY_UPSAMPLING
110
//------------------------------------------------------------------------------
111
// simple point-sampling
113
#define SAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
114
static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
115
const uint8_t* u, const uint8_t* v, \
116
uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
118
for (i = 0; i < len - 1; i += 2) { \
119
FUNC(top_y[0], u[0], v[0], top_dst); \
120
FUNC(top_y[1], u[0], v[0], top_dst + XSTEP); \
121
FUNC(bottom_y[0], u[0], v[0], bottom_dst); \
122
FUNC(bottom_y[1], u[0], v[0], bottom_dst + XSTEP); \
127
top_dst += 2 * XSTEP; \
128
bottom_dst += 2 * XSTEP; \
130
if (i == len - 1) { /* last one */ \
131
FUNC(top_y[0], u[0], v[0], top_dst); \
132
FUNC(bottom_y[0], u[0], v[0], bottom_dst); \
136
// All variants implemented.
137
SAMPLE_FUNC(SampleRgbLinePair, VP8YuvToRgb, 3)
138
SAMPLE_FUNC(SampleBgrLinePair, VP8YuvToBgr, 3)
139
SAMPLE_FUNC(SampleRgbaLinePair, VP8YuvToRgba, 4)
140
SAMPLE_FUNC(SampleBgraLinePair, VP8YuvToBgra, 4)
141
SAMPLE_FUNC(SampleArgbLinePair, VP8YuvToArgb, 4)
142
SAMPLE_FUNC(SampleRgba4444LinePair, VP8YuvToRgba4444, 2)
143
SAMPLE_FUNC(SampleRgb565LinePair, VP8YuvToRgb565, 2)
147
const WebPSampleLinePairFunc WebPSamplers[MODE_LAST] = {
148
SampleRgbLinePair, // MODE_RGB
149
SampleRgbaLinePair, // MODE_RGBA
150
SampleBgrLinePair, // MODE_BGR
151
SampleBgraLinePair, // MODE_BGRA
152
SampleArgbLinePair, // MODE_ARGB
153
SampleRgba4444LinePair, // MODE_RGBA_4444
154
SampleRgb565LinePair, // MODE_RGB_565
155
SampleRgbaLinePair, // MODE_rgbA
156
SampleBgraLinePair, // MODE_bgrA
157
SampleArgbLinePair, // MODE_Argb
158
SampleRgba4444LinePair // MODE_rgbA_4444
161
//------------------------------------------------------------------------------
163
#if !defined(FANCY_UPSAMPLING)
164
#define DUAL_SAMPLE_FUNC(FUNC_NAME, FUNC) \
165
static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bot_y, \
166
const uint8_t* top_u, const uint8_t* top_v, \
167
const uint8_t* bot_u, const uint8_t* bot_v, \
168
uint8_t* top_dst, uint8_t* bot_dst, int len) { \
169
const int half_len = len >> 1; \
171
if (top_dst != NULL) { \
172
for (x = 0; x < half_len; ++x) { \
173
FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x + 0); \
174
FUNC(top_y[2 * x + 1], top_u[x], top_v[x], top_dst + 8 * x + 4); \
176
if (len & 1) FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x); \
178
if (bot_dst != NULL) { \
179
for (x = 0; x < half_len; ++x) { \
180
FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x + 0); \
181
FUNC(bot_y[2 * x + 1], bot_u[x], bot_v[x], bot_dst + 8 * x + 4); \
183
if (len & 1) FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x); \
187
DUAL_SAMPLE_FUNC(DualLineSamplerBGRA, VP8YuvToBgra)
188
DUAL_SAMPLE_FUNC(DualLineSamplerARGB, VP8YuvToArgb)
189
#undef DUAL_SAMPLE_FUNC
191
#endif // !FANCY_UPSAMPLING
193
WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last) {
194
WebPInitUpsamplers();
196
#ifdef FANCY_UPSAMPLING
197
return WebPUpsamplers[alpha_is_last ? MODE_BGRA : MODE_ARGB];
199
return (alpha_is_last ? DualLineSamplerBGRA : DualLineSamplerARGB);
203
//------------------------------------------------------------------------------
206
#define YUV444_FUNC(FUNC_NAME, FUNC, XSTEP) \
207
static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
208
uint8_t* dst, int len) { \
210
for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * XSTEP]); \
213
YUV444_FUNC(Yuv444ToRgb, VP8YuvToRgb, 3)
214
YUV444_FUNC(Yuv444ToBgr, VP8YuvToBgr, 3)
215
YUV444_FUNC(Yuv444ToRgba, VP8YuvToRgba, 4)
216
YUV444_FUNC(Yuv444ToBgra, VP8YuvToBgra, 4)
217
YUV444_FUNC(Yuv444ToArgb, VP8YuvToArgb, 4)
218
YUV444_FUNC(Yuv444ToRgba4444, VP8YuvToRgba4444, 2)
219
YUV444_FUNC(Yuv444ToRgb565, VP8YuvToRgb565, 2)
223
const WebPYUV444Converter WebPYUV444Converters[MODE_LAST] = {
224
Yuv444ToRgb, // MODE_RGB
225
Yuv444ToRgba, // MODE_RGBA
226
Yuv444ToBgr, // MODE_BGR
227
Yuv444ToBgra, // MODE_BGRA
228
Yuv444ToArgb, // MODE_ARGB
229
Yuv444ToRgba4444, // MODE_RGBA_4444
230
Yuv444ToRgb565, // MODE_RGB_565
231
Yuv444ToRgba, // MODE_rgbA
232
Yuv444ToBgra, // MODE_bgrA
233
Yuv444ToArgb, // MODE_Argb
234
Yuv444ToRgba4444 // MODE_rgbA_4444
237
//------------------------------------------------------------------------------
238
// Premultiplied modes
240
// non dithered-modes
242
// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.)
243
// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5),
244
// one can use instead: (x * a * 65793 + (1 << 23)) >> 24
245
#if 1 // (int)(x * a / 255.)
246
#define MULTIPLIER(a) ((a) * 32897UL)
247
#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
248
#else // (int)(x * a / 255. + .5)
249
#define MULTIPLIER(a) ((a) * 65793UL)
250
#define PREMULTIPLY(x, m) (((x) * (m) + (1UL << 23)) >> 24)
253
static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
254
int w, int h, int stride) {
256
uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
257
const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
259
for (i = 0; i < w; ++i) {
260
const uint32_t a = alpha[4 * i];
262
const uint32_t mult = MULTIPLIER(a);
263
rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
264
rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
265
rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
276
#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15
278
static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
279
return (x & 0xf0) | (x >> 4);
282
static WEBP_INLINE uint8_t dither_lo(uint8_t x) {
283
return (x & 0x0f) | (x << 4);
286
static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
287
return (x * m) >> 16;
290
static void ApplyAlphaMultiply4444(uint8_t* rgba4444,
291
int w, int h, int stride) {
294
for (i = 0; i < w; ++i) {
295
const uint8_t a = (rgba4444[2 * i + 1] & 0x0f);
296
const uint32_t mult = MULTIPLIER(a);
297
const uint8_t r = multiply(dither_hi(rgba4444[2 * i + 0]), mult);
298
const uint8_t g = multiply(dither_lo(rgba4444[2 * i + 0]), mult);
299
const uint8_t b = multiply(dither_hi(rgba4444[2 * i + 1]), mult);
300
rgba4444[2 * i + 0] = (r & 0xf0) | ((g >> 4) & 0x0f);
301
rgba4444[2 * i + 1] = (b & 0xf0) | a;
308
void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int)
309
= ApplyAlphaMultiply;
310
void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int)
311
= ApplyAlphaMultiply4444;
313
//------------------------------------------------------------------------------
316
void WebPInitUpsamplers(void) {
317
#ifdef FANCY_UPSAMPLING
318
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
319
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
320
WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
321
WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
322
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
323
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
324
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
326
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
327
if (VP8GetCPUInfo != NULL) {
328
#if defined(WEBP_USE_SSE2)
329
if (VP8GetCPUInfo(kSSE2)) {
330
WebPInitUpsamplersSSE2();
333
#if defined(WEBP_USE_NEON)
334
if (VP8GetCPUInfo(kNEON)) {
335
WebPInitUpsamplersNEON();
339
#endif // FANCY_UPSAMPLING
342
void WebPInitPremultiply(void) {
343
WebPApplyAlphaMultiply = ApplyAlphaMultiply;
344
WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply4444;
346
#ifdef FANCY_UPSAMPLING
347
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
348
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
349
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
350
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
352
if (VP8GetCPUInfo != NULL) {
353
#if defined(WEBP_USE_SSE2)
354
if (VP8GetCPUInfo(kSSE2)) {
355
WebPInitPremultiplySSE2();
358
#if defined(WEBP_USE_NEON)
359
if (VP8GetCPUInfo(kNEON)) {
360
WebPInitPremultiplyNEON();
364
#endif // FANCY_UPSAMPLING
367
#if defined(__cplusplus) || defined(c_plusplus)