| 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 |  | 
|---|