1 // Copyright 2010 Google Inc. All Rights Reserved.
2 //
3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // -----------------------------------------------------------------------------
7 //
8 // inline YUV<->RGB conversion function
9 //
10 // The exact naming is Y'CbCr, following the ITU-R BT.601 standard.
11 // More information at: http://en.wikipedia.org/wiki/YCbCr
12 // Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16
13 // U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128
14 // V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128
15 // We use 16bit fixed point operations for RGB->YUV conversion.
16 //
17 // For the Y'CbCr to RGB conversion, the BT.601 specification reads:
18 // R = 1.164 * (Y-16) + 1.596 * (V-128)
19 // G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.391 * (U-128)
20 // B = 1.164 * (Y-16) + 2.018 * (U-128)
21 // where Y is in the [16,235] range, and U/V in the [16,240] range.
22 // But the common term 1.164 * (Y-16) can be handled as an offset in the
23 // VP8kClip[] table. So the formulae should be read as:
24 // R = 1.164 * [Y + 1.371 * (V-128) ] - 18.624
25 // G = 1.164 * [Y - 0.698 * (V-128) - 0.336 * (U-128)] - 18.624
26 // B = 1.164 * [Y + 1.733 * (U-128)] - 18.624
27 // once factorized. Here too, 16bit fixed precision is used.
28 //
29 // Author: Skal (pascal.massimino@gmail.com)
30
31 #ifndef WEBP_DSP_YUV_H_
32 #define WEBP_DSP_YUV_H_
33
34 #include "../dec/decode_vp8.h"
35
36 #if defined(WEBP_EXPERIMENTAL_FEATURES)
37 // Do NOT activate this feature for real compression. This is only experimental!
38 // This flag is for comparison purpose against JPEG's "YUVj" natural colorspace.
39 // This colorspace is close to Rec.601's Y'CbCr model with the notable
40 // difference of allowing larger range for luma/chroma.
41 // See http://en.wikipedia.org/wiki/YCbCr#JPEG_conversion paragraph, and its
42 // difference with http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
43 // #define USE_YUVj
44 #endif
45
46 //------------------------------------------------------------------------------
47 // YUV -> RGB conversion
48
49 #if defined(__cplusplus) || defined(c_plusplus)
50 extern "C" {
51 #endif
52
53 enum { YUV_FIX = 16, // fixed-point precision
54 YUV_RANGE_MIN = -227, // min value of r/g/b output
55 YUV_RANGE_MAX = 256 + 226 // max value of r/g/b output
56 };
57 extern int16_t VP8kVToR[256], VP8kUToB[256];
58 extern int32_t VP8kVToG[256], VP8kUToG[256];
59 extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
60 extern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
61
VP8YuvToRgb(uint8_t y,uint8_t u,uint8_t v,uint8_t * const rgb)62 static WEBP_INLINE void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
63 uint8_t* const rgb) {
64 const int r_off = VP8kVToR[v];
65 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
66 const int b_off = VP8kUToB[u];
67 rgb[0] = VP8kClip[y + r_off - YUV_RANGE_MIN];
68 rgb[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
69 rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
70 }
71
VP8YuvToRgb565(uint8_t y,uint8_t u,uint8_t v,uint8_t * const rgb)72 static WEBP_INLINE void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v,
73 uint8_t* const rgb) {
74 const int r_off = VP8kVToR[v];
75 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
76 const int b_off = VP8kUToB[u];
77 const uint8_t rg = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
78 (VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
79 const uint8_t gb = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
80 (VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
81 #ifdef WEBP_SWAP_16BIT_CSP
82 rgb[0] = gb;
83 rgb[1] = rg;
84 #else
85 rgb[0] = rg;
86 rgb[1] = gb;
87 #endif
88 }
89
VP8YuvToArgb(uint8_t y,uint8_t u,uint8_t v,uint8_t * const argb)90 static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
91 uint8_t* const argb) {
92 argb[0] = 0xff;
93 VP8YuvToRgb(y, u, v, argb + 1);
94 }
95
VP8YuvToRgba4444(uint8_t y,uint8_t u,uint8_t v,uint8_t * const argb)96 static WEBP_INLINE void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v,
97 uint8_t* const argb) {
98 const int r_off = VP8kVToR[v];
99 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
100 const int b_off = VP8kUToB[u];
101 const uint8_t rg = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) |
102 VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]);
103 const uint8_t ba = (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4) | 0x0f;
104 #ifdef WEBP_SWAP_16BIT_CSP
105 argb[0] = ba;
106 argb[1] = rg;
107 #else
108 argb[0] = rg;
109 argb[1] = ba;
110 #endif
111 }
112
VP8YuvToBgr(uint8_t y,uint8_t u,uint8_t v,uint8_t * const bgr)113 static WEBP_INLINE void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
114 uint8_t* const bgr) {
115 const int r_off = VP8kVToR[v];
116 const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
117 const int b_off = VP8kUToB[u];
118 bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN];
119 bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
120 bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN];
121 }
122
VP8YuvToBgra(uint8_t y,uint8_t u,uint8_t v,uint8_t * const bgra)123 static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v,
124 uint8_t* const bgra) {
125 VP8YuvToBgr(y, u, v, bgra);
126 bgra[3] = 0xff;
127 }
128
VP8YuvToRgba(uint8_t y,uint8_t u,uint8_t v,uint8_t * const rgba)129 static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
130 uint8_t* const rgba) {
131 VP8YuvToRgb(y, u, v, rgba);
132 rgba[3] = 0xff;
133 }
134
135 // Must be called before everything, to initialize the tables.
136 void VP8YUVInit(void);
137
138 //------------------------------------------------------------------------------
139 // RGB -> YUV conversion
140
VP8ClipUV(int v)141 static WEBP_INLINE int VP8ClipUV(int v) {
142 v = (v + (257 << (YUV_FIX + 2 - 1))) >> (YUV_FIX + 2);
143 return ((v & ~0xff) == 0) ? v : (v < 0) ? 0 : 255;
144 }
145
146 #ifndef USE_YUVj
147
VP8RGBToY(int r,int g,int b)148 static WEBP_INLINE int VP8RGBToY(int r, int g, int b) {
149 const int kRound = (1 << (YUV_FIX - 1)) + (16 << YUV_FIX);
150 const int luma = 16839 * r + 33059 * g + 6420 * b;
151 return (luma + kRound) >> YUV_FIX; // no need to clip
152 }
153
VP8RGBToU(int r,int g,int b)154 static WEBP_INLINE int VP8RGBToU(int r, int g, int b) {
155 const int u = -9719 * r - 19081 * g + 28800 * b;
156 return VP8ClipUV(u);
157 }
158
VP8RGBToV(int r,int g,int b)159 static WEBP_INLINE int VP8RGBToV(int r, int g, int b) {
160 const int v = +28800 * r - 24116 * g - 4684 * b;
161 return VP8ClipUV(v);
162 }
163
164 #else
165
166 // This JPEG-YUV colorspace, only for comparison!
167 // These are also 16-bit precision coefficients from Rec.601, but with full
168 // [0..255] output range.
VP8RGBToY(int r,int g,int b)169 static WEBP_INLINE int VP8RGBToY(int r, int g, int b) {
170 const int kRound = (1 << (YUV_FIX - 1));
171 const int luma = 19595 * r + 38470 * g + 7471 * b;
172 return (luma + kRound) >> YUV_FIX; // no need to clip
173 }
174
VP8RGBToU(int r,int g,int b)175 static WEBP_INLINE int VP8RGBToU(int r, int g, int b) {
176 const int u = -11058 * r - 21710 * g + 32768 * b;
177 return VP8ClipUV(u);
178 }
179
VP8RGBToV(int r,int g,int b)180 static WEBP_INLINE int VP8RGBToV(int r, int g, int b) {
181 const int v = 32768 * r - 27439 * g - 5329 * b;
182 return VP8ClipUV(v);
183 }
184
185 #endif // USE_YUVj
186
187 #if defined(__cplusplus) || defined(c_plusplus)
188 } // extern "C"
189 #endif
190
191 #endif /* WEBP_DSP_YUV_H_ */
192