github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/image/webp/libwebp/src/dsp/yuv.h (about)

     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  // 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 read:
    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.
    31  // For YUV->RGB conversion, only 14bit fixed precision is used (YUV_FIX2).
    32  // That's the maximum possible for a convenient ARM implementation.
    33  //
    34  // Author: Skal (pascal.massimino@gmail.com)
    35  
    36  #ifndef WEBP_DSP_YUV_H_
    37  #define WEBP_DSP_YUV_H_
    38  
    39  #include "./dsp.h"
    40  #include "../dec/decode_vp8.h"
    41  
    42  // Define the following to use the LUT-based code:
    43  // #define WEBP_YUV_USE_TABLE
    44  
    45  #if defined(WEBP_EXPERIMENTAL_FEATURES)
    46  // Do NOT activate this feature for real compression. This is only experimental!
    47  // This flag is for comparison purpose against JPEG's "YUVj" natural colorspace.
    48  // This colorspace is close to Rec.601's Y'CbCr model with the notable
    49  // difference of allowing larger range for luma/chroma.
    50  // See http://en.wikipedia.org/wiki/YCbCr#JPEG_conversion paragraph, and its
    51  // difference with http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
    52  // #define USE_YUVj
    53  #endif
    54  
    55  //------------------------------------------------------------------------------
    56  // YUV -> RGB conversion
    57  
    58  #ifdef __cplusplus
    59  extern "C" {
    60  #endif
    61  
    62  enum {
    63    YUV_FIX = 16,                    // fixed-point precision for RGB->YUV
    64    YUV_HALF = 1 << (YUV_FIX - 1),
    65    YUV_MASK = (256 << YUV_FIX) - 1,
    66    YUV_RANGE_MIN = -227,            // min value of r/g/b output
    67    YUV_RANGE_MAX = 256 + 226,       // max value of r/g/b output
    68  
    69    YUV_FIX2 = 14,                   // fixed-point precision for YUV->RGB
    70    YUV_HALF2 = 1 << (YUV_FIX2 - 1),
    71    YUV_MASK2 = (256 << YUV_FIX2) - 1
    72  };
    73  
    74  // These constants are 14b fixed-point version of ITU-R BT.601 constants.
    75  #define kYScale 19077    // 1.164 = 255 / 219
    76  #define kVToR   26149    // 1.596 = 255 / 112 * 0.701
    77  #define kUToG   6419     // 0.391 = 255 / 112 * 0.886 * 0.114 / 0.587
    78  #define kVToG   13320    // 0.813 = 255 / 112 * 0.701 * 0.299 / 0.587
    79  #define kUToB   33050    // 2.018 = 255 / 112 * 0.886
    80  #define kRCst (-kYScale * 16 - kVToR * 128 + YUV_HALF2)
    81  #define kGCst (-kYScale * 16 + kUToG * 128 + kVToG * 128 + YUV_HALF2)
    82  #define kBCst (-kYScale * 16 - kUToB * 128 + YUV_HALF2)
    83  
    84  //------------------------------------------------------------------------------
    85  
    86  #if !defined(WEBP_YUV_USE_TABLE)
    87  
    88  // slower on x86 by ~7-8%, but bit-exact with the SSE2 version
    89  
    90  static WEBP_INLINE int VP8Clip8(int v) {
    91    return ((v & ~YUV_MASK2) == 0) ? (v >> YUV_FIX2) : (v < 0) ? 0 : 255;
    92  }
    93  
    94  static WEBP_INLINE int VP8YUVToR(int y, int v) {
    95    return VP8Clip8(kYScale * y + kVToR * v + kRCst);
    96  }
    97  
    98  static WEBP_INLINE int VP8YUVToG(int y, int u, int v) {
    99    return VP8Clip8(kYScale * y - kUToG * u - kVToG * v + kGCst);
   100  }
   101  
   102  static WEBP_INLINE int VP8YUVToB(int y, int u) {
   103    return VP8Clip8(kYScale * y + kUToB * u + kBCst);
   104  }
   105  
   106  static WEBP_INLINE void VP8YuvToRgb(int y, int u, int v,
   107                                      uint8_t* const rgb) {
   108    rgb[0] = VP8YUVToR(y, v);
   109    rgb[1] = VP8YUVToG(y, u, v);
   110    rgb[2] = VP8YUVToB(y, u);
   111  }
   112  
   113  static WEBP_INLINE void VP8YuvToBgr(int y, int u, int v,
   114                                      uint8_t* const bgr) {
   115    bgr[0] = VP8YUVToB(y, u);
   116    bgr[1] = VP8YUVToG(y, u, v);
   117    bgr[2] = VP8YUVToR(y, v);
   118  }
   119  
   120  static WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v,
   121                                         uint8_t* const rgb) {
   122    const int r = VP8YUVToR(y, v);      // 5 usable bits
   123    const int g = VP8YUVToG(y, u, v);   // 6 usable bits
   124    const int b = VP8YUVToB(y, u);      // 5 usable bits
   125    const int rg = (r & 0xf8) | (g >> 5);
   126    const int gb = ((g << 3) & 0xe0) | (b >> 3);
   127  #ifdef WEBP_SWAP_16BIT_CSP
   128    rgb[0] = gb;
   129    rgb[1] = rg;
   130  #else
   131    rgb[0] = rg;
   132    rgb[1] = gb;
   133  #endif
   134  }
   135  
   136  static WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v,
   137                                           uint8_t* const argb) {
   138    const int r = VP8YUVToR(y, v);        // 4 usable bits
   139    const int g = VP8YUVToG(y, u, v);     // 4 usable bits
   140    const int b = VP8YUVToB(y, u);        // 4 usable bits
   141    const int rg = (r & 0xf0) | (g >> 4);
   142    const int ba = (b & 0xf0) | 0x0f;     // overwrite the lower 4 bits
   143  #ifdef WEBP_SWAP_16BIT_CSP
   144    argb[0] = ba;
   145    argb[1] = rg;
   146  #else
   147    argb[0] = rg;
   148    argb[1] = ba;
   149  #endif
   150  }
   151  
   152  #else
   153  
   154  // Table-based version, not totally equivalent to the SSE2 version.
   155  // Rounding diff is only +/-1 though.
   156  
   157  extern int16_t VP8kVToR[256], VP8kUToB[256];
   158  extern int32_t VP8kVToG[256], VP8kUToG[256];
   159  extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
   160  extern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
   161  
   162  static WEBP_INLINE void VP8YuvToRgb(int y, int u, int v,
   163                                      uint8_t* const rgb) {
   164    const int r_off = VP8kVToR[v];
   165    const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
   166    const int b_off = VP8kUToB[u];
   167    rgb[0] = VP8kClip[y + r_off - YUV_RANGE_MIN];
   168    rgb[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
   169    rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
   170  }
   171  
   172  static WEBP_INLINE void VP8YuvToBgr(int y, int u, int v,
   173                                      uint8_t* const bgr) {
   174    const int r_off = VP8kVToR[v];
   175    const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
   176    const int b_off = VP8kUToB[u];
   177    bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN];
   178    bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
   179    bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN];
   180  }
   181  
   182  static WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v,
   183                                         uint8_t* const rgb) {
   184    const int r_off = VP8kVToR[v];
   185    const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
   186    const int b_off = VP8kUToB[u];
   187    const int rg = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
   188                    (VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
   189    const int gb = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
   190                     (VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
   191  #ifdef WEBP_SWAP_16BIT_CSP
   192    rgb[0] = gb;
   193    rgb[1] = rg;
   194  #else
   195    rgb[0] = rg;
   196    rgb[1] = gb;
   197  #endif
   198  }
   199  
   200  static WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v,
   201                                           uint8_t* const argb) {
   202    const int r_off = VP8kVToR[v];
   203    const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
   204    const int b_off = VP8kUToB[u];
   205    const int rg = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) |
   206                     VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]);
   207    const int ba = (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4) | 0x0f;
   208  #ifdef WEBP_SWAP_16BIT_CSP
   209    argb[0] = ba;
   210    argb[1] = rg;
   211  #else
   212    argb[0] = rg;
   213    argb[1] = ba;
   214  #endif
   215  }
   216  
   217  #endif  // WEBP_YUV_USE_TABLE
   218  
   219  //-----------------------------------------------------------------------------
   220  // Alpha handling variants
   221  
   222  static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
   223                                       uint8_t* const argb) {
   224    argb[0] = 0xff;
   225    VP8YuvToRgb(y, u, v, argb + 1);
   226  }
   227  
   228  static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v,
   229                                       uint8_t* const bgra) {
   230    VP8YuvToBgr(y, u, v, bgra);
   231    bgra[3] = 0xff;
   232  }
   233  
   234  static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
   235                                       uint8_t* const rgba) {
   236    VP8YuvToRgb(y, u, v, rgba);
   237    rgba[3] = 0xff;
   238  }
   239  
   240  // Must be called before everything, to initialize the tables.
   241  void VP8YUVInit(void);
   242  
   243  //-----------------------------------------------------------------------------
   244  // SSE2 extra functions (mostly for upsampling_sse2.c)
   245  
   246  #if defined(WEBP_USE_SSE2)
   247  
   248  #if defined(FANCY_UPSAMPLING)
   249  // Process 32 pixels and store the result (24b or 32b per pixel) in *dst.
   250  void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
   251                      uint8_t* dst);
   252  void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
   253                     uint8_t* dst);
   254  void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
   255                      uint8_t* dst);
   256  void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
   257                     uint8_t* dst);
   258  #endif  // FANCY_UPSAMPLING
   259  
   260  // Must be called to initialize tables before using the functions.
   261  void VP8YUVInitSSE2(void);
   262  
   263  #endif    // WEBP_USE_SSE2
   264  
   265  //------------------------------------------------------------------------------
   266  // RGB -> YUV conversion
   267  
   268  // Stub functions that can be called with various rounding values:
   269  static WEBP_INLINE int VP8ClipUV(int uv, int rounding) {
   270    uv = (uv + rounding + (128 << (YUV_FIX + 2))) >> (YUV_FIX + 2);
   271    return ((uv & ~0xff) == 0) ? uv : (uv < 0) ? 0 : 255;
   272  }
   273  
   274  #ifndef USE_YUVj
   275  
   276  static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
   277    const int luma = 16839 * r + 33059 * g + 6420 * b;
   278    return (luma + rounding + (16 << YUV_FIX)) >> YUV_FIX;  // no need to clip
   279  }
   280  
   281  static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) {
   282    const int u = -9719 * r - 19081 * g + 28800 * b;
   283    return VP8ClipUV(u, rounding);
   284  }
   285  
   286  static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
   287    const int v = +28800 * r - 24116 * g - 4684 * b;
   288    return VP8ClipUV(v, rounding);
   289  }
   290  
   291  #else
   292  
   293  // This JPEG-YUV colorspace, only for comparison!
   294  // These are also 16bit precision coefficients from Rec.601, but with full
   295  // [0..255] output range.
   296  static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
   297    const int luma = 19595 * r + 38470 * g + 7471 * b;
   298    return (luma + rounding) >> YUV_FIX;  // no need to clip
   299  }
   300  
   301  static WEBP_INLINE int VP8_RGB_TO_U(int r, int g, int b, int rounding) {
   302    const int u = -11058 * r - 21710 * g + 32768 * b;
   303    return VP8ClipUV(u, rounding);
   304  }
   305  
   306  static WEBP_INLINE int VP8_RGB_TO_V(int r, int g, int b, int rounding) {
   307    const int v = 32768 * r - 27439 * g - 5329 * b;
   308    return VP8ClipUV(v, rounding);
   309  }
   310  
   311  #endif    // USE_YUVj
   312  
   313  #ifdef __cplusplus
   314  }    // extern "C"
   315  #endif
   316  
   317  #endif  /* WEBP_DSP_YUV_H_ */