OLD | NEW |
1 // Copyright 2010 Google Inc. All Rights Reserved. | 1 // Copyright 2010 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // This code is licensed under the same terms as WebM: | 3 // This code is licensed under the same terms as WebM: |
4 // Software License Agreement: http://www.webmproject.org/license/software/ | 4 // Software License Agreement: http://www.webmproject.org/license/software/ |
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ | 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ |
6 // ----------------------------------------------------------------------------- | 6 // ----------------------------------------------------------------------------- |
7 // | 7 // |
8 // inline YUV<->RGB conversion function | 8 // inline YUV<->RGB conversion function |
9 // | 9 // |
| 10 // The exact naming is Y'CbCr, following the ITU-R BT.601 standard. |
| 11 // More information at: http://en.wikipedia.org/wiki/YCbCr |
| 12 // Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16 |
| 13 // U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128 |
| 14 // V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128 |
| 15 // We use 16bit fixed point operations for RGB->YUV conversion. |
| 16 // |
| 17 // For the Y'CbCr to RGB conversion, the BT.601 specification reads: |
| 18 // R = 1.164 * (Y-16) + 1.596 * (V-128) |
| 19 // G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.391 * (U-128) |
| 20 // B = 1.164 * (Y-16) + 2.018 * (U-128) |
| 21 // where Y is in the [16,235] range, and U/V in the [16,240] range. |
| 22 // In the table-lookup version (WEBP_YUV_USE_TABLE), the common factor |
| 23 // "1.164 * (Y-16)" can be handled as an offset in the VP8kClip[] table. |
| 24 // So in this case the formulae should be read as: |
| 25 // R = 1.164 * [Y + 1.371 * (V-128) ] - 18.624 |
| 26 // G = 1.164 * [Y - 0.698 * (V-128) - 0.336 * (U-128)] - 18.624 |
| 27 // B = 1.164 * [Y + 1.733 * (U-128)] - 18.624 |
| 28 // once factorized. Here too, 16bit fixed precision is used. |
| 29 // |
10 // Author: Skal (pascal.massimino@gmail.com) | 30 // Author: Skal (pascal.massimino@gmail.com) |
11 | 31 |
12 #ifndef WEBP_DSP_YUV_H_ | 32 #ifndef WEBP_DSP_YUV_H_ |
13 #define WEBP_DSP_YUV_H_ | 33 #define WEBP_DSP_YUV_H_ |
14 | 34 |
15 #include "../dec/decode_vp8.h" | 35 #include "../dec/decode_vp8.h" |
16 | 36 |
| 37 // Define the following to use the LUT-based code: |
| 38 #define WEBP_YUV_USE_TABLE |
| 39 |
| 40 #if defined(WEBP_EXPERIMENTAL_FEATURES) |
| 41 // Do NOT activate this feature for real compression. This is only experimental! |
| 42 // This flag is for comparison purpose against JPEG's "YUVj" natural colorspace. |
| 43 // This colorspace is close to Rec.601's Y'CbCr model with the notable |
| 44 // difference of allowing larger range for luma/chroma. |
| 45 // See http://en.wikipedia.org/wiki/YCbCr#JPEG_conversion paragraph, and its |
| 46 // difference with http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion |
| 47 // #define USE_YUVj |
| 48 #endif |
| 49 |
17 //------------------------------------------------------------------------------ | 50 //------------------------------------------------------------------------------ |
18 // YUV -> RGB conversion | 51 // YUV -> RGB conversion |
19 | 52 |
20 #if defined(__cplusplus) || defined(c_plusplus) | 53 #if defined(__cplusplus) || defined(c_plusplus) |
21 extern "C" { | 54 extern "C" { |
22 #endif | 55 #endif |
23 | 56 |
24 enum { YUV_FIX = 16, // fixed-point precision | 57 enum { YUV_FIX = 16, // fixed-point precision |
| 58 YUV_HALF = 1 << (YUV_FIX - 1), |
| 59 YUV_MASK = (256 << YUV_FIX) - 1, |
25 YUV_RANGE_MIN = -227, // min value of r/g/b output | 60 YUV_RANGE_MIN = -227, // min value of r/g/b output |
26 YUV_RANGE_MAX = 256 + 226 // max value of r/g/b output | 61 YUV_RANGE_MAX = 256 + 226 // max value of r/g/b output |
27 }; | 62 }; |
| 63 |
| 64 #ifdef WEBP_YUV_USE_TABLE |
| 65 |
28 extern int16_t VP8kVToR[256], VP8kUToB[256]; | 66 extern int16_t VP8kVToR[256], VP8kUToB[256]; |
29 extern int32_t VP8kVToG[256], VP8kUToG[256]; | 67 extern int32_t VP8kVToG[256], VP8kUToG[256]; |
30 extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN]; | 68 extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN]; |
31 extern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN]; | 69 extern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN]; |
32 | 70 |
33 static WEBP_INLINE void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v, | 71 static WEBP_INLINE void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v, |
34 uint8_t* const rgb) { | 72 uint8_t* const rgb) { |
35 const int r_off = VP8kVToR[v]; | 73 const int r_off = VP8kVToR[v]; |
36 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; | 74 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; |
37 const int b_off = VP8kUToB[u]; | 75 const int b_off = VP8kUToB[u]; |
38 rgb[0] = VP8kClip[y + r_off - YUV_RANGE_MIN]; | 76 rgb[0] = VP8kClip[y + r_off - YUV_RANGE_MIN]; |
39 rgb[1] = VP8kClip[y + g_off - YUV_RANGE_MIN]; | 77 rgb[1] = VP8kClip[y + g_off - YUV_RANGE_MIN]; |
40 rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN]; | 78 rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN]; |
41 } | 79 } |
42 | 80 |
| 81 static WEBP_INLINE void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v, |
| 82 uint8_t* const bgr) { |
| 83 const int r_off = VP8kVToR[v]; |
| 84 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; |
| 85 const int b_off = VP8kUToB[u]; |
| 86 bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN]; |
| 87 bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN]; |
| 88 bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN]; |
| 89 } |
| 90 |
43 static WEBP_INLINE void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v, | 91 static WEBP_INLINE void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v, |
44 uint8_t* const rgb) { | 92 uint8_t* const rgb) { |
45 const int r_off = VP8kVToR[v]; | 93 const int r_off = VP8kVToR[v]; |
46 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; | 94 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; |
47 const int b_off = VP8kUToB[u]; | 95 const int b_off = VP8kUToB[u]; |
48 rgb[0] = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) | | 96 const uint8_t rg = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) | |
49 (VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5)); | 97 (VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5)); |
50 rgb[1] = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) | | 98 const uint8_t gb = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) | |
51 (VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3)); | 99 (VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3)); |
52 } | 100 #ifdef WEBP_SWAP_16BIT_CSP |
53 | 101 rgb[0] = gb; |
54 static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v, | 102 rgb[1] = rg; |
55 uint8_t* const argb) { | 103 #else |
56 argb[0] = 0xff; | 104 rgb[0] = rg; |
57 VP8YuvToRgb(y, u, v, argb + 1); | 105 rgb[1] = gb; |
| 106 #endif |
58 } | 107 } |
59 | 108 |
60 static WEBP_INLINE void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v, | 109 static WEBP_INLINE void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v, |
61 uint8_t* const argb) { | 110 uint8_t* const argb) { |
62 const int r_off = VP8kVToR[v]; | 111 const int r_off = VP8kVToR[v]; |
63 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; | 112 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; |
64 const int b_off = VP8kUToB[u]; | 113 const int b_off = VP8kUToB[u]; |
65 // Don't update alpha (last 4 bits of argb[1]) | 114 const uint8_t rg = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) | |
66 argb[0] = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) | | 115 VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]); |
67 VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]); | 116 const uint8_t ba = (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4) | 0x0f; |
68 argb[1] = 0x0f | (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4); | 117 #ifdef WEBP_SWAP_16BIT_CSP |
| 118 argb[0] = ba; |
| 119 argb[1] = rg; |
| 120 #else |
| 121 argb[0] = rg; |
| 122 argb[1] = ba; |
| 123 #endif |
| 124 } |
| 125 |
| 126 #else // Table-free version (slower on x86) |
| 127 |
| 128 // These constants are 16b fixed-point version of ITU-R BT.601 constants |
| 129 #define kYScale 76309 // 1.164 = 255 / 219 |
| 130 #define kVToR 104597 // 1.596 = 255 / 112 * 0.701 |
| 131 #define kUToG 25674 // 0.391 = 255 / 112 * 0.886 * 0.114 / 0.587 |
| 132 #define kVToG 53278 // 0.813 = 255 / 112 * 0.701 * 0.299 / 0.587 |
| 133 #define kUToB 132201 // 2.018 = 255 / 112 * 0.886 |
| 134 #define kRCst (-kYScale * 16 - kVToR * 128 + YUV_HALF) |
| 135 #define kGCst (-kYScale * 16 + kUToG * 128 + kVToG * 128 + YUV_HALF) |
| 136 #define kBCst (-kYScale * 16 - kUToB * 128 + YUV_HALF) |
| 137 |
| 138 static WEBP_INLINE uint8_t VP8Clip8(int v) { |
| 139 return ((v & ~YUV_MASK) == 0) ? (uint8_t)(v >> YUV_FIX) |
| 140 : (v < 0) ? 0u : 255u; |
| 141 } |
| 142 |
| 143 static WEBP_INLINE uint8_t VP8ClipN(int v, int N) { // clip to N bits |
| 144 return ((v & ~YUV_MASK) == 0) ? (uint8_t)(v >> (YUV_FIX + (8 - N))) |
| 145 : (v < 0) ? 0u : (255u >> (8 - N)); |
| 146 } |
| 147 |
| 148 static WEBP_INLINE int VP8YUVToR(int y, int v) { |
| 149 return kYScale * y + kVToR * v + kRCst; |
| 150 } |
| 151 |
| 152 static WEBP_INLINE int VP8YUVToG(int y, int u, int v) { |
| 153 return kYScale * y - kUToG * u - kVToG * v + kGCst; |
| 154 } |
| 155 |
| 156 static WEBP_INLINE int VP8YUVToB(int y, int u) { |
| 157 return kYScale * y + kUToB * u + kBCst; |
| 158 } |
| 159 |
| 160 static WEBP_INLINE void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v, |
| 161 uint8_t* const rgb) { |
| 162 rgb[0] = VP8Clip8(VP8YUVToR(y, v)); |
| 163 rgb[1] = VP8Clip8(VP8YUVToG(y, u, v)); |
| 164 rgb[2] = VP8Clip8(VP8YUVToB(y, u)); |
69 } | 165 } |
70 | 166 |
71 static WEBP_INLINE void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v, | 167 static WEBP_INLINE void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v, |
72 uint8_t* const bgr) { | 168 uint8_t* const bgr) { |
73 const int r_off = VP8kVToR[v]; | 169 bgr[0] = VP8Clip8(VP8YUVToB(y, u)); |
74 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX; | 170 bgr[1] = VP8Clip8(VP8YUVToG(y, u, v)); |
75 const int b_off = VP8kUToB[u]; | 171 bgr[2] = VP8Clip8(VP8YUVToR(y, v)); |
76 bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN]; | 172 } |
77 bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN]; | 173 |
78 bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN]; | 174 static WEBP_INLINE void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v, |
| 175 uint8_t* const rgb) { |
| 176 const int r = VP8Clip8(VP8YUVToR(y, u)); |
| 177 const int g = VP8ClipN(VP8YUVToG(y, u, v), 6); |
| 178 const int b = VP8ClipN(VP8YUVToB(y, v), 5); |
| 179 const uint8_t rg = (r & 0xf8) | (g >> 3); |
| 180 const uint8_t gb = (g << 5) | b; |
| 181 #ifdef WEBP_SWAP_16BIT_CSP |
| 182 rgb[0] = gb; |
| 183 rgb[1] = rg; |
| 184 #else |
| 185 rgb[0] = rg; |
| 186 rgb[1] = gb; |
| 187 #endif |
| 188 } |
| 189 |
| 190 static WEBP_INLINE void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v, |
| 191 uint8_t* const argb) { |
| 192 const int r = VP8Clip8(VP8YUVToR(y, u)); |
| 193 const int g = VP8ClipN(VP8YUVToG(y, u, v), 4); |
| 194 const int b = VP8Clip8(VP8YUVToB(y, v)); |
| 195 const uint8_t rg = (r & 0xf0) | g; |
| 196 const uint8_t ba = b | 0x0f; // overwrite the lower 4 bits |
| 197 #ifdef WEBP_SWAP_16BIT_CSP |
| 198 argb[0] = ba; |
| 199 argb[1] = rg; |
| 200 #else |
| 201 argb[0] = rg; |
| 202 argb[1] = ba; |
| 203 #endif |
| 204 } |
| 205 |
| 206 #endif // WEBP_YUV_USE_TABLE |
| 207 |
| 208 static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v, |
| 209 uint8_t* const argb) { |
| 210 argb[0] = 0xff; |
| 211 VP8YuvToRgb(y, u, v, argb + 1); |
79 } | 212 } |
80 | 213 |
81 static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v, | 214 static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v, |
82 uint8_t* const bgra) { | 215 uint8_t* const bgra) { |
83 VP8YuvToBgr(y, u, v, bgra); | 216 VP8YuvToBgr(y, u, v, bgra); |
84 bgra[3] = 0xff; | 217 bgra[3] = 0xff; |
85 } | 218 } |
86 | 219 |
87 static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v, | 220 static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v, |
88 uint8_t* const rgba) { | 221 uint8_t* const rgba) { |
89 VP8YuvToRgb(y, u, v, rgba); | 222 VP8YuvToRgb(y, u, v, rgba); |
90 rgba[3] = 0xff; | 223 rgba[3] = 0xff; |
91 } | 224 } |
92 | 225 |
93 static WEBP_INLINE uint32_t VP8Clip4Bits(uint8_t c) { | |
94 const uint32_t v = (c + 8) >> 4; | |
95 return (v > 15) ? 15 : v; | |
96 } | |
97 | |
98 // Must be called before everything, to initialize the tables. | 226 // Must be called before everything, to initialize the tables. |
99 void VP8YUVInit(void); | 227 void VP8YUVInit(void); |
100 | 228 |
101 //------------------------------------------------------------------------------ | 229 //------------------------------------------------------------------------------ |
102 // RGB -> YUV conversion | 230 // RGB -> YUV conversion |
103 // The exact naming is Y'CbCr, following the ITU-R BT.601 standard. | |
104 // More information at: http://en.wikipedia.org/wiki/YCbCr | |
105 // Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16 | |
106 // U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128 | |
107 // V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128 | |
108 // We use 16bit fixed point operations. | |
109 | 231 |
110 static WEBP_INLINE int VP8ClipUV(int v) { | 232 static WEBP_INLINE int VP8ClipUV(int v) { |
111 v = (v + (257 << (YUV_FIX + 2 - 1))) >> (YUV_FIX + 2); | 233 v = (v + (257 << (YUV_FIX + 2 - 1))) >> (YUV_FIX + 2); |
112 return ((v & ~0xff) == 0) ? v : (v < 0) ? 0 : 255; | 234 return ((v & ~0xff) == 0) ? v : (v < 0) ? 0 : 255; |
113 } | 235 } |
114 | 236 |
| 237 #ifndef USE_YUVj |
| 238 |
115 static WEBP_INLINE int VP8RGBToY(int r, int g, int b) { | 239 static WEBP_INLINE int VP8RGBToY(int r, int g, int b) { |
116 const int kRound = (1 << (YUV_FIX - 1)) + (16 << YUV_FIX); | 240 const int kRound = (1 << (YUV_FIX - 1)) + (16 << YUV_FIX); |
117 const int luma = 16839 * r + 33059 * g + 6420 * b; | 241 const int luma = 16839 * r + 33059 * g + 6420 * b; |
118 return (luma + kRound) >> YUV_FIX; // no need to clip | 242 return (luma + kRound) >> YUV_FIX; // no need to clip |
119 } | 243 } |
120 | 244 |
121 static WEBP_INLINE int VP8RGBToU(int r, int g, int b) { | 245 static WEBP_INLINE int VP8RGBToU(int r, int g, int b) { |
122 return VP8ClipUV(-9719 * r - 19081 * g + 28800 * b); | 246 const int u = -9719 * r - 19081 * g + 28800 * b; |
| 247 return VP8ClipUV(u); |
123 } | 248 } |
124 | 249 |
125 static WEBP_INLINE int VP8RGBToV(int r, int g, int b) { | 250 static WEBP_INLINE int VP8RGBToV(int r, int g, int b) { |
126 return VP8ClipUV(+28800 * r - 24116 * g - 4684 * b); | 251 const int v = +28800 * r - 24116 * g - 4684 * b; |
| 252 return VP8ClipUV(v); |
127 } | 253 } |
128 | 254 |
| 255 #else |
| 256 |
| 257 // This JPEG-YUV colorspace, only for comparison! |
| 258 // These are also 16-bit precision coefficients from Rec.601, but with full |
| 259 // [0..255] output range. |
| 260 static WEBP_INLINE int VP8RGBToY(int r, int g, int b) { |
| 261 const int kRound = (1 << (YUV_FIX - 1)); |
| 262 const int luma = 19595 * r + 38470 * g + 7471 * b; |
| 263 return (luma + kRound) >> YUV_FIX; // no need to clip |
| 264 } |
| 265 |
| 266 static WEBP_INLINE int VP8RGBToU(int r, int g, int b) { |
| 267 const int u = -11058 * r - 21710 * g + 32768 * b; |
| 268 return VP8ClipUV(u); |
| 269 } |
| 270 |
| 271 static WEBP_INLINE int VP8RGBToV(int r, int g, int b) { |
| 272 const int v = 32768 * r - 27439 * g - 5329 * b; |
| 273 return VP8ClipUV(v); |
| 274 } |
| 275 |
| 276 #endif // USE_YUVj |
| 277 |
129 #if defined(__cplusplus) || defined(c_plusplus) | 278 #if defined(__cplusplus) || defined(c_plusplus) |
130 } // extern "C" | 279 } // extern "C" |
131 #endif | 280 #endif |
132 | 281 |
133 #endif /* WEBP_DSP_YUV_H_ */ | 282 #endif /* WEBP_DSP_YUV_H_ */ |
OLD | NEW |