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