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 | // inline YUV<->RGB conversion function |
11 | // |
12 | // The exact naming is Y'CbCr, following the ITU-R BT.601 standard. |
13 | // More information at: http://en.wikipedia.org/wiki/YCbCr |
14 | // Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16 |
15 | // U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128 |
16 | // V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128 |
17 | // We use 16bit fixed point operations for RGB->YUV conversion (YUV_FIX). |
18 | // |
19 | // For the Y'CbCr to RGB conversion, the BT.601 specification reads: |
20 | // R = 1.164 * (Y-16) + 1.596 * (V-128) |
21 | // G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.391 * (U-128) |
22 | // B = 1.164 * (Y-16) + 2.018 * (U-128) |
23 | // where Y is in the [16,235] range, and U/V in the [16,240] range. |
24 | // |
25 | // The fixed-point implementation used here is: |
26 | // R = (19077 . y + 26149 . v - 14234) >> 6 |
27 | // G = (19077 . y - 6419 . u - 13320 . v + 8708) >> 6 |
28 | // B = (19077 . y + 33050 . u - 17685) >> 6 |
29 | // where the '.' operator is the mulhi_epu16 variant: |
30 | // a . b = ((a << 8) * b) >> 16 |
31 | // that preserves 8 bits of fractional precision before final descaling. |
32 | |
33 | // Author: Skal (pascal.massimino@gmail.com) |
34 | |
35 | #ifndef WEBP_DSP_YUV_H_ |
36 | #define WEBP_DSP_YUV_H_ |
37 | |
38 | #include "./dsp.h" |
39 | #include "../dec/vp8_dec.h" |
40 | |
41 | #if defined(WEBP_EXPERIMENTAL_FEATURES) |
42 | // Do NOT activate this feature for real compression. This is only experimental! |
43 | // This flag is for comparison purpose against JPEG's "YUVj" natural colorspace. |
44 | // This colorspace is close to Rec.601's Y'CbCr model with the notable |
45 | // difference of allowing larger range for luma/chroma. |
46 | // See http://en.wikipedia.org/wiki/YCbCr#JPEG_conversion paragraph, and its |
47 | // difference with http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion |
48 | // #define USE_YUVj |
49 | #endif |
50 | |
51 | //------------------------------------------------------------------------------ |
52 | // YUV -> RGB conversion |
53 | |
54 | #ifdef __cplusplus |
55 | extern "C" { |
56 | #endif |
57 | |
58 | enum { |
59 | YUV_FIX = 16, // fixed-point precision for RGB->YUV |
60 | YUV_HALF = 1 << (YUV_FIX - 1), |
61 | YUV_MASK = (256 << YUV_FIX) - 1, |
62 | YUV_RANGE_MIN = -227, // min value of r/g/b output |
63 | YUV_RANGE_MAX = 256 + 226, // max value of r/g/b output |
64 | |
65 | YUV_FIX2 = 6, // fixed-point precision for YUV->RGB |
66 | YUV_HALF2 = 1 << YUV_FIX2 >> 1, |
67 | YUV_MASK2 = (256 << YUV_FIX2) - 1 |
68 | }; |
69 | |
70 | //------------------------------------------------------------------------------ |
71 | // slower on x86 by ~7-8%, but bit-exact with the SSE2/NEON version |
72 | |
73 | static WEBP_INLINE int MultHi(int v, int coeff) { // _mm_mulhi_epu16 emulation |
74 | return (v * coeff) >> 8; |
75 | } |
76 | |
77 | static WEBP_INLINE int VP8Clip8(int v) { |
78 | return ((v & ~YUV_MASK2) == 0) ? (v >> YUV_FIX2) : (v < 0) ? 0 : 255; |
79 | } |
80 | |
81 | static WEBP_INLINE int VP8YUVToR(int y, int v) { |
82 | return VP8Clip8(MultHi(y, 19077) + MultHi(v, 26149) - 14234); |
83 | } |
84 | |
85 | static WEBP_INLINE int VP8YUVToG(int y, int u, int v) { |
86 | return VP8Clip8(MultHi(y, 19077) - MultHi(u, 6419) - MultHi(v, 13320) + 8708); |
87 | } |
88 | |
89 | static WEBP_INLINE int VP8YUVToB(int y, int u) { |
90 | return VP8Clip8(MultHi(y, 19077) + MultHi(u, 33050) - 17685); |
91 | } |
92 | |
93 | static WEBP_INLINE void VP8YuvToRgb(int y, int u, int v, |
94 | uint8_t* const rgb) { |
95 | rgb[0] = VP8YUVToR(y, v); |
96 | rgb[1] = VP8YUVToG(y, u, v); |
97 | rgb[2] = VP8YUVToB(y, u); |
98 | } |
99 | |
100 | static WEBP_INLINE void VP8YuvToBgr(int y, int u, int v, |
101 | uint8_t* const bgr) { |
102 | bgr[0] = VP8YUVToB(y, u); |
103 | bgr[1] = VP8YUVToG(y, u, v); |
104 | bgr[2] = VP8YUVToR(y, v); |
105 | } |
106 | |
107 | static WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v, |
108 | uint8_t* const rgb) { |
109 | const int r = VP8YUVToR(y, v); // 5 usable bits |
110 | const int g = VP8YUVToG(y, u, v); // 6 usable bits |
111 | const int b = VP8YUVToB(y, u); // 5 usable bits |
112 | const int rg = (r & 0xf8) | (g >> 5); |
113 | const int gb = ((g << 3) & 0xe0) | (b >> 3); |
114 | #ifdef WEBP_SWAP_16BIT_CSP |
115 | rgb[0] = gb; |
116 | rgb[1] = rg; |
117 | #else |
118 | rgb[0] = rg; |
119 | rgb[1] = gb; |
120 | #endif |
121 | } |
122 | |
123 | static WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v, |
124 | uint8_t* const argb) { |
125 | const int r = VP8YUVToR(y, v); // 4 usable bits |
126 | const int g = VP8YUVToG(y, u, v); // 4 usable bits |
127 | const int b = VP8YUVToB(y, u); // 4 usable bits |
128 | const int rg = (r & 0xf0) | (g >> 4); |
129 | const int ba = (b & 0xf0) | 0x0f; // overwrite the lower 4 bits |
130 | #ifdef WEBP_SWAP_16BIT_CSP |
131 | argb[0] = ba; |
132 | argb[1] = rg; |
133 | #else |
134 | argb[0] = rg; |
135 | argb[1] = ba; |
136 | #endif |
137 | } |
138 | |
139 | //----------------------------------------------------------------------------- |
140 | // Alpha handling variants |
141 | |
142 | static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v, |
143 | uint8_t* const argb) { |
144 | argb[0] = 0xff; |
145 | VP8YuvToRgb(y, u, v, argb + 1); |
146 | } |
147 | |
148 | static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v, |
149 | uint8_t* const bgra) { |
150 | VP8YuvToBgr(y, u, v, bgra); |
151 | bgra[3] = 0xff; |
152 | } |
153 | |
154 | static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v, |
155 | uint8_t* const rgba) { |
156 | VP8YuvToRgb(y, u, v, rgba); |
157 | rgba[3] = 0xff; |
158 | } |
159 | |
160 | // Must be called before everything, to initialize the tables. |
161 | void VP8YUVInit(void); |
162 | |
163 | //----------------------------------------------------------------------------- |
164 | // SSE2 extra functions (mostly for upsampling_sse2.c) |
165 | |
166 | #if defined(WEBP_USE_SSE2) |
167 | |
168 | // Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst. |
169 | void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v, |
170 | uint8_t* dst); |
171 | void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v, |
172 | uint8_t* dst); |
173 | void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v, |
174 | uint8_t* dst); |
175 | void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v, |
176 | uint8_t* dst); |
177 | void VP8YuvToArgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v, |
178 | uint8_t* dst); |
179 | void VP8YuvToRgba444432(const uint8_t* y, const uint8_t* u, const uint8_t* v, |
180 | uint8_t* dst); |
181 | void VP8YuvToRgb56532(const uint8_t* y, const uint8_t* u, const uint8_t* v, |
182 | uint8_t* dst); |
183 | |
184 | #endif // WEBP_USE_SSE2 |
185 | |
186 | //------------------------------------------------------------------------------ |
187 | // RGB -> YUV conversion |
188 | |
189 | // Stub functions that can be called with various rounding values: |
190 | static WEBP_INLINE int VP8ClipUV(int uv, int rounding) { |
191 | uv = (uv + rounding + (128 << (YUV_FIX + 2))) >> (YUV_FIX + 2); |
192 | return ((uv & ~0xff) == 0) ? uv : (uv < 0) ? 0 : 255; |
193 | } |
194 | |
195 | #ifndef USE_YUVj |
196 | |
197 | static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) { |
198 | const int luma = 16839 * r + 33059 * g + 6420 * b; |
199 | return (luma + rounding + (16 << YUV_FIX)) >> YUV_FIX; // no need to clip |
200 | } |
201 | |
202 | static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) { |
203 | const int u = -9719 * r - 19081 * g + 28800 * b; |
204 | return VP8ClipUV(u, rounding); |
205 | } |
206 | |
207 | static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) { |
208 | const int v = +28800 * r - 24116 * g - 4684 * b; |
209 | return VP8ClipUV(v, rounding); |
210 | } |
211 | |
212 | #else |
213 | |
214 | // This JPEG-YUV colorspace, only for comparison! |
215 | // These are also 16bit precision coefficients from Rec.601, but with full |
216 | // [0..255] output range. |
217 | static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) { |
218 | const int luma = 19595 * r + 38470 * g + 7471 * b; |
219 | return (luma + rounding) >> YUV_FIX; // no need to clip |
220 | } |
221 | |
222 | static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) { |
223 | const int u = -11058 * r - 21710 * g + 32768 * b; |
224 | return VP8ClipUV(u, rounding); |
225 | } |
226 | |
227 | static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) { |
228 | const int v = 32768 * r - 27439 * g - 5329 * b; |
229 | return VP8ClipUV(v, rounding); |
230 | } |
231 | |
232 | #endif // USE_YUVj |
233 | |
234 | #ifdef __cplusplus |
235 | } // extern "C" |
236 | #endif |
237 | |
238 | #endif /* WEBP_DSP_YUV_H_ */ |
239 | |