yuv.h 8.15 KB
Newer Older
AoD314's avatar
AoD314 committed
1 2
// Copyright 2010 Google Inc. All Rights Reserved.
//
3 4 5 6 7
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
AoD314's avatar
AoD314 committed
8 9 10 11
// -----------------------------------------------------------------------------
//
// inline YUV<->RGB conversion function
//
AoD314's avatar
AoD314 committed
12 13 14 15 16
// The exact naming is Y'CbCr, following the ITU-R BT.601 standard.
// More information at: http://en.wikipedia.org/wiki/YCbCr
// Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16
// U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128
// V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128
17
// We use 16bit fixed point operations for RGB->YUV conversion (YUV_FIX).
AoD314's avatar
AoD314 committed
18 19 20 21 22 23 24
//
// For the Y'CbCr to RGB conversion, the BT.601 specification reads:
//   R = 1.164 * (Y-16) + 1.596 * (V-128)
//   G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.391 * (U-128)
//   B = 1.164 * (Y-16)                   + 2.018 * (U-128)
// where Y is in the [16,235] range, and U/V in the [16,240] range.
//
25 26 27 28 29 30 31 32
// The fixed-point implementation used here is:
//  R = (19077 . y             + 26149 . v - 14234) >> 6
//  G = (19077 . y -  6419 . u - 13320 . v +  8708) >> 6
//  B = (19077 . y + 33050 . u             - 17685) >> 6
// where the '.' operator is the mulhi_epu16 variant:
//   a . b = ((a << 8) * b) >> 16
// that preserves 8 bits of fractional precision before final descaling.

AoD314's avatar
AoD314 committed
33 34 35 36 37
// Author: Skal (pascal.massimino@gmail.com)

#ifndef WEBP_DSP_YUV_H_
#define WEBP_DSP_YUV_H_

38 39
#include "./dsp.h"
#include "../dec/vp8_dec.h"
AoD314's avatar
AoD314 committed
40 41 42 43 44 45 46 47 48 49 50

#if defined(WEBP_EXPERIMENTAL_FEATURES)
// Do NOT activate this feature for real compression. This is only experimental!
// This flag is for comparison purpose against JPEG's "YUVj" natural colorspace.
// This colorspace is close to Rec.601's Y'CbCr model with the notable
// difference of allowing larger range for luma/chroma.
// See http://en.wikipedia.org/wiki/YCbCr#JPEG_conversion paragraph, and its
// difference with http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
// #define USE_YUVj
#endif

AoD314's avatar
AoD314 committed
51 52 53
//------------------------------------------------------------------------------
// YUV -> RGB conversion

54
#ifdef __cplusplus
AoD314's avatar
AoD314 committed
55 56 57
extern "C" {
#endif

58 59 60 61 62 63
enum {
  YUV_FIX = 16,                    // fixed-point precision for RGB->YUV
  YUV_HALF = 1 << (YUV_FIX - 1),
  YUV_MASK = (256 << YUV_FIX) - 1,
  YUV_RANGE_MIN = -227,            // min value of r/g/b output
  YUV_RANGE_MAX = 256 + 226,       // max value of r/g/b output
AoD314's avatar
AoD314 committed
64

65 66 67 68
  YUV_FIX2 = 6,                   // fixed-point precision for YUV->RGB
  YUV_HALF2 = 1 << YUV_FIX2 >> 1,
  YUV_MASK2 = (256 << YUV_FIX2) - 1
};
AoD314's avatar
AoD314 committed
69

70 71
//------------------------------------------------------------------------------
// slower on x86 by ~7-8%, but bit-exact with the SSE2/NEON version
AoD314's avatar
AoD314 committed
72

73 74
static WEBP_INLINE int MultHi(int v, int coeff) {   // _mm_mulhi_epu16 emulation
  return (v * coeff) >> 8;
AoD314's avatar
AoD314 committed
75 76
}

77 78
static WEBP_INLINE int VP8Clip8(int v) {
  return ((v & ~YUV_MASK2) == 0) ? (v >> YUV_FIX2) : (v < 0) ? 0 : 255;
AoD314's avatar
AoD314 committed
79 80 81
}

static WEBP_INLINE int VP8YUVToR(int y, int v) {
82
  return VP8Clip8(MultHi(y, 19077) + MultHi(v, 26149) - 14234);
AoD314's avatar
AoD314 committed
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);
AoD314's avatar
AoD314 committed
87 88 89
}

static WEBP_INLINE int VP8YUVToB(int y, int u) {
90
  return VP8Clip8(MultHi(y, 19077) + MultHi(u, 33050) - 17685);
AoD314's avatar
AoD314 committed
91 92
}

93
static WEBP_INLINE void VP8YuvToRgb(int y, int u, int v,
AoD314's avatar
AoD314 committed
94
                                    uint8_t* const rgb) {
95 96 97
  rgb[0] = VP8YUVToR(y, v);
  rgb[1] = VP8YUVToG(y, u, v);
  rgb[2] = VP8YUVToB(y, u);
AoD314's avatar
AoD314 committed
98 99
}

100
static WEBP_INLINE void VP8YuvToBgr(int y, int u, int v,
AoD314's avatar
AoD314 committed
101
                                    uint8_t* const bgr) {
102 103 104
  bgr[0] = VP8YUVToB(y, u);
  bgr[1] = VP8YUVToG(y, u, v);
  bgr[2] = VP8YUVToR(y, v);
AoD314's avatar
AoD314 committed
105 106
}

107
static WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v,
AoD314's avatar
AoD314 committed
108
                                       uint8_t* const rgb) {
109 110 111 112 113
  const int r = VP8YUVToR(y, v);      // 5 usable bits
  const int g = VP8YUVToG(y, u, v);   // 6 usable bits
  const int b = VP8YUVToB(y, u);      // 5 usable bits
  const int rg = (r & 0xf8) | (g >> 5);
  const int gb = ((g << 3) & 0xe0) | (b >> 3);
AoD314's avatar
AoD314 committed
114 115 116 117 118 119 120 121 122
#ifdef WEBP_SWAP_16BIT_CSP
  rgb[0] = gb;
  rgb[1] = rg;
#else
  rgb[0] = rg;
  rgb[1] = gb;
#endif
}

123
static WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v,
AoD314's avatar
AoD314 committed
124
                                         uint8_t* const argb) {
125 126 127 128 129
  const int r = VP8YUVToR(y, v);        // 4 usable bits
  const int g = VP8YUVToG(y, u, v);     // 4 usable bits
  const int b = VP8YUVToB(y, u);        // 4 usable bits
  const int rg = (r & 0xf0) | (g >> 4);
  const int ba = (b & 0xf0) | 0x0f;     // overwrite the lower 4 bits
AoD314's avatar
AoD314 committed
130 131 132 133 134 135 136 137 138
#ifdef WEBP_SWAP_16BIT_CSP
  argb[0] = ba;
  argb[1] = rg;
#else
  argb[0] = rg;
  argb[1] = ba;
#endif
}

139 140
//-----------------------------------------------------------------------------
// Alpha handling variants
AoD314's avatar
AoD314 committed
141 142 143 144 145

static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
                                     uint8_t* const argb) {
  argb[0] = 0xff;
  VP8YuvToRgb(y, u, v, argb + 1);
AoD314's avatar
AoD314 committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
}

static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v,
                                     uint8_t* const bgra) {
  VP8YuvToBgr(y, u, v, bgra);
  bgra[3] = 0xff;
}

static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
                                     uint8_t* const rgba) {
  VP8YuvToRgb(y, u, v, rgba);
  rgba[3] = 0xff;
}

// Must be called before everything, to initialize the tables.
void VP8YUVInit(void);

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
//-----------------------------------------------------------------------------
// SSE2 extra functions (mostly for upsampling_sse2.c)

#if defined(WEBP_USE_SSE2)

// Process 32 pixels and store the result (16b, 24b or 32b per pixel) in *dst.
void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
                    uint8_t* dst);
void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
                   uint8_t* dst);
void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
                    uint8_t* dst);
void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
                   uint8_t* dst);
void VP8YuvToArgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
                    uint8_t* dst);
void VP8YuvToRgba444432(const uint8_t* y, const uint8_t* u, const uint8_t* v,
                        uint8_t* dst);
void VP8YuvToRgb56532(const uint8_t* y, const uint8_t* u, const uint8_t* v,
                      uint8_t* dst);

#endif    // WEBP_USE_SSE2

AoD314's avatar
AoD314 committed
186 187 188
//------------------------------------------------------------------------------
// RGB -> YUV conversion

189 190 191 192
// Stub functions that can be called with various rounding values:
static WEBP_INLINE int VP8ClipUV(int uv, int rounding) {
  uv = (uv + rounding + (128 << (YUV_FIX + 2))) >> (YUV_FIX + 2);
  return ((uv & ~0xff) == 0) ? uv : (uv < 0) ? 0 : 255;
AoD314's avatar
AoD314 committed
193 194
}

AoD314's avatar
AoD314 committed
195 196
#ifndef USE_YUVj

197
static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
AoD314's avatar
AoD314 committed
198
  const int luma = 16839 * r + 33059 * g + 6420 * b;
199
  return (luma + rounding + (16 << YUV_FIX)) >> YUV_FIX;  // no need to clip
AoD314's avatar
AoD314 committed
200 201
}

202
static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) {
AoD314's avatar
AoD314 committed
203
  const int u = -9719 * r - 19081 * g + 28800 * b;
204
  return VP8ClipUV(u, rounding);
AoD314's avatar
AoD314 committed
205 206
}

207
static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
AoD314's avatar
AoD314 committed
208
  const int v = +28800 * r - 24116 * g - 4684 * b;
209
  return VP8ClipUV(v, rounding);
AoD314's avatar
AoD314 committed
210 211
}

AoD314's avatar
AoD314 committed
212 213 214
#else

// This JPEG-YUV colorspace, only for comparison!
215
// These are also 16bit precision coefficients from Rec.601, but with full
AoD314's avatar
AoD314 committed
216
// [0..255] output range.
217
static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
AoD314's avatar
AoD314 committed
218
  const int luma = 19595 * r + 38470 * g + 7471 * b;
219
  return (luma + rounding) >> YUV_FIX;  // no need to clip
AoD314's avatar
AoD314 committed
220 221
}

222
static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) {
AoD314's avatar
AoD314 committed
223
  const int u = -11058 * r - 21710 * g + 32768 * b;
224
  return VP8ClipUV(u, rounding);
AoD314's avatar
AoD314 committed
225 226
}

227
static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
AoD314's avatar
AoD314 committed
228
  const int v = 32768 * r - 27439 * g - 5329 * b;
229
  return VP8ClipUV(v, rounding);
AoD314's avatar
AoD314 committed
230 231 232 233
}

#endif    // USE_YUVj

234
#ifdef __cplusplus
AoD314's avatar
AoD314 committed
235 236 237 238
}    // extern "C"
#endif

#endif  /* WEBP_DSP_YUV_H_ */