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 (at) gmail.com) 34 35 #ifndef WEBP_DSP_YUV_H_ 36 #define WEBP_DSP_YUV_H_ 37 38 #include "./dsp.h" 39 #include "../dec/decode_vp8.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